Since March 10, 2003 - Version 2.1
hypothetic.org

MSN Messenger Protocol

Client - File Transfer

Back To Normal Layout

File transfer

Though not technically a part of the MSN Messenger protocol, a file transfer protocol called "MSNFTP" is included in the official client. This protocol is unrelated to "FTP", or any other file transfer protocol.

Overview

Several very similar terms are used in MSNFTP, which can make it very confusing to read this page. The "sender" and "receiver" is the computer which sends and receives the file, respectively. The "server" and "client" is the computer which initiates and receives the TCP connection, respectively. A messages is "transmitted" (so as not to confuse "sending a message" with "sending the file").

During the invitation stage, the messenger clients will agree on which computer should be the server and which the client, which computer should be sender and which the receiver, what the file to be transferred is called, and an authentication cookie for the session. The sender is usually the server, but may ask the receiver to serve.

Once the client has connected to the server, MSNFTP begins with the two computers exchanging lines of text much like in an NS or SB conversation. In this initial stage, the computers negotiate a protocol, the receiver gives its passport and the authentication cookie, and the sender replies with the size of the file. Then, the sender sends the file in fixed-length blocks of binary data. The receiver can cancel the transfer at any time.

Establishing the connection

During the invitation stage, the computers agreed on either one or two IP addresses and ports the client should connect to. If only one IP address and port was given, the client should connect to that address and port, while the server should listen for connections on the port. If two addresses and ports were given, the server should listen for connections on both ports, while the client should simultaneously attempt to connect to the primary and secondary IP addresses and ports. As soon as one connection has been established, both computers should stop attempting to connect on the other port.

Binary data

This section discusses binary data, how to transmit and receive it. If you're already familiar with binary, you can safely ignore this section.

Ultimately, all computer information is just a series of 1s and 0s. A byte is a series of eight 1s and 0s, so a byte can be in any one of 256 (2^8) different states. In a text-based protocol like MSN Messenger, bytes are interpreted as characters of information according to some standard - usually ASCII. In a binary protocol, bytes are interpreted as something else - numbers between 0 and 255, shades of grey between black and white, reasons for a program crashing, etc.

It's most popular to interpret bytes of data as numbers, often in base 16 ("hexadecimal") instead of base 10 ("decimal"). To make this page easier to read, I'll use decimal, but hexadecimal numbers are used a lot in computing - for example, in plaintext message colour codes. Some programmers like to write things in hexadecimal because (once you get used to it) it's much easier to convert between hexadecimal and binary in your head.

You should consult your language's documentation about how it handles binary data. One important thing to check is that many programming languages (e.g. C and Visual Basic) use the same data type to represent a byte that they use to represent a character, but don't treat bytes and characters the same way - for example, the character '0' is not the same as the number 0. In Visual Basic, for example, you have to do asc(0) to get the ASCII character equivalent to the number 0, and val('0') to get the numerical value of the ASCII character 0.

Protocol - text section

The text section resembles the authentication step of logging into a notification server, except that there are no transaction IDs, and if either side transmits an invalid command, the other side should just close the connection without transmitting an error message.

First, the receiver transmits a VER command with the versions of the MSNFTP protocol it supports as parameters. The official client only supports MSNFTP. The sender replies with a VER command containing the chosen protocol.

Then, the receiver transmits a USR command with the username as the first parameter and authentication cookie as the second. The sender replies with a FIL command with the size of the file in bytes as the only parameter. The official client uses this instead of the size given during the invitation stage.

The receiver transmits a TFR command to indicate that it is ready to receive. At this point, the sender switches to binary for the rest of the session.

At some point after that, the receiver must transmit BYE with a single numeric parameter indicating the result of the file transfer. The following values are allowed:

2147942405
Failure: receiver is out of disk space
2164261682
Failure: receiver cancelled the transfer
2164261683
Failure: sender has cancelled the transfer
2164261694
Failure: connection is blocked
16777987
Success
16777989
Success

As a special case, CCL should be sent with no parameter instead of BYE 2164261682. In practice, only BYE 16777989 and CCL have ever been observed, and the official client's support for other codes is shabby at best.

Once the sender has finished sending, it should wait for the receiver to transmit a BYE command. If the sender does not receive a BYE quickly enough (within about 1 minute in the official client), it will transmit an invitation command in the switchboard session with "Invitation-Command: CANCEL" and "Cancel-Code: FTTIMEOUT". The sender may close the connection at any time after it has finished sending.

