From 6bff69af3070c733197cbcfaa5ba9b690a7d8342 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Tue, 27 Jul 2010 23:01:54 +0200 Subject: [PATCH] Meer cleanup, chunkstream implemented --- .gitignore | 7 ++ RTMP/Connector/Makefile | 24 +++++ RTMP/Connector/chunkstream.cpp | 138 ++++++++++++++++++++++++++ RTMP/Connector/handshake.cpp | 40 ++++++++ RTMP/Connector/main.cpp | 175 +++++++++++++-------------------- 5 files changed, 277 insertions(+), 107 deletions(-) create mode 100644 .gitignore create mode 100644 RTMP/Connector/Makefile create mode 100644 RTMP/Connector/chunkstream.cpp create mode 100644 RTMP/Connector/handshake.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..eff93cb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +#ignore object files and nonsense like that +*.[oa] +Client_PLS +Server_PLS +Connector_RTMP +*~ + diff --git a/RTMP/Connector/Makefile b/RTMP/Connector/Makefile new file mode 100644 index 00000000..c7a44e45 --- /dev/null +++ b/RTMP/Connector/Makefile @@ -0,0 +1,24 @@ +SRC = main.cpp +OBJ = $(SRC:.cpp=.o) +OUT = Connector_RTMP +INCLUDES = +CCFLAGS = -Wall -Wextra -funsigned-char -g +CC = $(CROSS)g++ +LD = $(CROSS)ld +AR = $(CROSS)ar +LIBS = +.SUFFIXES: .cpp +.PHONY: clean default +default: $(OUT) +.cpp.o: + $(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@ +$(OUT): $(OBJ) handshake.cpp chunkstream.cpp + $(CC) $(LIBS) -o $(OUT) $(OBJ) +clean: + rm -rf $(OBJ) $(OUT) Makefile.bak *~ +run-test: $(OUT) + rm -rf ./meh + mkfifo ./meh + nc -o test -l -p 1935 -e './Connector_RTMP 2>./meh' +run-cat: + cat < ./meh diff --git a/RTMP/Connector/chunkstream.cpp b/RTMP/Connector/chunkstream.cpp new file mode 100644 index 00000000..fc340768 --- /dev/null +++ b/RTMP/Connector/chunkstream.cpp @@ -0,0 +1,138 @@ +struct chunkpack { + unsigned char chunktype; + unsigned int cs_id; + unsigned int timestamp; + unsigned int len; + unsigned int real_len; + unsigned int len_left; + unsigned char msg_type_id; + unsigned int msg_stream_id; + unsigned char * data; +};//chunkpack + +unsigned int chunk_rec_max = 128; + +//clean a chunk so that it may be re-used without memory leaks +void scrubChunk(struct chunkpack c){ + if (c.data){free(c.data);} + c.data = 0; + c.real_len = 0; +}//scrubChunk + +//get a chunk from standard input +struct chunkpack getChunk(struct chunkpack prev){ + struct chunkpack ret; + unsigned char temp; + fread(&(ret.chunktype), 1, 1, stdin); + fprintf(stderr, "Got chunkstream ID %hhi\n", ret.chunktype & 0x3F); + switch (ret.chunktype & 0x3F){ + case 0: + fread(&temp, 1, 1, stdin); + ret.cs_id = temp + 64; + break; + case 1: + fread(&temp, 1, 1, stdin); + ret.cs_id = temp + 64; + fread(&temp, 1, 1, stdin); + ret.cs_id += temp * 256; + break; + default: + ret.cs_id = ret.chunktype & 0x3F; + break; + } + fprintf(stderr, "Got a type %hhi chunk\n", ret.chunktype & 0xC0); + switch (ret.chunktype & 0xC0){ + case 0: + fread(&temp, 1, 1, stdin); + ret.timestamp = temp*256*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp; + fread(&temp, 1, 1, stdin); + ret.len = temp*256*256; + fread(&temp, 1, 1, stdin); + ret.len += temp*256; + fread(&temp, 1, 1, stdin); + ret.len += temp; + ret.len_left = 0; + fread(&temp, 1, 1, stdin); + ret.msg_type_id = temp; + fread(&temp, 1, 1, stdin); + ret.msg_stream_id = temp*256*256; + fread(&temp, 1, 1, stdin); + ret.msg_stream_id += temp*256; + fread(&temp, 1, 1, stdin); + ret.msg_stream_id += temp; + break; + case 1: + fread(&temp, 1, 1, stdin); + ret.timestamp = temp*256*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp; + ret.timestamp += prev.timestamp; + fread(&temp, 1, 1, stdin); + ret.len = temp*256*256; + fread(&temp, 1, 1, stdin); + ret.len += temp*256; + fread(&temp, 1, 1, stdin); + ret.len += temp; + ret.len_left = 0; + fread(&temp, 1, 1, stdin); + ret.msg_type_id = temp; + ret.msg_stream_id = prev.msg_stream_id; + break; + case 2: + fread(&temp, 1, 1, stdin); + ret.timestamp = temp*256*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp; + ret.timestamp += prev.timestamp; + ret.len = prev.len; + ret.len_left = prev.len_left; + ret.msg_type_id = prev.msg_type_id; + ret.msg_stream_id = prev.msg_stream_id; + break; + case 3: + ret.timestamp = prev.timestamp; + ret.len = prev.len; + ret.len_left = prev.len_left; + ret.msg_type_id = prev.msg_type_id; + ret.msg_stream_id = prev.msg_stream_id; + break; + } + fprintf(stderr, "Timestamp: %i\n", ret.timestamp); + fprintf(stderr, "Length: %i\n", ret.len); + fprintf(stderr, "Message type ID: %hhi\n", ret.msg_type_id); + fprintf(stderr, "Message stream ID: %i\n", ret.msg_stream_id); + if (ret.len_left > 0){ + ret.real_len = ret.len_left; + ret.len_left -= ret.real_len; + }else{ + ret.real_len = ret.len; + } + if (ret.real_len > chunk_rec_max){ + ret.len_left += ret.real_len - chunk_rec_max; + } + if (ret.timestamp == 0x00ffffff){ + fread(&temp, 1, 1, stdin); + ret.timestamp = temp*256*256*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp*256*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp*256; + fread(&temp, 1, 1, stdin); + ret.timestamp += temp; + } + if (ret.real_len > 0){ + ret.data = (unsigned char*)malloc(ret.real_len); + fread(ret.data, 1, ret.real_len, stdin); + }else{ + ret.data = 0; + } + return ret; +} diff --git a/RTMP/Connector/handshake.cpp b/RTMP/Connector/handshake.cpp new file mode 100644 index 00000000..9b527cde --- /dev/null +++ b/RTMP/Connector/handshake.cpp @@ -0,0 +1,40 @@ +struct Handshake { + char Time[4]; + char Zero[4]; + char Random[1528]; +};//Handshake + +void doHandshake(){ + srand(time(NULL)); + char Version; + Handshake Client; + Handshake Server; + /** Read C0 **/ + fread(&(Version), 1, 1, stdin); + /** Read C1 **/ + fread(Client.Time, 1, 4, stdin); + fread(Client.Zero, 1, 4, stdin); + fread(Client.Random, 1, 1528, stdin); + /** Build S1 Packet **/ + Server.Time[0] = 0; Server.Time[1] = 0; Server.Time[2] = 0; Server.Time[3] = 0; + Server.Zero[0] = 0; Server.Zero[1] = 0; Server.Zero[2] = 0; Server.Zero[3] = 0; + for (int i = 0; i < 1528; i++){Server.Random[i] = (rand() % 256);} + /** Send S0 **/ + fwrite(&(Version), 1, 1, stdout); + /** Send S1 **/ + fwrite(Server.Time, 1, 4, stdout); + fwrite(Server.Zero, 1, 4, stdout); + fwrite(Server.Random, 1, 1528, stdout); + /** Flush output, just for certainty **/ + fflush(stdout); + /** Send S2 **/ + fwrite(Client.Time, 1, 4, stdout); + fwrite(Client.Time, 1, 4, stdout); + fwrite(Client.Random, 1, 1528, stdout); + /** Flush, necessary in order to work **/ + fflush(stdout); + /** Read and discard C2 **/ + fread(Client.Time, 1, 4, stdin); + fread(Client.Zero, 1, 4, stdin); + fread(Client.Random, 1, 1528, stdin); +}//doHandshake \ No newline at end of file diff --git a/RTMP/Connector/main.cpp b/RTMP/Connector/main.cpp index 1fbd942f..275cd69e 100644 --- a/RTMP/Connector/main.cpp +++ b/RTMP/Connector/main.cpp @@ -2,116 +2,77 @@ #include #include #include +#include "handshake.cpp" //handshaking +#include "chunkstream.cpp" //chunkstream decoding -struct Handshake_0 { - char Version; -};//Handshake_0 +int main(){ + chunkpack prev, next; + doHandshake(); + std::cerr << "Handshake completed" << std::endl; -struct Handshake_1 { - char Time[4]; - char Zero[4]; - char Random[1528]; -};//Handshake_1 - -struct Handshake_2 { - char Time[4]; - char Time2[4]; - char Random_Echo[1528]; -};//Handshake_2 - -int main( ) { - srand( time( NULL ) ); - char next; - char chunk_header[14];//Space to any chunk header imaginable. Basic header max 3, Chunck msg header max 11 - char extended_timestamp[4];//Not always used, so not included in header space. - int chunkIDlenght; - int chunkstream_id; - Handshake_0 Client_0; - Handshake_1 Client_1; - Handshake_2 Client_2; - Handshake_1 Server_1; - Handshake_2 Server_2; - /** Start Handshake **/ - - /** Read C0 **/ - std::cin >> Client_0.Version; - /** Read C1 **/ - fread( Client_1.Time, 1, 4, stdin); - fread( Client_1.Zero, 1, 4, stdin); - fread( Client_1.Random, 1, 1528, stdin); - /** Build S1 Packet **/ - Server_1.Time[0] = 0; Server_1.Time[1] = 0; Server_1.Time[2] = 0; Server_1.Time[3] = 4; - Server_1.Zero[0] = 0; Server_1.Zero[1] = 0; Server_1.Zero[2] = 0; Server_1.Zero[3] = 0; - for (int i = 0; i < 1528; i++) { Server_1.Random[i] = (rand() % 256); } - /** Send S0 **/ - std::cout << Client_0.Version; - /** Send S1 **/ - std::cout << Server_1.Time[0]; - std::cout << Server_1.Time[1]; - std::cout << Server_1.Time[2]; - std::cout << Server_1.Time[3]; - std::cout << Server_1.Zero[0]; - std::cout << Server_1.Zero[1]; - std::cout << Server_1.Zero[2]; - std::cout << Server_1.Zero[3]; - for (int i = 0; i < 1528; i++) { - std::cout << Server_1.Random[i]; - } - /** Flush output, just for certainty **/ - std::cout << std::flush; - /** Build S2 Packet **/ - for (int i = 0; i < 4; i++ ) { - Server_2.Time[i] = Client_1.Time[i]; - Server_2.Time2[i] = Server_2.Time[i]; - } - Server_2.Time2[3] = Server_2.Time2[3] + 1; - /** Send S2 **/ - std::cout << Server_2.Time[0]; - std::cout << Server_2.Time[1]; - std::cout << Server_2.Time[2]; - std::cout << Server_2.Time[3]; - std::cout << Server_2.Time2[0]; - std::cout << Server_2.Time2[1]; - std::cout << Server_2.Time2[2]; - std::cout << Server_2.Time2[3]; - for (int i = 0; i < 1528; i++) { - std::cout << Client_1.Random[i]; - } - /** Flush, necessary in order to work **/ - std::cout << std::flush; - /** Read C2 **/ - fread( Client_2.Time, 1, 4, stdin); - fread( Client_2.Time2, 1, 4, stdin); - fread( Client_2.Random_Echo, 1, 1528, stdin); - - /** Handshake done, continue with connect command **/ - - int chunkIDlength = 0; - next = std::cin.peek(); - if (next > 63 || next == 2) { exit(1); }//Connect command has a 11 byte header, ALWAYS, maximum value of first byte is then 63 - if (next <= 63 && next >= 3) {//1 byte chunkstream ID - fread ( chunk_header, 1, 12, stdin ); - chunkIDlength = 1; - } else if ((int) next == 0 ) {//2 bytes chunkstream ID - fread ( chunk_header, 1, 13, stdin ); - chunkIDlength = 2; - } else if ((int) next == 1 ) {//3 bytes chunkstream ID - fread ( chunk_header, 1, 14, stdin ); - chunkIDlength = 3; - } - switch(chunkIDlength) { - case 1: chunkstream_id = (int)chunk_header[0]; break; - case 2: chunkstream_id = (int)chunk_header[1] + 64; break; - case 3: chunkstream_id = ((int)chunk_header[2] * 256) + (int)chunk_header[1] + 64; break; - default: exit(1); break;//Something went wrong - } - - if ( chunk_header[chunkIDlength] == 0xFF && chunk_header[chunkIDlength+1] == 0xFF && chunk_header[chunkIDlength+2] == 0xFF ) { - fread ( extended_timestamp, 1, 4, stdin); //read extended timestamp if 3-byte timestamp equals 0xFFFFFF - } else {//set extended timestamp to 0 - extended_timestamp[0] = 0; extended_timestamp[1] = 0; extended_timestamp[2] = 0; extended_timestamp[3] = 0; + prev.len = 0; + prev.data = 0; + while (!feof(stdin)){ + next = getChunk(prev); + if (next.cs_id == 2 && next.msg_stream_id == 0){ + fprintf(stderr, "Received protocol message. (cs_id 2, stream id 0)\nContents:\n"); + fwrite(next.data, 1, next.real_len, stderr); + fflush(stderr); + } + switch (next.msg_type_id){ + case 1: + fprintf(stderr, "CTRL: Set chunk size\n"); + break; + case 2: + fprintf(stderr, "CTRL: Abort message\n"); + break; + case 3: + fprintf(stderr, "CTRL: Acknowledgement\n"); + break; + case 4: + fprintf(stderr, "CTRL: User control message\n"); + break; + case 5: + fprintf(stderr, "CTRL: Window size\n"); + break; + case 6: + fprintf(stderr, "CTRL: Set peer bandwidth\n"); + break; + case 8: + fprintf(stderr, "Received audio data\n"); + break; + case 9: + fprintf(stderr, "Received video data\n"); + break; + case 15: + fprintf(stderr, "Received AFM3 data message\n"); + break; + case 16: + fprintf(stderr, "Received AFM3 shared object\n"); + break; + case 17: + fprintf(stderr, "Received AFM3 command message\n"); + break; + case 18: + fprintf(stderr, "Received AFM0 data message\n"); + break; + case 19: + fprintf(stderr, "Received AFM0 shared object\n"); + break; + case 20: + fprintf(stderr, "Received AFM0 command message\n"); + break; + case 22: + fprintf(stderr, "Received aggregate message\n"); + break; + default: + fprintf(stderr, "Unknown chunk received!\n"); + break; + } + scrubChunk(prev); + prev = next; } return 0; -} +}//main