milgra
about
articles
projects
blogroll
bit-101
coding horror
blameit
failblog
beszeljukmac
sghu
navigation
posts
docs
admin
|
Low level AS3 - Establishing an RTMP connection with Socket and ByteArray
|
First Part - Sniffing around
To reverse engineer rtmp communication, data stream between client and server has to be captured and analyzed somehow. The best and most professional tool for this is wireshark ( previously ethereal ), it is a free and multi-platformed application.
The other two thing needed is an rtmp-capable server ( red5, wowza, or Adobe's FMS ), and a test application with a simple AMF0 - encoded NetConnection.
Start a new live capture in wireshark with an rtmp port filter ( port == 1935 ), then run the test application in flex, and stop both after a successful connection.
The first data from the client is an 1537 bytes long dump:
Source Code
If you connect to the server a few more times, it appears that only the first byte is constant, the last 1536 bytes are generated randomly.
So, the first part of the handshake is a 0x03 byte followed by 1536 random bytes.
Let's check the server's response for this. It's a 3073 bytes length dump, starting with the familiar 0x03. Substracting this from 3073 is 3072, and that is 2 * 1536. Using red5 as the rtmp server the first 1536 is just simple zero-bytes and the second 1536 seems to be the bytes sent by the player from the first handshake.
It looks like the second part of the handshake is a 0x03 byte followed by 1536 bytes generated by the server followed by 1536 bytes generated by the player.
What's next? The player sends 1860 bytes to the server. The first 1536 bytes are zero bytes, it looks they are the bytes received from the server from the previous step. But what is with the second part of the message?
Source Code
Well, it looks like this is our first rtmp packet! But how can we decode this mess? Do you know Smashing Pumpkins? Yes? Then try, try, try! :D
The most boring part comes: from the test application invoke function calls with different identifiers, without arguments, with arguments, with every type of data as argument, and check and analyze the resulting dump. This is my "test dump" :
Source Code
Second Part - Conclusion and Realisation
Analyzing the data stream created by function calls, the following structure has to be implemented:
RTMP header:
first byte :
0x03 in case of a 12 byte length header
or
0x43 in case of a 8 byte length header
or
0xC3 in case of a 0 byte length header
next three bytes:
unknown, can be 0x00
next three bytes:
body length, without inter-chunk headers
maximum body size is FFFFFF = 16777215 bytes
next byte:
body type
0x14 : invoke with AMF data
next four bytes:
unknown, can be 0x00
Body bytes in case of invoke
invoke identifier encoded as an AMF string
followed by a number in double precision floating point number ( maybe result request? )
followed by the AMF-encoded arguments
at connection, an AMF encoded object with compulsory properties needed:
- app : the application identifier to connect to
- swfURL : referrer of the swf
- flashVer : agent
- audioCodecs
- videoCodes
- pageURL
body have to be split up into 128-byte length chunks inserting a 0-byte rtmp header ( 0xC3 ) between chunks
AMF encoding
String:
0x02 followed by the size of the string on two bytes, max length: 65535
null:
0x05
Object
0x03 closed by 0x00 0x00 0x09
key - value pairs are defined inside them, keys as amf strings
values as amf encoded data
Fortunately we don't need to know how to encode AMF data, because ByteArray has a built-in AMF encoder function, and it is also faster than a simple implementation.
And that's all. Let's see how to realize it:
Source Code
A few useful links on RTMP and AMF:
http://osflash.org/documentation/rtmp
http://osflash.org/_media/rtmp_spec.jpg
http://osflash.org/documentation/amf/astypes
http://osflash.org/documentation/amf/datatypes
http://osflash.org/documentation/amf3
Article on actionscript.org
MilGra
|
|