Protocol - binary section

An MSNFTP block consists of a header and a body. The header specifies whether the file has been completely sent, and (if not) the number of bytes that will be sent in the body of this block. The body contains the specified number of bytes from the file.

The header is three bytes long. If the file has not been completely transmitted, the first byte of the header will be 0, and the second two bytes of the header will specify the length of the body - the length is equal to the value of the second byte plus 256 times the value of the third byte. So, for example, if the number of bytes in the body is 2045 (the default length in the official client), the value of second byte would be 253 and the value of the third byte would be 7 (253 + 7*256 = 2045). the specified number of bytes follow in the body. Once the file has been completely transmitted, a final block is sent in which the first byte of the header is 1, the second two bytes are 0, and the body is empty.

For example, if you wanted to transmit a 13-byte long file containing the string "Hello, world!", the steps you might go through are:

  1. Generate the first block.
  2. Transmit the first block.
  3. Check whether the receiver has transmitted a BYE or CCL message. If so, close the socket.
  4. Generate the second block.
  5. Transmit the second block
  6. The file is now complete.
  7. Wait up to a minute for the receiver to transmit BYE or CCL, then close the connection

Example sessions

Here is an example of a successful transfer (note that italics represent binary data):

<o> Incoming Connection on Port: 6891

<<< VER MYPROTO MSNFTP

>>> VER MSNFTP

<<< USR myname@msn.com 93301

>>> FIL 13

<<< TFR

>>> 0, 13, 0, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33

>>> 1, 0, 0

<<< BYE 16777989

And here is a failed negotiation:

<o> Incoming Connection on Port: 6891

<<< VER MYPROTO

<o> Disconnect

File Transfers in older MSN protocol


The file transfer between 3rd party MSN clients and official Microsoft's MSN client uses MSNP2P protocol for file transfer. The file transfer takes place through SB connection established for chat, i.e. there is no separate TCP connection for file transfer as discribed above in MSNFT protocol. The typical process can be enumerated in following steps -

  1. When client wants to transfer file, it sends message to receiver with Content-Type set to application/x-msnmsgrp2p
  2. Content-Type is followed by P2P-Dest header.
  3. A P2P-Dest header is followed by 48 bytes which contains following information in sequence (we are only interested in Channel SessionID, Offset, Total Data Size, and Message Size for the purpose of File Transfer).
    1. Channel SessionID - 4 bytes
    2. ID - 4 bytes
    3. Offset - 8 bytes
    4. Total Data Size - 8 bytes
    5. Message Size - 4 bytes
    6. Flags - 4 bytes
    7. Acknowledgement ID - 4 bytes
    8. Acknowledgement UID - 4 bytes
    9. Acknowledgement Size - 8 bytes
  4. The above 48 bytes header ends with message INVITE MSNMSGR <email>@hotmail.com MSNSLP/1.0
  5. This is followed by few more headers like To, From indicating the sender and receiver of the file.
  6. Then there is 2nd Content-Type header where type is set to application/x-msnmsgr-sessionreqbody
  7. Followed by this is a header EUF-GUID whose value indicates whether the invitation is for a file transfer or a buddy icon transfer. In case of file transfer EUF-GUID is set to {5D3E02AB-6190-11D3-BBBB-00C04F795683}
  8. Then is SessionID header. When the actual file data is transfered, the Channel Session ID of that message, in the 48 bytes P2P header is set to this SessionID value. So the current SessionID header is an indication to receiver that when it receives MSNP2P message with Channel Session ID set to this, the data section contains file-data. This typically looks like -
    SessionID: 1189641425\r\n
  9. The AppID indicates the type of file transfer viz, whethere it's buddy icon/image or a file transfer. In case of file transfer AppID is set to 2 like -
    AppID: 2\r\n
  10. Then follows the Context part. Context's value is base64 encoded 250 bytes string which contains name of file and filesize etc information.

A typical MSNP2P file transfer invitation message looks as follows -

>>> MSG 6 D 1348\r\n
    MIME-Version: 1.0\r\n
    Content-Type: application/x-msnmsgrp2p\r\n
    P2P-Dest: some_body@hotmail.com\r\n
    \r\n
    \000\000\000\000-\037\216#\000\000\000\000\000
