Last updated on January 16, 2023
Since the official Soulseek client and server is proprietary software, this documentation has been compiled thanks to years of reverse engineering efforts. To preserve the health of the Soulseek network, please do not modify or extend the protocol in ways that negatively impact the network.
If you find any inconsistencies, errors or omissions in the documentation, please report them.
- Packing
- Constants
- Server Messages
- Peer Init Messages
- Peer Messages
- File Messages
- Distributed Messages
Number |
---|
1 Byte |
Number |
---|
4 Bytes (little-endian) |
Number |
---|
8 Bytes (little-endian) |
Number |
---|
1 Byte (0 or 1) |
Length of String | String |
---|---|
uint32 | bytes |
Type | Connection |
---|---|
P | Peer To Peer |
F | File Transfer |
D | Distributed Network |
Reason | Description |
---|---|
INVALIDUSERNAME | Username is longer than 30 characters or contains invalid characters (non-ASCII) |
INVALIDPASS | Password for existing user is incorrect |
Code | Status |
---|---|
0 | Offline |
1 | Away |
2 | Online |
Code | Direction |
---|---|
0 | Download from Peer |
1 | Upload to Peer |
String | Comments |
---|---|
Banned | SoulseekQt uses 'File not shared.' instead |
Cancelled | |
Complete | |
Disallowed extension | Sent by Soulseek NS for filtered extensions |
File not shared. | Note: Ends with a dot |
Pending shutdown. | Note: Ends with a dot |
Queued | |
Remote file error | |
Too many files | |
Too many megabytes |
String | Comments |
---|---|
Blocked country | Exclusive to Nicotine+, no longer used in Nicotine+ >=3.2.0 |
File not shared | Exclusive to Nicotine+, no longer used in Nicotine+ >=3.1.1 |
User limit of x megabytes exceeded | Exclusive to Nicotine+, no longer used in Nicotine+ >=3.1.1 |
User limit of x files exceeded | Exclusive to Nicotine+, no longer used in Nicotine+ >=3.1.1 |
Code | Attribute (unit) |
---|---|
0 | Bitrate (kbps) |
1 | Duration (seconds) |
2 | VBR (0 or 1) |
3 | Encoder (unused) |
4 | Sample Rate (Hz) |
5 | Bit Depth (bits) |
These combinations are actively used by clients. Other combinations are discouraged, unless the official client makes changes.
-
Soulseek NS, SoulseekQt (2015-2-21 and earlier), Nicotine+ (lossy formats), Museek+, SoulSeeX, slskd (lossy formats):
- {0: bitrate, 1: duration, 2: VBR}
-
SoulseekQt (2015-2-21 and earlier):
- {0: bitrate, 2: VBR}
-
SoulseekQt (2015-6-12 and later):
- {0: bitrate}
- {1: duration}
- {0: bitrate, 1: duration} (MP3, OGG, WMA, M4A)
- {4: sample rate, 5: bit depth}
- {1: duration, 4: sample rate, 5: bit depth} (FLAC, WAV, APE)
- {0: bitrate, 1: duration, 4: sample rate, 5: bit depth} (WV)
-
Nicotine+ (lossless formats), slskd (lossless formats):
- {1: duration, 4: sample rate, 5: bit depth}
Send | Receive |
---|---|
Send to Server | Receive from Server |
Server messages are used by clients to interface with the server. In Nicotine+, these messages are defined in slskmessages.py.
If you want a Soulseek server, check out Soulfind. Soulfind is obviously not exactly the same as the official proprietary Soulseek server, but it handles the protocol well enough (and can be modified).
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint32 | ... |
We send this to the server right after the connection has been established. Server responds with the greeting message.
Message:
Data | Message Length | Message Code | Username Length | Username | Password Length | Password |
---|---|---|---|---|---|---|
Human | 72 | 1 | 8 | username | 8 | password |
Hex | 48 00 00 00 | 01 00 00 00 | 08 00 00 00 | 75 73 65 72 6e 61 6d 65 | 08 00 00 00 | 70 61 73 73 77 6f 72 64 |
... continued:
Data | Version | Hash Length | Hash | Minor Version |
---|---|---|---|---|
Human | 160 | 32 | d51c9a7e9353746a6020f9602d452929 | 1 |
Hex | a0 00 00 00 | 20 00 00 00 | 64 35 31 63 39 61 37 65 39 33 35 33 37 34 36 61 36 30 32 30 66 39 36 30 32 64 34 35 32 39 32 39 | 01 00 00 00 |
Message as a Hex Stream:
- 48 00 00 00 01 00 00 00 08 00 00 00 75 73 65 72 6e 61 6d 65 08 00 00 00 70 61 73 73 77 6f 72 64 a0 00 00 00 20 00 00 00 64 35 31 63 39 61 37 65 39 33 35 33 37 34 36 61 36 30 32 30 66 39 36 30 32 64 34 35 32 39 32 39 01 00 00 00
- Send Login Attempt
- string username
- string password A non-empty string is required
- uint32 version number 160 for Nicotine+
- string hash MD5 hex digest of concatenated username & password
- uint32 minor version 0x13000000 for 157 ns 13e, 0x11000000 for 157 ns 13c
- Receive Login Success
- bool success 1
- string greet MOTD string
- uint32 Your IP Address
- string hash MD5 hex digest of the password string
- Receive Login Failure
- bool failure 0
- string reason see Login Failure Reasons
We send this to the server to indicate the port number that we listen on (2234 by default).
If this value is set to zero, or the message is not sent upon login (which defaults the listen port to 0), remote clients handling a ConnectToPeer message will fail to properly purge the request. Confirmed in SoulseekQt 2020.3.12, but probably impacts most or all other versions.
- Send
- uint32 port
- bool use obfuscation
- uint32 obfuscated port
- Receive
- No Message
We send this to the server to ask for a peer's address (IP address and port), given the peer's username.
- Send
- string username
- Receive
- string username
- ip ip
- uint32 port
- bool use obfuscation
- uint32 obfuscated port
Used to be kept updated about a user's stats. When a user's stats have changed, the server sends a GetUserStats response message with the new user stats.
- Send
- string username
- Receive
- string username
- bool exists
- If exists is true
- uint32 status see User Status Codes
- uint32 avgspeed
- uint64 uploadnum Number of uploaded files. The value changes when sending a SendUploadSpeed server message, and is likely used by the server to calculate the average speed.
- uint32 files
- uint32 dirs
- If status is away/online
- string countrycode Uppercase country code
Used when we no longer want to be kept updated about a user's stats.
- Send
- string username
- Receive
- No Message
The server tells us if a user has gone away or has returned.
- Send
- string username
- Receive
- string username
- uint32 status see User Status Codes
- bool privileged
Either we want to say something in the chatroom, or someone else did.
- Send
- string room
- string message
- Receive
- string room
- string username
- string message
We send this message to the server when we want to join a room. If the room doesn't exist, it is created.
Server responds with this message when we join a room. Contains users list with data on everyone.
- Send
- string room
- uint32 private If the room doesn't exist, should the new room be private?
- Receive
- string room
- uint32 number of users in room For private rooms, also contain owner and operators
- Iterate the number of users
- string username
- uint32 number of statuses
- Iterate the number of statuses
- uint32 status
- uint32 number of user stats
- Iterate the number of user stats
- uint32 avgspeed
- uint64 uploadnum
- uint32 files
- uint32 dirs
- uint32 number of slotsfree
- Iterate the number of slotsfree
- uint32 slotsfree
- uint32 number of user countries
- Iterate the number of user countries
- string countrycode Uppercase country code
- string owner If private room
- uint32 number of operators in room If private room
- Iterate the number of operators
- string operator
We send this to the server when we want to leave a room.
- Send
- string room
- Receive
- string room
The server tells us someone has just joined a room we're in.
- Send
- No Message
- Receive
- string room
- string username
- uint32 status
- uint32 avgspeed
- uint64 uploadnum
- uint32 files
- uint32 dirs
- uint32 slotsfree
- string countrycode Uppercase country code
The server tells us someone has just left a room we're in.
- Send
- No Message
- Receive
- string room
- string username
Either we ask server to tell someone else we want to establish a connection with them, or server tells us someone wants to connect with us. Used when the side that wants a connection can't establish it, and tries to go the other way around (direct connection has failed).
See also: Peer Connection Message Order
- Send
- uint32 token
- string username
- string type P, F or D see Connection Types
- Receive
- string username
- string type P, F or D see Connection Types
- ip ip
- uint32 port
- uint32 token Use this token for PierceFireWall
- bool privileged
- bool use obfuscation
- uint32 obfuscated port
Chat phrase sent to someone or received by us in private.
- Send
- string username
- string message
- Receive
- uint32 ID
- uint32 timestamp
- string username
- string message
- bool new message 1 if message is new, 0 if message is re-sent (e.g. if recipient was offline)
We send this to the server to confirm that we received a private message. If we don't send it, the server will keep sending the chat phrase to us.
- Send
- uint32 message ID
- Receive
- No Message
OBSOLETE, use RoomSearch server message
We send this to the server when we search for something in a room.
- Send
- uint32 token
- uint32 room id
- string search query
- Receive
- No Message
We send this to the server when we search for something. Alternatively, the server sends this message outside the distributed network to tell us that someone is searching for something, currently used for UserSearch and RoomSearch requests.
The token is a number generated by the client and is used to track the search results.
- Send
- uint32 token
- string search query
- Receive
- string username
- uint32 token
- string search query
We send our new status to the server. Status is a way to define whether we're available (online) or busy (away).
1 = Away
2 = Online
- Send
- int32 status see User Status Codes
- Receive
- No Message
DEPRECATED
We test if the server responds.
- Send
- Empty Message
- Receive
- Empty Message
OBSOLETE, no longer used
- Send
- string username
- uint32 token
- Receive
- string username
- uint32 token
OBSOLETE, use SendUploadSpeed server message
We used to send this after a finished download to let the server update the speed statistics for a user.
- Send
- string username
- uint32 speed
- Receive
- No Message
We send this to server to indicate the number of folder and files that we share.
- Send
- uint32 dirs
- uint32 files
- Receive
- No Message
The server sends this to indicate a change in a user's statistics, if we've requested to watch the user in WatchUser previously. A user's stats can also be requested by sending a GetUserStats message to the server, but WatchUser should be used instead.
- Send
- string username
- Receive
- string username
- uint32 avgspeed
- uint64 uploadnum
- uint32 files
- uint32 dirs
OBSOLETE, no longer sent by the server
The server sends this to indicate if someone has download slots available or not.
- Send
- No Message
- Receive
- string username
- bool slotsfree Can immediately download
The server sends this if someone else logged in under our nickname, and then disconnects us.
- Send
- No Message
- Receive
- Empty Message
We send this to the server when we search a specific user's shares. The token is a number generated by the client and is used to track the search results.
- Send
- string username
- uint32 token
- string search query
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we add an item to our likes list.
- Send
- string item
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we remove an item from our likes list.
- Send
- string item
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of personal recommendations and a number for each.
- Send
- Empty Message
- Receive
- uint32 number of total recommendations
- Iterate for number of total recommendations
- string recommendation
- int32 number of recommendations this recommendation has
- uint32 number of total unrecommendations
- Iterate for number of total unrecommendations
- string unrecommendation
- int32 number of unrecommendations this unrecommendation has (negative)
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of global recommendations and a number for each.
- Send
- Empty Message
- Receive
- uint32 number of total recommendations
- Iterate for number of total recommendations
- string recommendation
- int32 number of recommendations this recommendation has
- uint32 number of total unrecommendations
- Iterate for number of total unrecommendations
- string unrecommendation
- int32 number of unrecommendations this unrecommendation has (negative)
DEPRECATED, used in Soulseek NS but not SoulseekQt
We ask the server for a user's liked and hated interests. The server responds with a list of interests.
- Send
- string username
- Receive
- string username
- uint32 number of liked interests
- Iterate for number of liked interests
- string interest
- uint32 number of hated interests
- Iterate for number of hated interests
- string interest
OBSOLETE, no longer used since Soulseek stopped supporting third-party servers in 2002
We send this to the server to run an admin command (e.g. to ban or silence a user) if we have admin status on the server.
- Send
- string command
- uint32 number of command arguments
- Iterate for number of command arguments
- string command argument
- Receive
- No Message
OBSOLETE, use PlaceInQueueResponse peer message
The server sends this to indicate change in place in queue while we're waiting for files from another peer.
- Send
- string username
- uint32 req
- uint32 place
- Receive
- string username
- uint32 req
- uint32 place
OBSOLETE, no longer sent by the server
The server tells us a new room has been added.
- Send
- No Message
- Receive
- string room
OBSOLETE, no longer sent by the server
The server tells us a room has been removed.
- Send
- No Message
- Receive
- string room
The server tells us a list of rooms and the number of users in them. When connecting to the server, the server only sends us rooms with at least 5 users. A few select rooms are also excluded, such as nicotine and The Lobby. Requesting the room list yields a response containing the missing rooms.
- Send
- Empty Message
- Receive
- uint32 number of rooms
- Iterate for number of rooms
- string room
- uint32 number of rooms
- Iterate for number of rooms
- uint32 number of users in room
- uint32 number of owned private rooms
- Iterate for number of owned private rooms
- string owned private room
- uint32 number of owned private rooms
- Iterate for number of owned private rooms
- uint32 number of users in owned private room
- uint32 number of private rooms (except owned)
- Iterate for number of private rooms (except owned)
- string private room
- uint32 number of private rooms (except owned)
- Iterate for number of private rooms (except owned)
- uint32 number of users in private rooms (except owned)
- uint32 number of operated private rooms
- Iterate for number of operated private rooms
- string operated private room
OBSOLETE, no results even with official client
We send this to search for an exact file name and folder, to find other sources.
- Send
- uint32 token
- string filename
- string path
- uint64 filesize
- uint32 checksum
- Receive
- string username
- uint32 token
- string filename
- string path
- uint64 filesize
- uint32 checksum
A global message from the server admin has arrived.
- Send
- No Message
- Receive
- string message
OBSOLETE, no longer used
We send this to get a global list of all users online.
- Send
- Empty Message
- Receive
- uint32 number of users in room
- Iterate the number of users
- string username
- uint32 number of userdata
- Iterate the number of users
- uint32 status
- uint32 number of userdata
- Iterate the userdata
- uint32 avgspeed
- uint64 uploadnum
- uint32 files
- uint32 dirs
- uint32 number of slotsfree
- Iterate through number of slotsfree
- uint32 slotsfree
- uint32 number of usercountries
- Iterate through number of usercountries
- string countrycode Uppercase country code
OBSOLETE, no longer used
Server message for tunneling a chat message.
- Send
- string username
- uint32 token
- uint32 code
- string message
- Receive
- string username
- uint32 code
- uint32 token
- ip ip
- uint32 port
- string message
The server sends us a list of privileged users, a.k.a. users who have donated.
- Send
- No Message
- Receive
- uint32 number of users
- Iterate number of users
- string username
We inform the server if we have a distributed parent or not. If not, the server eventually sends us a PossibleParents message with a list of possible parents to connect to. If no candidates are found, no such message is sent by the server, and we eventually become a branch root.
- Send
- bool have parents
- Receive
- No Message
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We send the IP address of our parent to the server.
- Send
- ip ip
- Receive
- No Message
The server informs us about the minimum upload speed required to become a parent in the distributed network.
- Send
- No Message
- Receive
- uint32 speed
The server sends us a speed ratio determining the number of children we can have in the distributed network. The maximum number of children is our upload speed divided by the speed ratio.
- Send
- No Message
- Receive
- uint32 ratio
OBSOLETE, no longer sent by the server
- Send
- No Message
- Receive
- uint32 number
OBSOLETE, no longer sent by the server
- Send
- No Message
- Receive
- uint32 number
OBSOLETE, no longer sent by the server
- Send
- No Message
- Receive
- uint32 number
OBSOLETE, no longer sent by the server
- Send
- No Message
- Receive
- uint32 number
OBSOLETE, no longer sent by the server
The server sends us the username of a new privileged user, which we add to our list of global privileged users.
- Send
- No Message
- Receive
- string username
We ask the server how much time we have left of our privileges. The server responds with the remaining time, in seconds.
- Send
- Empty Message
- Receive
- uint32 time left
The server sends us an embedded distributed message. The only type of distributed message sent at present is DistribSearch (distributed code 3). If we receive such a message, we are a branch root in the distributed network, and we distribute the embedded message (not the unpacked distributed message) to our child peers.
- Send
- No Message
- Receive
- uint8 distributed code see Distributed Message Codes
- bytes distributed message Raw message associated with distributed code
We tell the server if we want to accept child nodes.
- Send
- bool accept
- Receive
- No Message
The server send us a list of max 10 possible distributed parents to connect to. Messages of this type are sent to us at regular intervals, until we tell the server we don't need more possible parents with a HaveNoParent message.
The received list always contains users whose upload speed is higher than our own. If we have the highest upload speed on the server, we become a branch root, and start receiving SearchRequest messages directly from the server.
- Send
- No Message
- Receive
- uint32 number of parents
- Iterate for number of parents
- string username
- ip ip
- uint32 port
We send the server one of our wishlist search queries at each interval.
- Send
- uint32 token
- string search query
- Receive
- No Message
The server tells us the wishlist search interval.
This interval is almost always 12 minutes, or 2 minutes for privileged users.
- Send
- No Message
- Receive
- uint32 interval
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of similar users related to our interests.
- Send
- Empty Message
- Receive
- uint32 number of users
- Iterate for number of user
- string username
- uint32 rating
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of recommendations related to a specific item, which is usually present in the like/dislike list or an existing recommendation list.
- Send
- string item
- Receive
- string item
- uint32 number of recommendations
- Iterate for number of recommendations
- string recommendation
- uint32 number of recommendations for this recommendation (can be negative)
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of similar users related to a specific item, which is usually present in the like/dislike list or recommendation list.
- Send
- string item
- Receive
- string item
- uint32 number of users
- Iterate for number of users
- string username
The server returns a list of tickers in a chat room.
Tickers are customizable, user-specific messages that appear on chat room walls.
- Send
- No Message
- Receive
- string room
- uint32 number of users
- Iterate for number of user
- string username
- string tickers
The server sends us a new ticker that was added to a chat room.
Tickers are customizable, user-specific messages that appear on chat room walls.
- Send
- No Message
- Receive
- string room
- string username
- string ticker
The server informs us that a ticker was removed from a chat room.
Tickers are customizable, user-specific messages that appear on chat room walls.
- Send
- No Message
- Receive
- string room
- string username
We send this to the server when we change our own ticker in a chat room. Sending an empty ticker string removes any existing ticker in the room.
Tickers are customizable, user-specific messages that appear on chat room walls.
- Send
- string room
- string ticker
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we add an item to our hate list.
- Send
- string item
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we remove an item from our hate list.
- Send
- string item
- Receive
- No Message
We send this to the server to search files shared by users who have joined a specific chat room.
The token is a number generated by the client and is used to track the search results.
- Send
- string room
- uint32 token
- string search query
- Receive
- No Message
We send this after a finished upload to let the server update the speed statistics for ourselves.
- Send
- uint32 speed
- Receive
- No Message
DEPRECATED, use WatchUser and GetUserStatus server messages
We ask the server whether a user is privileged or not.
- Send
- string username
- Receive
- string username
- bool privileged
We give (part of) our privileges, specified in days, to another user on the network.
- Send
- string username
- uint32 days
- Receive
- No Message
DEPRECATED, sent by Soulseek NS but not SoulseekQt
- Send
- uint32 token
- string username
- Receive
- uint32 token
- string username
DEPRECATED, no longer used
- Send
- uint32 token
- Receive
- uint32 token
We tell the server what our position is in our branch (xth generation) on the distributed network.
- Send
- uint32 branch level
- Receive
- No Message
We tell the server the username of the root of the branch we're in on the distributed network.
- Send
- string branch root
- Receive
- No Message
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We tell the server the maximum number of generation of children we have on the distributed network.
- Send
- uint32 child depth
- Receive
- No Message
The server asks us to reset our distributed parent and children.
- Send
- No Message
- Receive
- Empty Message
The server sends us a list of room users that we can alter (add operator abilities / dismember).
- Send
- No Message
- Receive
- string room
- uint32 number of users
- Iterate for number of users
- string users
We send this to inform the server that we've added a user to a private room.
- Send
- string room
- string username
- Receive
- string room
- string username
We send this to inform the server that we've removed a user from a private room.
- Send
- string room
- string username
- Receive
- string room
- string username
We send this to the server to remove our own membership of a private room.
- Send
- string room
- Receive
- No Message
We send this to the server to stop owning a private room.
- Send
- string room
- Receive
- No Message
OBSOLETE, no longer used
Unknown purpose
- Send
- string room
- Receive
- string room
The server sends us this message when we are added to a private room.
- Send
- No Message
- Receive
- string room
The server sends us this message when we are removed from a private room.
- Send
- No Message
- Receive
- string room
We send this when we want to enable or disable invitations to private rooms.
- Send
- bool enable
- Receive
- bool enable
We send this to the server to change our password. We receive a response if our password changes.
- Send
- string pass
- Receive
- string pass
We send this to the server to add private room operator abilities to a user.
- Send
- string room
- string username
- Receive
- string room
- string username
We send this to the server to remove private room operator abilities from a user.
- Send
- string room
- string username
- Receive
- string room
- string username
The server send us this message when we're given operator abilities in a private room.
- Send
- No Message
- Receive
- string room
The server send us this message when our operator abilities are removed in a private room.
- Send
- No Message
- Receive
- string room
The server sends us a list of operators in a specific room, that we can remove operator abilities from.
- Send
- No Message
- Receive
- string room
- uint32 number of operators in room
- Iterate the number of operators
- string operator
Sends a broadcast private message to the given list of online users.
- Send
- uint32 number of users
- Iterate the number of users
- string username
- string message
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
We ask the server to send us messages from all public rooms, also known as public room feed.
- Send
- Empty Message
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
We ask the server to stop sending us messages from all public rooms, also known as public room feed.
- Send
- Empty Message
- Receive
- No Message
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends this when a new message has been written in the public room feed (every single line written in every public room).
- Send
- No Message
- Receive
- string room
- string username
- string message
OBSOLETE, server sends empty list as of 2018
The server returns a list of related search terms for a search query.
- Send
- string query
- Receive
- string query
- uint32 number of terms
- Iterate for number of term
- string term
- uint32 score
We send this to say we can't connect to peer after it has asked us to connect. We receive this if we asked peer to connect and it can't do this. This message means a connection can't be established either way.
See also: Peer Connection Message Order
- Send
- uint32 token
- string username
- Receive
- uint32 token
- string username
Server tells us a new room cannot be created.
This message only seems to be sent if you try to create a room with the same name as an existing private room. In other cases, such as using a room name with leading or trailing spaces, only a private message containing an error message is sent.
- Send
- No Message
- Receive
- string room
Send | Receive |
---|---|
Send to Peer | Receive from Peer |
Peer init messages are used to initiate a 'P', 'F' or 'D' connection to a peer. In Nicotine+, these messages are defined in slskmessages.py.
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint8 | ... |
Code | Message |
---|---|
0 | Pierce Firewall |
1 | Peer Init |
Used by SoulseekQt, Nicotine+ 3.2.1 and later, Soulseek.NET-based clients (slskd, Seeker)
- User A sends ConnectToPeer to the Server with a unique token (indirect connection request)
- User A sends a PeerInit to User B (direct connection request)
- The Server sends a ConnectToPeer response to User B with the same token.
If User B receives the PeerInit message, a connection is established, and user A is free to send peer messages.
Otherwise, once User B receives the ConnectToPeer message from the Server, User B proceeds with step 4. - User B sends a PierceFireWall to User A with the token included in the ConnectToPeer message.
If this succeeds, a connection is established, and User A is free to send peer messages.
If this fails, User B retries for ~1 minute. If this still fails, no connection is possible, and User B proceeds with step 5. - User B sends a CantConnectToPeer to the Server.
- The Server sends a CantConnectToPeer response to User A.
Unlike SoulseekQt, Nicotine+ and Soulseek.NET-based clients skip step 5 in favor of letting the connection attempt time out on User A's end.
Used by Soulseek NS, Nicotine+ 3.2.0 and earlier, Museek+, soulseeX
- User A sends a PeerInit to User B.
If this succeeds, a connection is established, and User A is free to send peer messages.
If this fails (socket cannot connect), User A proceeds with an indirect connection request (step 2). - User A sends ConnectToPeer to the Server with a unique token
- The Server sends a ConnectToPeer response to User B with the same token
- User B sends a PierceFireWall to User A with the same token.
If this succeeds, a connection is established, and User A is free to send peer messages.
If this fails, User B retries for ~1 minute. If this still fails, no connection is possible, and User B proceeds with step 5. - User B sends a CantConnectToPeer to the Server.
- The Server sends a CantConnectToPeer response to User A.
This message is sent in response to an indirect connection request from another user. If the message goes through to the user, the connection is ready. The token is taken from the ConnectToPeer server message.
See also: Peer Connection Message Order
- Send
- uint32 token
- Receive
- uint32 token
This message is sent to initiate a direct connection to another peer. The token is apparently always 0 and ignored.
See also: Peer Connection Message Order
- Send
- string username local username
- string type P, F or D see Connection Types
- uint32 token value is always 0
- Receive
- string username remote username
- string type P, F or D see Connection Types
- uint32 token value is always 0
Send | Receive |
---|---|
Send to Peer | Receive from Peer |
Peer messages are sent to peers over a 'P' connection. Only a single active connection to a peer is allowed. In Nicotine+, these messages are defined in slskmessages.py.
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint32 | ... |
Code | Message | Status |
---|---|---|
1 | Private Message | Obsolete, contents unknown |
4 | Shared File List Request | |
5 | Shared File List Response | |
8 | File Search Request | Obsolete |
9 | File Search Response | |
10 | Room Invitation | Obsolete, contents unknown |
14 | Cancelled Queued Transfer | Obsolete, contents unknown |
15 | User Info Request | |
16 | User Info Response | |
33 | Send Connect Token | Obsolete, contents unknown |
34 | Move Download To Top | Obsolete, contents unknown |
36 | Folder Contents Request | |
37 | Folder Contents Response | |
40 | Transfer Request | |
41 | Download Response | Deprecated |
41 | Upload Response | |
42 | Upload Placehold | Obsolete |
43 | Queue Upload | |
44 | Place In Queue Response | |
46 | Upload Failed | |
47 | Exact File Search Request | Obsolete, contents unknown |
48 | Queued Downloads | Obsolete, contents unknown |
49 | Indirect File Search Request | Obsolete, contents unknown |
50 | Upload Denied | |
51 | Place In Queue Request | |
52 | Upload Queue Notification | Deprecated |
We send this to a peer to ask for a list of shared files.
- Send
- Empty Message
- Receive
- Empty Message
A peer responds with a list of shared files after we've sent a SharedFileListRequest.
- Send
- Iterate through shares database
- data
- Iterate through shares database
- Receive
- decompress
- uint32 number of directories
- Iterate number of directories
- string directory
- uint32 number of files
- Iterate number of files
- uint8 code value is always 1
- string filename
- unit64 file size
- string file extension
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
- uint32 unknown official clients always send a value of 0
- uint32 number of private directories
- Iterate number of private directories
- string directory
- uint32 number of files
- Iterate number of files
- uint8 code value is always 1
- string filename
- uint64 file size
- string file extension
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
OBSOLETE, use UserSearch server message
We send this to the peer when we search for a file. Alternatively, the peer sends this to tell us it is searching for a file.
- Send
- uint32 token
- string query
- Receive
- uint32 token
- string query
A peer sends this message when it has a file search match. The token is taken from original FileSearch, UserSearch or RoomSearch server message.
- Send
- string username
- uint32 token
- uint32 number of results
- Iterate for number of results
- uint8 code value is always 1
- string filename
- uint64 file size
- string file extension (SoulseekNS requires "mp3" to show attributes)
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
- bool slotfree
- uint32 avgspeed
- uint32 queue length
- uint32 unknown official clients always send a value of 0
- uint32 number of privately shared results
- Iterate for number of privately shared results
- uint8 code value is always 1
- string filename
- uint64 file size
- string file extension (SoulseekNS requires "mp3" to show attributes)
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
- Receive
- decompress
- string username
- uint32 token
- uint32 number of results
- Iterate for number of results
- uint8 code value is always 1
- string filename
- uint64 size
- string file extension (Always blank from SoulseekQt clients)
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
- bool slotfree
- uint32 avgspeed
- uint32 queue length
- uint32 unknown official clients always send a value of 0
- uint32 number of privately shared results
- Iterate for number of privately shared results
- uint8 code value is always 1
- string filename
- uint64 size
- string file extension (Always blank from SoulseekQt clients)
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
We ask the other peer to send us their user information, picture and all.
- Send
- Empty Message
- Receive
- Empty Message
A peer responds with this after we've sent a UserInfoRequest.
- Send
- string description
- Check contents of picture
- If picture is not empty
- bool has picture 1
- string picture
- If picture is empty
- bool has picture 0
- If picture is not empty
- uint32 totalupl
- uint32 queuesize
- bool slotsfree Can immediately upload
- uint32 uploadpermitted Who can upload anything to us? 0 == No one; 1 == Everyone; 2 == Users in List; 3 == Trusted Users
- Receive
- string description
- bool has picture
- Check contents of has picture
- If has picture is not empty
- string picture
- If has picture is not empty
- uint32 totalupl
- uint32 queuesize
- bool slotsfree Can immediately download
- uint32 uploadpermitted Who can upload anything to this user (not sent by SoulseekQt)? 0 == No one; 1 == Everyone; 2 == Users in List; 3 == Trusted Users
We ask the peer to send us the contents of a single folder.
- Send
- uint32 token
- string folder
- Receive
- uint32 token
- string folder
A peer responds with the contents of a particular folder (with all subfolders) after we've sent a FolderContentsRequest.
- Send
- uint32 token
- string folder
- uint32 number of folders
- Iterate for number of folders
- string dir
- uint32 number of files
- Iterate number of files
- uint8 code value is always 1
- string file
- uint64 file size
- string file extension (Always blank from SoulseekQt clients)
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
- Receive
- decompress
- uint32 token
- string folder
- uint32 number of folders
- Iterate for number of folders
- string dir
- uint32 number of files
- Iterate number of files
- uint8 code value is always 1
- string file
- uint64 file size
- string file extension (Always blank from SoulseekQt clients)
- uint32 number of attributes
- Iterate for number of attributes
- uint32 attribute code see File Attribute Types
- uint32 attribute value
This message is sent by a peer once they are ready to start uploading a file to us. A TransferResponse message is expected from the recipient, either allowing or rejecting the upload attempt.
This message was formerly used to send a download request (direction 0) as well, but Nicotine+, Museek+ and the official clients use the QueueUpload peer message for this purpose today.
- Send
- uint32 direction 0 or 1 see Transfer Directions
- uint32 token
- string filename
- Check contents of direction
- uint64 filesize if direction == 1 (upload)
- Receive
- uint32 direction 0 or 1 see Transfer Directions
- uint32 token
- string filename
- Check contents of direction
- uint64 filesize if direction == 1 (upload)
DEPRECATED, use QueueUpload to request files
Response to TransferRequest
We (or the other peer) either agrees, or tells the reason for rejecting the file download.
- Send
- uint32 token
- bool allowed
- Check contents of allowed
- uint64 filesize if allowed == 1
- string reason if allowed == 0 ; see Transfer Status Strings
- Receive
- uint32 token
- bool allowed
- Check contents of allowed
- uint64 filesize if allowed == 1
- string reason if allowed == 0 ; see Transfer Status Strings
Response to TransferRequest
We (or the other peer) either agrees, or tells the reason for rejecting the file upload.
- Send
- uint32 token
- bool allowed
- Check contents of allowed
- string reason if allowed == 0 ; see Transfer Status Strings
- Receive
- uint32 token
- bool allowed
- Check contents of allowed
- string reason if allowed == 0 ; see Transfer Status Strings
OBSOLETE, no longer used
- Send
- string filename
- Receive
- string filename
This message is used to tell a peer that an upload should be queued on their end. Once the recipient is ready to transfer the requested file, they will send a TransferRequest to us.
- Send
- string filename
- Receive
- string filename
The peer replies with the upload queue placement of the requested file.
- Send
- string filename
- uint32 place
- Receive
- string filename
- uint32 place
This message is sent whenever a file connection of an active upload closes. Soulseek NS clients can also send this message when a file can not be read. The recipient either re-queues the upload (download on their end), or ignores the message if the transfer finished.
- Send
- string filename
- Receive
- string filename
This message is sent to reject QueueUpload attempts and previously queued files. The reason for rejection will appear in the transfer list of the recipient.
- Send
- string filename
- string reason see Transfer Status Strings
- Receive
- string filename
- string reason see Transfer Status Strings
This message is sent when asking for the upload queue placement of a file.
- Send
- string filename
- Receive
- string filename
DEPRECATED, sent by Soulseek NS but not SoulseekQt
This message is sent to inform a peer about an upload attempt initiated by us.
- Send
- Empty Message
- Receive
- Empty Message
Send | Receive |
---|---|
Send to Peer | Receive from Peer |
File messages are sent to peers over a 'F' connection, and do not have messages codes associated with them.
Message Contents |
---|
... |
Message |
---|
File Download Init |
File Upload Init |
File Offset |
We receive this from a peer via a 'F' connection when they want to start uploading a file to us. The token is the same as the one previously included in the TransferRequest peer message.
- Send
- No Message
- Receive
- uint32 token
We send this to a peer via a 'F' connection to tell them that we want to start uploading a file. The token is the same as the one previously included in the TransferRequest peer message.
- Send
- uint32 token
- Receive
- No Message
We send this to the uploading peer at the beginning of a 'F' connection, to tell them how many bytes of the file we've previously downloaded. If none, the offset is 0.
Soulseek NS fails to read the size of an incomplete file if more than 2 GB of the file has been downloaded by them, and their download pauses and later resumes. The legacy client then sends us an invalid file offset of -1.
- Send
- uint64 offset
- Receive
- uint64 offset
Send | Receive |
---|---|
Send to Node | Receive from Node |
Distributed messages are sent to peers over a 'D' connection, and are used for the distributed search network. Only a single active connection to a peer is allowed. In Nicotine+, these messages are defined in slskmessages.py.
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint8 | ... |
Code | Message | Status |
---|---|---|
0 | Ping | |
3 | Search Request | |
4 | Branch Level | |
5 | Branch Root | |
7 | Child Depth | Deprecated |
93 | Embedded Message |
Send it every 60 sec.
- Send
- Empty Message
- Receive
- uint32 unknown
Search request that arrives through the distributed network. We transmit the search request to our child peers.
- Send
- uint32 unknown
- string username
- uint32 token
- string query
- Receive
- uint32 unknown
- string username
- uint32 token
- string query
We tell our distributed children what our position is in our branch (xth generation) on the distributed network.
- Send
- int32 branch level
- Receive
- int32 branch level
We tell our distributed children the username of the root of the branch we're in on the distributed network.
- Send
- string branch root
- Receive
- string branch root
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We tell our distributed parent the maximum number of generation of children we have on the distributed network.
- Send
- uint32 child depth
- Receive
- uint32 child depth
A branch root sends us an embedded distributed message. We unpack the distributed message and distribute it to our child peers.
The only type of distributed message sent at present is DistribSearch (distributed code 3).
- Send
- uint8 distributed code see Distributed Message Codes
- bytes distributed message Raw message associated with distributed code
- Receive
- uint8 distributed code see Distributed Message Codes
- bytes distributed message Raw message associated with distributed code
This documentation exists thanks to efforts from the following projects:
- Nicotine+ (Hyriand, daelstorm, mathiascode)
- slskd (jpdillingham)
- Museek+ (lbponey)
- SoleSeek (BriEnigma)
- PySoulSeek (Alexander Kanavin)