\000\000\000\271\004\000\000\000\000\000\000
\262\004\000\000\000\000\000\000.\371\234\020\000\000
\000\000\000\000\000\000\000\000\000\000INVITE MSNMSGR some_body@hotmail.com MSNSLP/1.0\r\n
    To: <msnmsgr:some_body @hotmail.com>\r\n
    From: <msnmsgr:this_buddy@hotmail.com>\r\n
    Via: MSNSLP/1.0/TLP ;branch={7E873D59-824B-5084-3544-90B83C8D3C40}\r\n
    CSeq: 0\r\n
    Call-ID: {9C468B3E-4BEA-1C6E-9E6D-1BE9455F8147}\r\n
    Max-Forwards: 0\r\n
    Content-Type: application/x-msnmsgr-sessionreqbody\r\n
    Content-Length: 865\r\n
    \r\n
    EUF-GUID: {5D3E02AB-6190-11D3-BBBB-00C04F795683}\r\n
    SessionID: 1189641425\r\n
    Context: PgIAAAIAAAAsAQAAAAAAAAAAAAB0AGUAcwB0ADEAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n

When the file is actually sent, that time sender sets the Channel SessionID field in 48 bytes MSNP2P header as equal to the SessionID negotiated above in INVITE message. i.e. in above example it will be 1189641425

The receiver responds with MSNP2P message indicating acceptance of invitation, which typically looks like -

<<< MSG some_body@hotmail.com Somebody 487\r\n
    MIME-Version: 1.0\r\n
    Content-Type: application/x-msnmsgrp2p\r\n
    P2P-Dest: this_buddy@hotmail.com\r\n
    \r\n
    \000\000\000\000\016\212\235\020\000\000\000\000\000\000\000
    \000T\001\000\000\000\000\000\000T\001\000\000\000\000\000\000
    \205\360\203%\000\000\000\000\000\000\000\000\000\000\000\000
    MSNSLP/1.0 200 OK\r\n
    To: <msnmsgr:this_buddy@hotmail.com>\r\n
    From: <msnmsgr:some_body@hotmail.com>\r\n
    Via: MSNSLP/1.0/TLP ;branch={7E873D59-824B-5084-3544-90B83C8D3C40}\r\n
    CSeq: 1\r\n
    Call-ID: {9C468B3E-4BEA-1C6E-9E6D-1BE9455F8147}\r\n
    Max-Forwards: 0\r\n
    Content-Type: application/x-msnmsgr-sessionreqbody\r\n
    Content-Length: 26\r\n
    \r\n
    SessionID: 1189641425\r\n
    \r\n
    \000\000\000

A typical file transfer message with actual file data inside it looks like -

>>> MSG 8 D 446\r\n
   MIME-Version: 1.0\r\n
    Content-Type: application/x-msnmsgrp2p\r\n
    P2P-Dest: some_body@hotmail.com\r\n
    \r\n
    \321|\350F.\037\216#\000\000\000\000\000\000\000\000,\001\000\000\000\000\000\000
    \001\000\0000\000\000\0013\302\334\177\000\000\000\000\000\000\000\000\000\000\000\000
    This is test msg for MSN FT 0\n
    This is test msg for MSN FT 1\n
    This is test msg for MSN FT 2\n
    This is test msg for MSN FT 3\n
    This is test msg for MSN FT 4\n
    This is test msg for MSN FT 5\n
    This is test msg for MSN FT 6\n
    This is test msg for MSN FT 7\n
    This is test msg for MSN FT 8\n
    This is test msg for MSN FT 9\n
    \000\000\000\000

Please note that any MSNP2P message first contains the 48 bytes MSNP2P headers before start of any data. So in above case the actual file data starts with This is test msg for MSN FT and previous to that is the 48 bytes header as mentioned above. When the file is huge and cannot be transfered in one packet, it is sent partially through multiple MSNP2P messages. In that case, the Message Size field indicates the total number of bytes from file in this message, and Total Data Size field indicates the total size of file being transfered. So receiver comes to know end of file transfer by examining these fields from 48 bytes P2P header (Typically Offset+ Message Size = Total Data Size indicates that file transfer is complete).

(This section on File Transfer in Older MSN Protocol was researched and submitted by Medha Atre medhaATgs-labDOTcom).

Copyright ©2002-2004 to Mike Mintz.
<http://www.mikemintz.com/>