Werkende RTMP connector! WHEEEE! Also, RTMPf weggegooit. Er is geen ruimte voor faal in dit bedrijf!

This commit is contained in:
Thulinma 2010-11-17 01:05:36 +01:00
parent fbd0520264
commit 273f30784b
22 changed files with 123 additions and 2015 deletions

View file

@ -70,7 +70,7 @@ int main( int argc, char * argv[] ) {
//invalidate the current buffer //invalidate the current buffer
ringbuf[current_buffer]->number = -1; ringbuf[current_buffer]->number = -1;
if ((epoll_wait(poller, events, 1, 100) > 0) && FLV_GetPacket(ringbuf[current_buffer]->FLV)){ if ((epoll_wait(poller, events, 1, 100) > 0) && FLV_GetPacket(ringbuf[current_buffer]->FLV)){
loopcount ++; loopcount++;
packtype = ringbuf[current_buffer]->FLV->data[0]; packtype = ringbuf[current_buffer]->FLV->data[0];
//store metadata, if available //store metadata, if available
if (packtype == 0x12){ if (packtype == 0x12){
@ -113,12 +113,14 @@ int main( int argc, char * argv[] ) {
} }
//on keyframe set start point //on keyframe set start point
if (packtype == 0x09){ if (packtype == 0x09){
if (((ringbuf[current_buffer]->FLV->data[11] & 0xf0) >> 4) == 1){lastproper = current_buffer;} if (((ringbuf[current_buffer]->FLV->data[11] & 0xf0) >> 4) == 1){
lastproper = current_buffer;
}
} }
//keep track of buffers //keep track of buffers
ringbuf[current_buffer]->number = loopcount;
current_buffer++; current_buffer++;
current_buffer %= buffers; current_buffer %= buffers;
ringbuf[current_buffer]->number = loopcount;
} }
//check for new connections, accept them if there are any //check for new connections, accept them if there are any

View file

@ -5,5 +5,5 @@
#ffmpeg -y -i "$1" -ar 44100 -vcodec libx264 -b 1000k -g 150 -r 20 -f flv - | ./Buffer 500 #ffmpeg -y -i "$1" -ar 44100 -vcodec libx264 -b 1000k -g 150 -r 20 -f flv - | ./Buffer 500
ffmpeg -i "$1" -re -acodec aac -ar 11025 -vcodec libx264 -b 700k -vpre ultrafast -refs 1 -bf 0 -g 150 -f flv - 2> /dev/null | ./Buffer 500 ffmpeg -i "$1" -re -acodec aac -ar 11025 -vcodec libx264 -b 700k -vpre ultrafast -refs 1 -bf 0 -g 150 -f flv - 2> /dev/null | ./Buffer 500 $2

View file

@ -11,7 +11,7 @@ LIBS = -lssl -lcrypto
.PHONY: clean default .PHONY: clean default
default: $(OUT) default: $(OUT)
.cpp.o: .cpp.o:
$(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@ $(CC) $(INCLUDES) $(CCFLAGS) -c $< -o $@
$(OUT): $(OBJ) chunkstream.cpp parsechunks.cpp handshake.cpp crypto.cpp amf.cpp $(OUT): $(OBJ) chunkstream.cpp parsechunks.cpp handshake.cpp crypto.cpp amf.cpp
$(CC) $(LIBS) -o $(OUT) $(OBJ) $(CC) $(LIBS) -o $(OUT) $(OBJ)
clean: clean:

View file

@ -270,7 +270,7 @@ AMFType parseOneAMF(const unsigned char *& data, unsigned int &len, unsigned int
return ret; return ret;
} break; } break;
} }
#ifdef DEBUG #if DEBUG >= 2
fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]); fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]);
#endif #endif
return AMFType("error", (unsigned char)0xFF); return AMFType("error", (unsigned char)0xFF);

View file

@ -457,7 +457,7 @@ chunkpack * AddChunkPart(chunkpack newchunk){
p = it->second; p = it->second;
tmpdata = (unsigned char*)realloc(p->data, p->real_len + newchunk.real_len); tmpdata = (unsigned char*)realloc(p->data, p->real_len + newchunk.real_len);
if (tmpdata == 0){ if (tmpdata == 0){
#ifdef DEBUG #if DEBUG >= 1
fprintf(stderr, "Error allocating memory!\n"); fprintf(stderr, "Error allocating memory!\n");
#endif #endif
return 0; return 0;

View file

@ -497,7 +497,7 @@ bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) {
uint8_t *pTempHash = new uint8_t[512]; uint8_t *pTempHash = new uint8_t[512];
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
bool result = (memcmp(pBuffer+clientDigestOffset, pTempHash, 32) == 0); bool result = (memcmp(pBuffer+clientDigestOffset, pTempHash, 32) == 0);
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed"); fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed");
#endif #endif
delete[] pTempBuffer; delete[] pTempBuffer;

View file

@ -69,14 +69,14 @@ bool doHandshake(){
for (int i = 8; i < 3072; ++i){Server[i] = versionstring[i%13];}//"random" data for (int i = 8; i < 3072; ++i){Server[i] = versionstring[i%13];}//"random" data
bool encrypted = (Version == 6); bool encrypted = (Version == 6);
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Handshake version is %hhi\n", Version); fprintf(stderr, "Handshake version is %hhi\n", Version);
#endif #endif
uint8_t _validationScheme = 5; uint8_t _validationScheme = 5;
if (ValidateClientScheme(Client, 0)) _validationScheme = 0; if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
if (ValidateClientScheme(Client, 1)) _validationScheme = 1; if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off"); fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off");
#endif #endif

View file

@ -1,4 +1,10 @@
#undef DEBUG //debugging level 0 = nothing
//debugging level 1 = critical errors
//debugging level 2 = errors
//debugging level 3 = status information
//debugging level 4 = extremely verbose status information
#define DEBUG 3
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
#include <cstdio> #include <cstdio>
@ -27,6 +33,12 @@ int server_socket = 0;
void termination_handler (int signum){ void termination_handler (int signum){
if (server_socket == 0) return; if (server_socket == 0) return;
switch (signum){
case SIGINT: break;
case SIGHUP: break;
case SIGTERM: break;
default: return; break;
}
close(server_socket); close(server_socket);
server_socket = 0; server_socket = 0;
} }
@ -41,9 +53,16 @@ int main(int argc, char ** argv){
sigaction (SIGHUP, &new_action, NULL); sigaction (SIGHUP, &new_action, NULL);
sigaction (SIGTERM, &new_action, NULL); sigaction (SIGTERM, &new_action, NULL);
server_socket = DDV_Listen(1936); server_socket = DDV_Listen(1935);
if ((argc < 2) || (argv[1] == "nd")){ fprintf(stderr, "Made a listening socket on port 1936...");
if (server_socket > 0){daemon(1, 0);}else{return 1;} if ((argc < 2) || (strcmp(argv[1], "nd") != 0)){
if (server_socket > 0){
daemon(1, 0);
fprintf(stderr, "Going into background mode...");
}else{
fprintf(stderr, "Error: could not make listening socket");
return 1;
}
} }
int status; int status;
while (server_socket > 0){ while (server_socket > 0){
@ -54,7 +73,7 @@ int main(int argc, char ** argv){
if (myid == 0){ if (myid == 0){
break; break;
}else{ }else{
printf("Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd); fprintf(stderr, "Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd);
} }
} }
} }
@ -71,23 +90,16 @@ int main(int argc, char ** argv){
//first timestamp set //first timestamp set
firsttime = getNowMS(); firsttime = getNowMS();
#ifdef DEBUG
fprintf(stderr, "Doing handshake...\n");
#endif
if (doHandshake()){ if (doHandshake()){
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Handshake succcess!\n"); fprintf(stderr, "Handshake succcess!\n");
#endif #endif
}else{ }else{
#ifdef DEBUG #if DEBUG >= 1
fprintf(stderr, "Handshake fail!\n"); fprintf(stderr, "Handshake fail!\n");
#endif #endif
return 0; return 0;
} }
#ifdef DEBUG
fprintf(stderr, "Starting processing...\n");
#endif
int retval; int retval;
int poller = epoll_create(1); int poller = epoll_create(1);
@ -104,10 +116,17 @@ int main(int argc, char ** argv){
while (!socketError && !All_Hell_Broke_Loose){ while (!socketError && !All_Hell_Broke_Loose){
//only parse input if available or not yet init'ed //only parse input if available or not yet init'ed
//rightnow = getNowMS(); //rightnow = getNowMS();
retval = epoll_wait(poller, events, 1, 0); retval = epoll_wait(poller, events, 1, 1);
if ((retval > 0) || !ready4data || (snd_cnt - snd_window_at >= snd_window_size)){ if ((retval > 0) || !ready4data){// || (snd_cnt - snd_window_at >= snd_window_size)
if (DDV_ready(CONN_fd)){ switch (DDV_ready(CONN_fd)){
parseChunk(); case 0:
socketError = true;
#if DEBUG >= 1
fprintf(stderr, "User socket is disconnected.\n");
#endif
break;
case -1: break;//not ready yet
default: parseChunk(); break;
} }
} }
if (ready4data){ if (ready4data){
@ -115,47 +134,57 @@ int main(int argc, char ** argv){
//we are ready, connect the socket! //we are ready, connect the socket!
ss = DDV_OpenUnix(streamname); ss = DDV_OpenUnix(streamname);
if (ss <= 0){ if (ss <= 0){
#ifdef DEBUG #if DEBUG >= 1
fprintf(stderr, "Could not connect to server!\n"); fprintf(stderr, "Could not connect to server!\n");
#endif #endif
return 0; socketError = 1;
break;
} }
ev.events = EPOLLIN; ev.events = EPOLLIN;
ev.data.fd = ss; ev.data.fd = ss;
epoll_ctl(sspoller, EPOLL_CTL_ADD, ss, &ev); epoll_ctl(sspoller, EPOLL_CTL_ADD, ss, &ev);
#ifdef DEBUG #if DEBUG >= 3
fprintf(stderr, "Everything connected, starting to send video data...\n"); fprintf(stderr, "Everything connected, starting to send video data...\n");
#endif #endif
inited = true; inited = true;
} }
retval = epoll_wait(poller, events, 1, 50); retval = epoll_wait(poller, events, 1, 1);
if (DDV_ready(ss)){ switch (DDV_ready(ss)){
if (FLV_GetPacket(tag, ss)){//able to read a full packet? case 0:
ts = tag->data[7] * 256*256*256; socketError = true;
ts += tag->data[4] * 256*256; #if DEBUG >= 1
ts += tag->data[5] * 256; fprintf(stderr, "Source socket is disconnected.\n");
ts += tag->data[6];
if (ts != 0){
if (fts == 0){fts = ts;ftst = getNowMS();}
ts -= fts;
tag->data[7] = ts / (256*256*256);
tag->data[4] = ts / (256*256);
tag->data[5] = ts / 256;
tag->data[6] = ts % 256;
ts += ftst;
}else{
ftst = getNowMS();
tag->data[7] = ftst / (256*256*256);
tag->data[4] = ftst / (256*256);
tag->data[5] = ftst / 256;
tag->data[6] = ftst % 256;
}
SendMedia((unsigned char)tag->data[0], (unsigned char *)tag->data+11, tag->len-15, ts);
#ifdef DEBUG
fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
#endif #endif
} break;
case -1: break;//not ready yet
default:
if (FLV_GetPacket(tag, ss)){//able to read a full packet?
ts = tag->data[7] * 256*256*256;
ts += tag->data[4] * 256*256;
ts += tag->data[5] * 256;
ts += tag->data[6];
if (ts != 0){
if (fts == 0){fts = ts;ftst = getNowMS();}
ts -= fts;
tag->data[7] = ts / (256*256*256);
tag->data[4] = ts / (256*256);
tag->data[5] = ts / 256;
tag->data[6] = ts % 256;
ts += ftst;
}else{
ftst = getNowMS();
tag->data[7] = ftst / (256*256*256);
tag->data[4] = ftst / (256*256);
tag->data[5] = ftst / 256;
tag->data[6] = ftst % 256;
}
SendMedia((unsigned char)tag->data[0], (unsigned char *)tag->data+11, tag->len-15, ts);
#if DEBUG >= 4
fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
#endif
}
break;
} }
} }
//send ACK if we received a whole window //send ACK if we received a whole window
@ -164,10 +193,10 @@ int main(int argc, char ** argv){
SendCTL(3, rec_cnt);//send ack (msg 3) SendCTL(3, rec_cnt);//send ack (msg 3)
} }
} }
//#ifdef DEBUG close(CONN_fd);
if (socketError){fprintf(stderr, "socketError\n");} #if DEBUG >= 1
if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");} if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
fprintf(stderr, "User %i disconnected.\n", CONN_fd); fprintf(stderr, "User %i disconnected.\n", CONN_fd);
//#endif #endif
return 0; return 0;
}//main }//main

View file

@ -13,25 +13,25 @@ void parseChunk(){
break;//happens when connection breaks unexpectedly break;//happens when connection breaks unexpectedly
case 1://set chunk size case 1://set chunk size
chunk_rec_max = ntohl(*(int*)next.data); chunk_rec_max = ntohl(*(int*)next.data);
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "CTRL: Set chunk size: %i\n", chunk_rec_max); fprintf(stderr, "CTRL: Set chunk size: %i\n", chunk_rec_max);
#endif #endif
break; break;
case 2://abort message - we ignore this one case 2://abort message - we ignore this one
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "CTRL: Abort message\n"); fprintf(stderr, "CTRL: Abort message\n");
#endif #endif
//4 bytes of stream id to drop //4 bytes of stream id to drop
break; break;
case 3://ack case 3://ack
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "CTRL: Acknowledgement\n"); fprintf(stderr, "CTRL: Acknowledgement\n");
#endif #endif
snd_window_at = ntohl(*(int*)next.data); snd_window_at = ntohl(*(int*)next.data);
snd_window_at = snd_cnt; snd_window_at = snd_cnt;
break; break;
case 4:{ case 4:{
#ifdef DEBUG #if DEBUG >= 4
short int ucmtype = ntohs(*(short int*)next.data); short int ucmtype = ntohs(*(short int*)next.data);
fprintf(stderr, "CTRL: User control message %hi\n", ucmtype); fprintf(stderr, "CTRL: User control message %hi\n", ucmtype);
#endif #endif
@ -47,7 +47,7 @@ void parseChunk(){
//we don't need to process this //we don't need to process this
} break; } break;
case 5://window size of other end case 5://window size of other end
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "CTRL: Window size\n"); fprintf(stderr, "CTRL: Window size\n");
#endif #endif
rec_window_size = ntohl(*(int*)next.data); rec_window_size = ntohl(*(int*)next.data);
@ -55,7 +55,7 @@ void parseChunk(){
SendCTL(3, rec_cnt);//send ack (msg 3) SendCTL(3, rec_cnt);//send ack (msg 3)
break; break;
case 6: case 6:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "CTRL: Set peer bandwidth\n"); fprintf(stderr, "CTRL: Set peer bandwidth\n");
#endif #endif
//4 bytes window size, 1 byte limit type (ignored) //4 bytes window size, 1 byte limit type (ignored)
@ -63,49 +63,45 @@ void parseChunk(){
SendCTL(5, snd_window_size);//send window acknowledgement size (msg 5) SendCTL(5, snd_window_size);//send window acknowledgement size (msg 5)
break; break;
case 8: case 8:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received audio data\n"); fprintf(stderr, "Received audio data\n");
#endif #endif
break; break;
case 9: case 9:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received video data\n"); fprintf(stderr, "Received video data\n");
#endif #endif
break; break;
case 15: case 15:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received AFM3 data message\n"); fprintf(stderr, "Received AFM3 data message\n");
#endif #endif
break; break;
case 16: case 16:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received AFM3 shared object\n"); fprintf(stderr, "Received AFM3 shared object\n");
#endif #endif
break; break;
case 17: case 17:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received AFM3 command message\n"); fprintf(stderr, "Received AFM3 command message\n");
#endif #endif
break; break;
case 18: case 18:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received AFM0 data message\n"); fprintf(stderr, "Received AFM0 data message\n");
#endif #endif
break; break;
case 19: case 19:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received AFM0 shared object\n"); fprintf(stderr, "Received AFM0 shared object\n");
#endif #endif
break; break;
case 20:{//AMF0 command message case 20:{//AMF0 command message
bool parsed = false; bool parsed = false;
amfdata = parseAMF(next.data, next.real_len); amfdata = parseAMF(next.data, next.real_len);
#ifdef DEBUG
fprintf(stderr, "Received AFM0 command message:\n");
amfdata.Print();
#endif
if (amfdata.getContentP(0)->StrValue() == "connect"){ if (amfdata.getContentP(0)->StrValue() == "connect"){
#ifdef DEBUG #if DEBUG >= 4
int tmpint; int tmpint;
tmpint = amfdata.getContentP(2)->getContentP("videoCodecs")->NumValue(); tmpint = amfdata.getContentP(2)->getContentP("videoCodecs")->NumValue();
if (tmpint & 0x04){fprintf(stderr, "Sorensen video support detected\n");} if (tmpint & 0x04){fprintf(stderr, "Sorensen video support detected\n");}
@ -149,9 +145,6 @@ void parseChunk(){
amfreply.addContent(AMFType("", (double)1));//stream ID - we use 1 amfreply.addContent(AMFType("", (double)1));//stream ID - we use 1
SendChunk(3, 20, next.msg_stream_id, amfreply.Pack()); SendChunk(3, 20, next.msg_stream_id, amfreply.Pack());
SendUSR(0, 0);//send UCM StreamBegin (0), stream 0 SendUSR(0, 0);//send UCM StreamBegin (0), stream 0
#ifdef DEBUG
fprintf(stderr, "AMF0 command: createStream result\n");
#endif
parsed = true; parsed = true;
}//createStream }//createStream
if ((amfdata.getContentP(0)->StrValue() == "getStreamLength") || (amfdata.getContentP(0)->StrValue() == "getMovLen")){ if ((amfdata.getContentP(0)->StrValue() == "getStreamLength") || (amfdata.getContentP(0)->StrValue() == "getMovLen")){
@ -162,9 +155,6 @@ void parseChunk(){
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType("", (double)0));//zero length amfreply.addContent(AMFType("", (double)0));//zero length
SendChunk(3, 20, next.msg_stream_id, amfreply.Pack()); SendChunk(3, 20, next.msg_stream_id, amfreply.Pack());
#ifdef DEBUG
fprintf(stderr, "AMF0 command: getStreamLength result\n");
#endif
parsed = true; parsed = true;
}//getStreamLength }//getStreamLength
if (amfdata.getContentP(0)->StrValue() == "checkBandwidth"){ if (amfdata.getContentP(0)->StrValue() == "checkBandwidth"){
@ -175,9 +165,6 @@ void parseChunk(){
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
SendChunk(3, 20, 1, amfreply.Pack()); SendChunk(3, 20, 1, amfreply.Pack());
#ifdef DEBUG
fprintf(stderr, "AMF0 command: checkBandwidth result\n");
#endif
parsed = true; parsed = true;
}//checkBandwidth }//checkBandwidth
if ((amfdata.getContentP(0)->StrValue() == "play") || (amfdata.getContentP(0)->StrValue() == "play2")){ if ((amfdata.getContentP(0)->StrValue() == "play") || (amfdata.getContentP(0)->StrValue() == "play2")){
@ -220,24 +207,24 @@ void parseChunk(){
chunk_snd_max = 1024*1024; chunk_snd_max = 1024*1024;
SendCTL(1, chunk_snd_max);//send chunk size max (msg 1) SendCTL(1, chunk_snd_max);//send chunk size max (msg 1)
ready4data = true;//start sending video data! ready4data = true;//start sending video data!
#ifdef DEBUG
fprintf(stderr, "AMF0 command: play result (%s)\n", streamname.c_str());
#endif
parsed = true; parsed = true;
}//createStream }//createStream
#if DEBUG >= 3
fprintf(stderr, "AMF0 command: %s\n", amfdata.getContentP(0)->StrValue().c_str());
#endif
if (!parsed){ if (!parsed){
#ifdef DEBUG #if DEBUG >= 2
fprintf(stderr, "AMF0 command not processed! :(\n"); fprintf(stderr, "AMF0 command not processed! :(\n");
#endif #endif
} }
} break; } break;
case 22: case 22:
#ifdef DEBUG #if DEBUG >= 4
fprintf(stderr, "Received aggregate message\n"); fprintf(stderr, "Received aggregate message\n");
#endif #endif
break; break;
default: default:
#ifdef DEBUG #if DEBUG >= 1
fprintf(stderr, "Unknown chunk received! Probably protocol corruption, stopping parsing of incoming data.\n"); fprintf(stderr, "Unknown chunk received! Probably protocol corruption, stopping parsing of incoming data.\n");
#endif #endif
stopparsing = true; stopparsing = true;

View file

@ -1,23 +0,0 @@
SRC = main.cpp ../sockets/sw_base.cpp ../sockets/sw_inet.cpp ../sockets/sw_unix.cpp
OBJ = $(SRC:.cpp=.o)
OUT = Connector_RTMPf
INCLUDES =
CCFLAGS = -Wall -Wextra -funsigned-char -g
CC = $(CROSS)g++
LD = $(CROSS)ld
AR = $(CROSS)ar
LIBS = -lssl -lcrypto
.SUFFIXES: .cpp
.PHONY: clean default
default: $(OUT)
.cpp.o:
$(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@
$(OUT): $(OBJ) chunkstream.cpp parsechunks.cpp handshake.cpp crypto.cpp amf.cpp
$(CC) $(LIBS) -o $(OUT) $(OBJ)
clean:
rm -rf $(OBJ) $(OUT) Makefile.bak *~
run-test: $(OUT)
rm -rf ./meh
mkfifo ./meh
cat ./meh &
nc -l -p 1935 -e './Connector_RTMPf 2>./meh'

View file

@ -1,285 +0,0 @@
#include <vector>
#include <string.h>
#include <string>
class AMFType {
public:
std::string Indice(){return myIndice;};
unsigned char GetType(){return myType;};
double NumValue(){return numval;};
std::string StrValue(){return strval;};
const char * Str(){return strval.c_str();};
int hasContent(){
if (!contents){return 0;}
return contents->size();
};
void addContent(AMFType c){if (contents != 0){contents->push_back(c);}};
AMFType* getContentP(int i){if (contents != 0){return &contents->at(i);}else{return 0;}};
AMFType getContent(int i){if (contents != 0){return contents->at(i);}else{return AMFType("error");}};
AMFType* getContentP(std::string s){
if (contents != 0){
for (std::vector<AMFType>::iterator it = contents->begin(); it != contents->end(); it++){
if (it->Indice() == s){
return &(*it);
}
}
}
return this;
};
AMFType getContent(std::string s){
if (contents != 0){
for (std::vector<AMFType>::iterator it = contents->begin(); it != contents->end(); it++){
if (it->Indice() == s){
return *it;
}
}
}
return AMFType("error");
};
AMFType(std::string indice, double val, unsigned char setType = 0x00){//num type initializer
myIndice = indice;
myType = setType;
strval = "";
numval = val;
contents = 0;
};
AMFType(std::string indice, std::string val, unsigned char setType = 0x02){//str type initializer
myIndice = indice;
myType = setType;
strval = val;
numval = 0;
contents = 0;
};
AMFType(std::string indice, unsigned char setType = 0x03){//object type initializer
myIndice = indice;
myType = setType;
strval = "";
numval = 0;
contents = new std::vector<AMFType>;
};
~AMFType(){if (contents != 0){delete contents;contents=0;}};
AMFType& operator=(const AMFType &a) {
myIndice = a.myIndice;
myType = a.myType;
strval = a.strval;
numval = a.numval;
if (contents){
if (a.contents != contents){
delete contents;
if (a.contents){
contents = new std::vector<AMFType>;
for (std::vector<AMFType>::iterator it = a.contents->begin(); it < a.contents->end(); it++){
contents->push_back(*it);
}
}else{
contents = 0;
}
}
}else{
if (a.contents){
contents = new std::vector<AMFType>;
for (std::vector<AMFType>::iterator it = a.contents->begin(); it < a.contents->end(); it++){
contents->push_back(*it);
}
}
}
return *this;
};//= operator
AMFType(const AMFType &a){
myIndice = a.myIndice;
myType = a.myType;
strval = a.strval;
numval = a.numval;
if (a.contents){
contents = new std::vector<AMFType>;
for (std::vector<AMFType>::iterator it = a.contents->begin(); it < a.contents->end(); it++){
contents->push_back(*it);
}
}else{contents = 0;}
};//copy constructor
void Print(std::string indent = ""){
std::cerr << indent;
switch (myType){
case 0x00: std::cerr << "Number"; break;
case 0x01: std::cerr << "Bool"; break;
case 0x02://short string
case 0x0C: std::cerr << "String"; break;
case 0x03: std::cerr << "Object"; break;
case 0x08: std::cerr << "ECMA Array"; break;
case 0x05: std::cerr << "Null"; break;
case 0x06: std::cerr << "Undefined"; break;
case 0x0D: std::cerr << "Unsupported"; break;
case 0xFF: std::cerr << "Container"; break;
}
std::cerr << " " << myIndice << " ";
switch (myType){
case 0x00: case 0x01: std::cerr << numval; break;
case 0x02: case 0x0C: std::cerr << strval; break;
}
std::cerr << std::endl;
if (contents){
for (std::vector<AMFType>::iterator it = contents->begin(); it != contents->end(); it++){it->Print(indent+" ");}
}
};//print
std::string Pack(){
std::string r = "";
if ((myType == 0x02) && (strval.size() > 0xFFFF)){myType = 0x0C;}
if (myType != 0xFF){r += myType;}
switch (myType){
case 0x00://number
r += *(((char*)&numval)+7); r += *(((char*)&numval)+6);
r += *(((char*)&numval)+5); r += *(((char*)&numval)+4);
r += *(((char*)&numval)+3); r += *(((char*)&numval)+2);
r += *(((char*)&numval)+1); r += *(((char*)&numval));
break;
case 0x01://bool
r += (char)numval;
break;
case 0x02://short string
r += strval.size() / 256;
r += strval.size() % 256;
r += strval;
break;
case 0x0C://long string
r += strval.size() / (256*256*256);
r += strval.size() / (256*256);
r += strval.size() / 256;
r += strval.size() % 256;
r += strval;
break;
case 0x03://object
if (contents){
for (std::vector<AMFType>::iterator it = contents->begin(); it != contents->end(); it++){
r += it->Indice().size() / 256;
r += it->Indice().size() % 256;
r += it->Indice();
r += it->Pack();
}
}
r += (char)0; r += (char)0; r += (char)9;
break;
case 0x08:{//array
int arrlen = 0;
if (contents){
arrlen = getContentP("length")->NumValue();
r += arrlen / (256*256*256); r += arrlen / (256*256); r += arrlen / 256; r += arrlen % 256;
for (std::vector<AMFType>::iterator it = contents->begin(); it != contents->end(); it++){
r += it->Indice().size() / 256;
r += it->Indice().size() % 256;
r += it->Indice();
r += it->Pack();
}
}else{
r += (char)0; r += (char)0; r += (char)0; r += (char)0;
}
r += (char)0; r += (char)0; r += (char)9;
} break;
case 0xFF://container - our own type - do not send, only send contents
if (contents){
for (std::vector<AMFType>::iterator it = contents->begin(); it != contents->end(); it++){
r += it->Pack();
}
}
break;
}
return r;
};//pack
protected:
std::string myIndice;
unsigned char myType;
std::string strval;
double numval;
std::vector<AMFType> * contents;
};//AMFType
AMFType parseOneAMF(const unsigned char *& data, unsigned int &len, unsigned int &i, std::string name){
char * helperchar = 0;
std::string tmpstr;
unsigned int tmpi = 0;
unsigned char tmpdbl[8];
switch (data[i]){
case 0x00://number
tmpdbl[7] = data[i+1];
tmpdbl[6] = data[i+2];
tmpdbl[5] = data[i+3];
tmpdbl[4] = data[i+4];
tmpdbl[3] = data[i+5];
tmpdbl[2] = data[i+6];
tmpdbl[1] = data[i+7];
tmpdbl[0] = data[i+8];
i+=9;
return AMFType(name, *(double*)tmpdbl, 0x00);
break;
case 0x01://bool
i+=2;
if (data[i-1] == 0){
return AMFType(name, (double)0, 0x01);
}else{
return AMFType(name, (double)1, 0x01);
}
break;
case 0x0C://long string
tmpi = data[i+1]*256*256*256+data[i+2]*256*256+data[i+3]*256+data[i+4];
helperchar = (char*)malloc(tmpi+1);
memcpy(helperchar, data+i+5, tmpi);
helperchar[tmpi] = 0;
tmpstr = helperchar;
free(helperchar);
i += tmpi + 5;
return AMFType(name, tmpstr, 0x0C);
break;
case 0x02://string
tmpi = data[i+1]*256+data[i+2];
helperchar = (char*)malloc(tmpi+1);
memcpy(helperchar, data+i+3, tmpi);
helperchar[tmpi] = 0;
tmpstr = helperchar;
free(helperchar);
i += tmpi + 3;
return AMFType(name, tmpstr, 0x02);
break;
case 0x05://null
case 0x06://undefined
case 0x0D://unsupported
++i;
return AMFType(name, (double)0, data[i-1]);
break;
case 0x03:{//object
++i;
AMFType ret = AMFType(name, data[i-1]);
while (data[i] + data[i+1] != 0){
tmpi = data[i]*256+data[i+1];
tmpstr = (char*)(data+i+2);
i += tmpi + 2;
ret.addContent(parseOneAMF(data, len, i, tmpstr));
}
i += 3;
return ret;
} break;
case 0x08:{//ECMA array
++i;
AMFType ret = AMFType(name, data[i-1]);
i += 4;
while (data[i] + data[i+1] != 0){
tmpi = data[i]*256+data[i+1];
tmpstr = (char*)(data+i+2);
i += tmpi + 2;
ret.addContent(parseOneAMF(data, len, i, tmpstr));
}
i += 3;
return ret;
} break;
}
#ifdef DEBUG
fprintf(stderr, "Error: Unimplemented AMF type %hhx - returning.\n", data[i]);
#endif
return AMFType("error", (unsigned char)0xFF);
}//parseOneAMF
AMFType parseAMF(const unsigned char * data, unsigned int len){
AMFType ret("returned", (unsigned char)0xFF);//container type
unsigned int i = 0;
while (i < len){ret.addContent(parseOneAMF(data, len, i, ""));}
return ret;
}//parseAMF
AMFType parseAMF(std::string data){return parseAMF((const unsigned char*)data.c_str(), data.size());}

View file

@ -1,501 +0,0 @@
#include <map>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <arpa/inet.h>
unsigned int getNowMS(){
timeval t;
gettimeofday(&t, 0);
return t.tv_sec + t.tv_usec/1000;
}
unsigned int chunk_rec_max = 128;
unsigned int chunk_snd_max = 128;
unsigned int rec_window_size = 0xFA00;
unsigned int snd_window_size = 1024*500;
unsigned int rec_window_at = 0;
unsigned int snd_window_at = 0;
unsigned int rec_cnt = 0;
unsigned int snd_cnt = 0;
unsigned int firsttime;
struct chunkinfo {
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;
};//chunkinfo
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
//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
//ugly global, but who cares...
std::map<unsigned int, chunkinfo> prevmap;
//return previous packet of this cs_id
chunkinfo GetPrev(unsigned int cs_id){
return prevmap[cs_id];
}//GetPrev
//store packet information of last packet of this cs_id
void PutPrev(chunkpack prev){
prevmap[prev.cs_id].timestamp = prev.timestamp;
prevmap[prev.cs_id].len = prev.len;
prevmap[prev.cs_id].real_len = prev.real_len;
prevmap[prev.cs_id].len_left = prev.len_left;
prevmap[prev.cs_id].msg_type_id = prev.msg_type_id;
prevmap[prev.cs_id].msg_stream_id = prev.msg_stream_id;
}//PutPrev
//ugly global, but who cares...
std::map<unsigned int, chunkinfo> sndprevmap;
//return previous packet of this cs_id
chunkinfo GetSndPrev(unsigned int cs_id){
return sndprevmap[cs_id];
}//GetPrev
//store packet information of last packet of this cs_id
void PutSndPrev(chunkpack prev){
sndprevmap[prev.cs_id].cs_id = prev.cs_id;
sndprevmap[prev.cs_id].timestamp = prev.timestamp;
sndprevmap[prev.cs_id].len = prev.len;
sndprevmap[prev.cs_id].real_len = prev.real_len;
sndprevmap[prev.cs_id].len_left = prev.len_left;
sndprevmap[prev.cs_id].msg_type_id = prev.msg_type_id;
sndprevmap[prev.cs_id].msg_stream_id = prev.msg_stream_id;
}//PutPrev
//sends the chunk over the network
void SendChunk(chunkpack ch){
unsigned char tmp;
unsigned int tmpi;
unsigned char chtype = 0x00;
chunkinfo prev = GetSndPrev(ch.cs_id);
ch.timestamp -= firsttime;
if (prev.cs_id == ch.cs_id){
if (ch.msg_stream_id == prev.msg_stream_id){
chtype = 0x40;//do not send msg_stream_id
if (ch.len == prev.len){
if (ch.msg_type_id == prev.msg_type_id){
chtype = 0x80;//do not send len and msg_type_id
if (ch.timestamp == prev.timestamp){
chtype = 0xC0;//do not send timestamp
}
}
}
}
}
if (ch.cs_id <= 63){
tmp = chtype | ch.cs_id; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=1;
}else{
if (ch.cs_id <= 255+64){
tmp = chtype | 0; fwrite(&tmp, 1, 1, stdout);
tmp = ch.cs_id - 64; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=2;
}else{
tmp = chtype | 1; fwrite(&tmp, 1, 1, stdout);
tmpi = ch.cs_id - 64;
tmp = tmpi % 256; fwrite(&tmp, 1, 1, stdout);
tmp = tmpi / 256; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=3;
}
}
unsigned int ntime = 0;
if (chtype != 0xC0){
//timestamp or timestamp diff
if (chtype == 0x00){
tmpi = ch.timestamp;
if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
tmp = tmpi / (256*256); fwrite(&tmp, 1, 1, stdout);
tmp = tmpi / 256; fwrite(&tmp, 1, 1, stdout);
tmp = tmpi % 256; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=3;
}else{
tmpi = ch.timestamp - prev.timestamp;
if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
tmp = tmpi / (256*256); fwrite(&tmp, 1, 1, stdout);
tmp = tmpi / 256; fwrite(&tmp, 1, 1, stdout);
tmp = tmpi % 256; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=3;
}
if (chtype != 0x80){
//len
tmpi = ch.len;
tmp = tmpi / (256*256); fwrite(&tmp, 1, 1, stdout);
tmp = tmpi / 256; fwrite(&tmp, 1, 1, stdout);
tmp = tmpi % 256; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=3;
//msg type id
tmp = ch.msg_type_id; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=1;
if (chtype != 0x40){
//msg stream id
tmp = ch.msg_stream_id % 256; fwrite(&tmp, 1, 1, stdout);
tmp = ch.msg_stream_id / 256; fwrite(&tmp, 1, 1, stdout);
tmp = ch.msg_stream_id / (256*256); fwrite(&tmp, 1, 1, stdout);
tmp = ch.msg_stream_id / (256*256*256); fwrite(&tmp, 1, 1, stdout);
snd_cnt+=4;
}
}
}
//support for 0x00ffffff timestamps
if (ntime){
tmp = ntime / (256*256*256); fwrite(&tmp, 1, 1, stdout);
tmp = ntime / (256*256); fwrite(&tmp, 1, 1, stdout);
tmp = ntime / 256; fwrite(&tmp, 1, 1, stdout);
tmp = ntime % 256; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=4;
}
ch.len_left = 0;
while (ch.len_left < ch.len){
tmpi = ch.len - ch.len_left;
if (tmpi > chunk_snd_max){tmpi = chunk_snd_max;}
fwrite((ch.data + ch.len_left), 1, tmpi, stdout);
snd_cnt+=tmpi;
ch.len_left += tmpi;
if (ch.len_left < ch.len){
if (ch.cs_id <= 63){
tmp = 0xC0 + ch.cs_id; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=1;
}else{
if (ch.cs_id <= 255+64){
tmp = 0xC0; fwrite(&tmp, 1, 1, stdout);
tmp = ch.cs_id - 64; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=2;
}else{
tmp = 0xC1; fwrite(&tmp, 1, 1, stdout);
tmpi = ch.cs_id - 64;
tmp = tmpi % 256; fwrite(&tmp, 1, 1, stdout);
tmp = tmpi / 256; fwrite(&tmp, 1, 1, stdout);
snd_cnt+=4;
}
}
}
}
PutSndPrev(ch);
}//SendChunk
//sends a chunk
void SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data){
chunkpack ch;
ch.cs_id = cs_id;
ch.timestamp = getNowMS();
ch.len = data.size();
ch.real_len = data.size();
ch.len_left = 0;
ch.msg_type_id = msg_type_id;
ch.msg_stream_id = msg_stream_id;
ch.data = (unsigned char*)malloc(data.size());
memcpy(ch.data, data.c_str(), data.size());
SendChunk(ch);
free(ch.data);
}//SendChunk
//sends a media chunk
void SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){
chunkpack ch;
ch.cs_id = msg_type_id;
ch.timestamp = ts;
ch.len = len;
ch.real_len = len;
ch.len_left = 0;
ch.msg_type_id = msg_type_id;
ch.msg_stream_id = 1;
ch.data = (unsigned char*)malloc(len);
memcpy(ch.data, data, len);
SendChunk(ch);
free(ch.data);
}//SendMedia
//sends a control message
void SendCTL(unsigned char type, unsigned int data){
chunkpack ch;
ch.cs_id = 2;
ch.timestamp = getNowMS();
ch.len = 4;
ch.real_len = 4;
ch.len_left = 0;
ch.msg_type_id = type;
ch.msg_stream_id = 0;
ch.data = (unsigned char*)malloc(4);
data = htonl(data);
memcpy(ch.data, &data, 4);
SendChunk(ch);
free(ch.data);
}//SendCTL
//sends a control message
void SendCTL(unsigned char type, unsigned int data, unsigned char data2){
chunkpack ch;
ch.cs_id = 2;
ch.timestamp = getNowMS();
ch.len = 5;
ch.real_len = 5;
ch.len_left = 0;
ch.msg_type_id = type;
ch.msg_stream_id = 0;
ch.data = (unsigned char*)malloc(5);
data = htonl(data);
memcpy(ch.data, &data, 4);
ch.data[4] = data2;
SendChunk(ch);
free(ch.data);
}//SendCTL
//sends a usr control message
void SendUSR(unsigned char type, unsigned int data){
chunkpack ch;
ch.cs_id = 2;
ch.timestamp = getNowMS();
ch.len = 6;
ch.real_len = 6;
ch.len_left = 0;
ch.msg_type_id = 4;
ch.msg_stream_id = 0;
ch.data = (unsigned char*)malloc(6);
data = htonl(data);
memcpy(ch.data+2, &data, 4);
ch.data[0] = 0;
ch.data[1] = type;
SendChunk(ch);
free(ch.data);
}//SendUSR
//sends a usr control message
void SendUSR(unsigned char type, unsigned int data, unsigned int data2){
chunkpack ch;
ch.cs_id = 2;
ch.timestamp = getNowMS();
ch.len = 10;
ch.real_len = 10;
ch.len_left = 0;
ch.msg_type_id = 4;
ch.msg_stream_id = 0;
ch.data = (unsigned char*)malloc(10);
data = htonl(data);
data2 = htonl(data2);
memcpy(ch.data+2, &data, 4);
memcpy(ch.data+6, &data2, 4);
ch.data[0] = 0;
ch.data[1] = type;
SendChunk(ch);
free(ch.data);
}//SendUSR
//get a chunk from standard input
struct chunkpack getChunk(){
gettimeofday(&lastrec, 0);
struct chunkpack ret;
unsigned char temp;
fread(&(ret.chunktype), 1, 1, stdin);
rec_cnt++;
//read the chunkstream ID properly
switch (ret.chunktype & 0x3F){
case 0:
fread(&temp, 1, 1, stdin);
rec_cnt++;
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;
rec_cnt+=2;
break;
default:
ret.cs_id = ret.chunktype & 0x3F;
break;
}
chunkinfo prev = GetPrev(ret.cs_id);
//process the rest of the header, for each chunk type
switch (ret.chunktype & 0xC0){
case 0x00:
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;
fread(&temp, 1, 1, stdin);
ret.msg_stream_id += temp*256;
fread(&temp, 1, 1, stdin);
ret.msg_stream_id += temp*256*256;
fread(&temp, 1, 1, stdin);
ret.msg_stream_id += temp*256*256*256;
rec_cnt+=11;
break;
case 0x40:
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;
rec_cnt+=7;
break;
case 0x80:
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;
rec_cnt+=3;
break;
case 0xC0:
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;
}
//calculate chunk length, real length, and length left till complete
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;
ret.real_len = chunk_rec_max;
}
//read extended timestamp, if neccesary
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;
rec_cnt+=4;
}
//read data if length > 0, and allocate it
if (ret.real_len > 0){
ret.data = (unsigned char*)malloc(ret.real_len);
fread(ret.data, 1, ret.real_len, stdin);
rec_cnt+=ret.real_len;
}else{
ret.data = 0;
}
PutPrev(ret);
return ret;
}//getChunk
//adds newchunk to global list of unfinished chunks, re-assembling them complete
//returns pointer to chunk when a chunk is finished, 0 otherwise
//removes pointed to chunk from internal list if returned, without cleanup
// (cleanup performed in getWholeChunk function)
chunkpack * AddChunkPart(chunkpack newchunk){
chunkpack * p;
unsigned char * tmpdata = 0;
static std::map<unsigned int, chunkpack *> ch_lst;
std::map<unsigned int, chunkpack *>::iterator it;
it = ch_lst.find(newchunk.cs_id);
if (it == ch_lst.end()){
p = (chunkpack*)malloc(sizeof(chunkpack));
*p = newchunk;
p->data = (unsigned char*)malloc(p->real_len);
memcpy(p->data, newchunk.data, p->real_len);
if (p->len_left == 0){return p;}
ch_lst[newchunk.cs_id] = p;
}else{
p = it->second;
tmpdata = (unsigned char*)realloc(p->data, p->real_len + newchunk.real_len);
if (tmpdata == 0){
#ifdef DEBUG
fprintf(stderr, "Error allocating memory!\n");
#endif
return 0;
}
p->data = tmpdata;
memcpy(p->data+p->real_len, newchunk.data, newchunk.real_len);
p->real_len += newchunk.real_len;
p->len_left -= newchunk.real_len;
if (p->len_left <= 0){
ch_lst.erase(it);
return p;
}else{
ch_lst[newchunk.cs_id] = p;//pointer may have changed
}
}
return 0;
}//AddChunkPart
//grabs chunks until a whole one comes in, then returns that
chunkpack getWholeChunk(){
static chunkpack gwc_next, gwc_complete;
static bool clean = false;
int counter = 0;
if (!clean){gwc_complete.data = 0; clean = true;}//prevent brain damage
chunkpack * ret = 0;
scrubChunk(gwc_complete);
while (counter < 10000){
gwc_next = getChunk();
ret = AddChunkPart(gwc_next);
scrubChunk(gwc_next);
if (ret){
gwc_complete = *ret;
free(ret);//cleanup returned chunk
return gwc_complete;
}
if (feof(stdin) != 0){break;}
counter++;
}
gwc_complete.msg_type_id = 0;
return gwc_complete;
}//getWholeChunk

View file

@ -1,506 +0,0 @@
#define STR(x) (((std::string)(x)).c_str())
#include "crypto.h"
#define P768 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
#define P1024 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
"FFFFFFFFFFFFFFFF"
#define Q1024 \
"7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" \
"948127044533E63A0105DF531D89CD9128A5043CC71A026E" \
"F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" \
"F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" \
"F71C35FDAD44CFD2D74F9208BE258FF324943328F67329C0" \
"FFFFFFFFFFFFFFFF"
#define P1536 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
#define P2048 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
#define P3072 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
"43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
#define P4096 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \
"FFFFFFFFFFFFFFFF"
#define P6144 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \
"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \
"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \
"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \
"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \
"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \
"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \
"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \
"12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF"
#define P8192 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" \
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" \
"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" \
"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" \
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" \
"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" \
"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" \
"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" \
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" \
"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" \
"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" \
"12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" \
"38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" \
"741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" \
"3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" \
"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" \
"4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" \
"062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" \
"4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" \
"B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" \
"4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" \
"9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" \
"60C980DD98EDD3DFFFFFFFFFFFFFFFFF"
uint8_t genuineFMSKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20,
0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c,
0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69,
0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001
0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8,
0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 68
uint8_t genuineFPKey[] = {
0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20,
0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x46, 0x6C,
0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79,
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Player 001
0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8,
0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57,
0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB,
0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
}; // 62
void replace(std::string &target, std::string search, std::string replacement) {
if (search == replacement)
return;
if (search == "")
return;
std::string::size_type i = std::string::npos;
while ((i = target.find(search)) != std::string::npos) {
target.replace(i, search.length(), replacement);
}
}
DHWrapper::DHWrapper(int32_t bitsCount) {
_bitsCount = bitsCount;
_pDH = NULL;
_pSharedKey = NULL;
_sharedKeyLength = 0;
_peerPublickey = NULL;
}
DHWrapper::~DHWrapper() {
Cleanup();
}
bool DHWrapper::Initialize() {
Cleanup();
//1. Create the DH
_pDH = DH_new();
if (_pDH == NULL) {
Cleanup();
return false;
}
//2. Create his internal p and g
_pDH->p = BN_new();
if (_pDH->p == NULL) {
Cleanup();
return false;
}
_pDH->g = BN_new();
if (_pDH->g == NULL) {
Cleanup();
return false;
}
//3. initialize p, g and key length
if (BN_hex2bn(&_pDH->p, P1024) == 0) {
Cleanup();
return false;
}
if (BN_set_word(_pDH->g, 2) != 1) {
Cleanup();
return false;
}
//4. Set the key length
_pDH->length = _bitsCount;
//5. Generate private and public key
if (DH_generate_key(_pDH) != 1) {
Cleanup();
return false;
}
return true;
}
bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength) {
if (_pDH == NULL) {
return false;
}
return CopyKey(_pDH->pub_key, pDst, dstLength);
}
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength) {
if (_pDH == NULL) {
return false;
}
return CopyKey(_pDH->priv_key, pDst, dstLength);
}
bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length) {
if (_pDH == NULL) {
return false;
}
if (_sharedKeyLength != 0 || _pSharedKey != NULL) {
return false;
}
_sharedKeyLength = DH_size(_pDH);
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024) {
return false;
}
_pSharedKey = new uint8_t[_sharedKeyLength];
_peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0);
if (_peerPublickey == NULL) {
return false;
}
if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength) {
return false;
}
return true;
}
bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength) {
if (_pDH == NULL) {
return false;
}
if (dstLength != _sharedKeyLength) {
return false;
}
memcpy(pDst, _pSharedKey, _sharedKeyLength);
return true;
}
void DHWrapper::Cleanup() {
if (_pDH != NULL) {
if (_pDH->p != NULL) {
BN_free(_pDH->p);
_pDH->p = NULL;
}
if (_pDH->g != NULL) {
BN_free(_pDH->g);
_pDH->g = NULL;
}
DH_free(_pDH);
_pDH = NULL;
}
if (_pSharedKey != NULL) {
delete[] _pSharedKey;
_pSharedKey = NULL;
}
_sharedKeyLength = 0;
if (_peerPublickey != NULL) {
BN_free(_peerPublickey);
_peerPublickey = NULL;
}
}
bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength) {
int32_t keySize = BN_num_bytes(pNum);
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)) {
return false;
}
if (BN_bn2bin(pNum, pDst) != keySize) {
return false;
}
return true;
}
void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut) {
uint8_t digest[SHA256_DIGEST_LENGTH];
unsigned int digestLen = 0;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
HMAC_Update(&ctx, pubKeyIn, 128);
HMAC_Final(&ctx, digest, &digestLen);
HMAC_CTX_cleanup(&ctx);
RC4_set_key(rc4keyOut, 16, digest);
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
HMAC_Update(&ctx, pubKeyOut, 128);
HMAC_Final(&ctx, digest, &digestLen);
HMAC_CTX_cleanup(&ctx);
RC4_set_key(rc4keyIn, 16, digest);
}
std::string md5(std::string source, bool textResult) {
EVP_MD_CTX mdctx;
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len;
EVP_DigestInit(&mdctx, EVP_md5());
EVP_DigestUpdate(&mdctx, STR(source), source.length());
EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(&mdctx);
if (textResult) {
std::string result = "";
char tmp[3];
for (uint32_t i = 0; i < md_len; i++) {
sprintf(tmp, "%02x", md_value[i]);
result += tmp;
}
return result;
} else {
return std::string((char *) md_value, md_len);
}
}
std::string b64(std::string source) {
return b64((uint8_t *) STR(source), source.size());
}
std::string b64(uint8_t *pBuffer, uint32_t length) {
BIO *bmem;
BIO *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, pBuffer, length);
std::string result = "";
if (BIO_flush(b64) == 1) {
BIO_get_mem_ptr(b64, &bptr);
result = std::string(bptr->data, bptr->length);
}
BIO_free_all(b64);
replace(result, "\n", "");
replace(result, "\r", "");
return result;
}
std::string unb64(std::string source) {
return unb64((uint8_t *)STR(source),source.length());
}
std::string unb64(uint8_t *pBuffer, uint32_t length){
// create a memory buffer containing base64 encoded data
//BIO* bmem = BIO_new_mem_buf((void*) STR(source), source.length());
BIO* bmem = BIO_new_mem_buf((void *)pBuffer, length);
// push a Base64 filter so that reading from buffer decodes it
BIO *bioCmd = BIO_new(BIO_f_base64());
// we don't want newlines
BIO_set_flags(bioCmd, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_push(bioCmd, bmem);
char *pOut = new char[length];
int finalLen = BIO_read(bmem, (void*) pOut, length);
BIO_free_all(bmem);
std::string result(pOut, finalLen);
delete[] pOut;
return result;
}
void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult) {
unsigned int digestLen;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, (unsigned char*) pKey, keyLength, EVP_sha256(), NULL);
HMAC_Update(&ctx, (unsigned char *) pData, dataLength);
HMAC_Final(&ctx, (unsigned char *) pResult, &digestLen);
HMAC_CTX_cleanup(&ctx);
}
uint32_t GetDigestOffset0(uint8_t *pBuffer) {
uint32_t offset = pBuffer[8] + pBuffer[9] + pBuffer[10] + pBuffer[11];
return (offset % 728) + 12;
}
uint32_t GetDigestOffset1(uint8_t *pBuffer) {
uint32_t offset = pBuffer[772] + pBuffer[773] + pBuffer[774] + pBuffer[775];
return (offset % 728) + 776;
}
uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){
if (scheme == 0){return GetDigestOffset0(pBuffer);}else{return GetDigestOffset1(pBuffer);}
}
uint32_t GetDHOffset0(uint8_t *pBuffer) {
uint32_t offset = pBuffer[1532] + pBuffer[1533] + pBuffer[1534] + pBuffer[1535];
return (offset % 632) + 772;
}
uint32_t GetDHOffset1(uint8_t *pBuffer) {
uint32_t offset = pBuffer[768] + pBuffer[769] + pBuffer[770] + pBuffer[771];
return (offset % 632) + 8;
}
uint32_t GetDHOffset(uint8_t *pBuffer, uint8_t scheme){
if (scheme == 0){return GetDHOffset0(pBuffer);}else{return GetDHOffset1(pBuffer);}
}
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) {
uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);
uint8_t *pTempBuffer = new uint8_t[1536 - 32];
memcpy(pTempBuffer, pBuffer, clientDigestOffset);
memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32);
uint8_t *pTempHash = new uint8_t[512];
HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
bool result = (memcmp(pBuffer+clientDigestOffset, pTempHash, 32) == 0);
#ifdef DEBUG
fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed");
#endif
delete[] pTempBuffer;
delete[] pTempHash;
return result;
}

View file

@ -1,45 +0,0 @@
#ifndef _CRYPTO_H
#define _CRYPTO_H
#define DLLEXP
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/rc4.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/hmac.h>
class DLLEXP DHWrapper {
private:
int32_t _bitsCount;
DH *_pDH;
uint8_t *_pSharedKey;
int32_t _sharedKeyLength;
BIGNUM *_peerPublickey;
public:
DHWrapper(int32_t bitsCount);
virtual ~DHWrapper();
bool Initialize();
bool CopyPublicKey(uint8_t *pDst, int32_t dstLength);
bool CopyPrivateKey(uint8_t *pDst, int32_t dstLength);
bool CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length);
bool CopySharedKey(uint8_t *pDst, int32_t dstLength);
private:
void Cleanup();
bool CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength);
};
DLLEXP void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut,
RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut);
DLLEXP std::string md5(std::string source, bool textResult);
DLLEXP std::string b64(std::string source);
DLLEXP std::string b64(uint8_t *pBuffer, uint32_t length);
DLLEXP std::string unb64(std::string source);
DLLEXP std::string unb64(uint8_t *pBuffer, uint32_t length);
#endif /* _CRYPTO_H */

View file

@ -1,30 +0,0 @@
SWBaseSocket::SWBaseError SWBerr;
char * FLVbuffer;
int FLV_len;
int FLVbs = 0;
void FLV_Readheader(SWUnixSocket & ss){
static char header[13];
while (ss.frecv(header, 13, &SWBerr) != 13){
//wait
}
}//FLV_Readheader
void FLV_Dump(){FLV_len = 0;}
bool FLV_GetPacket(SWUnixSocket & ss){
if (FLVbs < 15){FLVbuffer = (char*)realloc(FLVbuffer, 15); FLVbs = 15;}
//if received a whole header, receive a whole packet
//if not, retry header next pass
if (FLV_len == 0){
if (ss.frecv(FLVbuffer, 11, &SWBerr) == 11){
FLV_len = FLVbuffer[3] + 15;
FLV_len += (FLVbuffer[2] << 8);
FLV_len += (FLVbuffer[1] << 16);
if (FLVbs < FLV_len){FLVbuffer = (char*)realloc(FLVbuffer, FLV_len);FLVbs = FLV_len;}
}
}else{
if (ss.frecv(FLVbuffer+11, FLV_len-11, &SWBerr) == FLV_len-11){return true;}
}
return false;
}//FLV_GetPacket

View file

@ -1,137 +0,0 @@
#undef OLDHANDSHAKE //change to #define for old handshake method
char versionstring[] = "PLSRTMPServer";
#ifdef OLDHANDSHAKE
struct Handshake {
char Time[4];
char Zero[4];
char Random[1528];
};//Handshake
bool doHandshake(){
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);
rec_cnt+=1537;
/** 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] = versionstring[i%13];
}
/** 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);
snd_cnt+=1537;
/** Send S2 **/
fwrite(Client.Time, 1, 4, stdout);
fwrite(Client.Time, 1, 4, stdout);
fwrite(Client.Random, 1, 1528, stdout);
snd_cnt+=1536;
/** 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);
rec_cnt+=1536;
return true;
}//doHandshake
#else
#include "crypto.cpp" //cryptography for handshaking
bool doHandshake(){
char Version;
/** Read C0 **/
fread(&Version, 1, 1, stdin);
uint8_t Client[1536];
uint8_t Server[3072];
fread(&Client, 1, 1536, stdin);
rec_cnt+=1537;
/** Build S1 Packet **/
*((uint32_t*)Server) = 0;//time zero
*(((uint32_t*)(Server+4))) = htonl(0x01020304);//version 1 2 3 4
for (int i = 8; i < 3072; ++i){Server[i] = versionstring[i%13];}//"random" data
bool encrypted = (Version == 6);
#ifdef DEBUG
fprintf(stderr, "Handshake version is %hhi\n", Version);
#endif
uint8_t _validationScheme = 5;
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
#ifdef DEBUG
fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off");
#endif
//**** FIRST 1536 bytes from server response ****//
//compute DH key position
uint32_t serverDHOffset = GetDHOffset(Server, _validationScheme);
uint32_t clientDHOffset = GetDHOffset(Client, _validationScheme);
//generate DH key
DHWrapper dhWrapper(1024);
if (!dhWrapper.Initialize()) return false;
if (!dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) return false;
if (!dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) return false;
if (encrypted) {
uint8_t secretKey[128];
if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) return false;
RC4_KEY _pKeyIn;
RC4_KEY _pKeyOut;
InitRC4Encryption(secretKey, (uint8_t*) & Client[clientDHOffset], (uint8_t*) & Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
uint8_t data[1536];
RC4(&_pKeyIn, 1536, data, data);
RC4(&_pKeyOut, 1536, data, data);
}
//generate the digest
uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme);
uint8_t *pTempBuffer = new uint8_t[1536 - 32];
memcpy(pTempBuffer, Server, serverDigestOffset);
memcpy(pTempBuffer + serverDigestOffset, Server + serverDigestOffset + 32, 1536 - serverDigestOffset - 32);
uint8_t *pTempHash = new uint8_t[512];
HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash);
memcpy(Server + serverDigestOffset, pTempHash, 32);
delete[] pTempBuffer;
delete[] pTempHash;
//**** SECOND 1536 bytes from server response ****//
uint32_t keyChallengeIndex = GetDigestOffset(Client, _validationScheme);
pTempHash = new uint8_t[512];
HMACsha256(Client + keyChallengeIndex, 32, genuineFMSKey, 68, pTempHash);
uint8_t *pLastHash = new uint8_t[512];
HMACsha256(Server + 1536, 1536 - 32, pTempHash, 32, pLastHash);
memcpy(Server + 1536 * 2 - 32, pLastHash, 32);
delete[] pTempHash;
delete[] pLastHash;
//***** DONE BUILDING THE RESPONSE ***//
/** Send response **/
fwrite(&Version, 1, 1, stdout);
fwrite(&Server, 1, 3072, stdout);
snd_cnt+=3073;
/** Flush, necessary in order to work **/
fflush(stdout);
/** Read and discard C2 **/
fread(Client, 1, 1536, stdin);
rec_cnt+=1536;
return true;
}
#endif

View file

@ -1,119 +0,0 @@
#undef DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
//needed for select
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
//for connection to server
#include "../sockets/SocketW.h"
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking
#include "flv_sock.cpp" //FLV parsing with SocketW
int main(){
unsigned int ts;
unsigned int fts = 0;
unsigned int ftst;
SWUnixSocket ss;
fd_set pollset;
struct timeval timeout;
//0 timeout - return immediately after select call
timeout.tv_sec = 1; timeout.tv_usec = 0;
FD_ZERO(&pollset);//clear the polling set
FD_SET(0, &pollset);//add stdin to polling set
//first timestamp set
firsttime = getNowMS();
#ifdef DEBUG
fprintf(stderr, "Doing handshake...\n");
#endif
if (doHandshake()){
#ifdef DEBUG
fprintf(stderr, "Handshake succcess!\n");
#endif
}else{
#ifdef DEBUG
fprintf(stderr, "Handshake fail!\n");
#endif
return 0;
}
#ifdef DEBUG
fprintf(stderr, "Starting processing...\n");
#endif
while (std::cin.good() && std::cout.good()){
//select(1, &pollset, 0, 0, &timeout);
//only parse input from stdin if available or not yet init'ed
//FD_ISSET(0, &pollset) || //NOTE: Polling does not work? WHY?!? WHY DAMN IT?!?
if ((!ready4data || (snd_cnt - snd_window_at >= snd_window_size)) && !stopparsing){parseChunk();fflush(stdout);}
if (ready4data){
if (!inited){
//we are ready, connect the socket!
if (!ss.connect(streamname.c_str())){
#ifdef DEBUG
fprintf(stderr, "Could not connect to server!\n");
#endif
return 0;
}
FLV_Readheader(ss);//read the header, we don't want it
#ifdef DEBUG
fprintf(stderr, "Header read, starting to send video data...\n");
#endif
inited = true;
}
//only send data if previous data has been ACK'ed...
if (snd_cnt - snd_window_at < snd_window_size){
if (FLV_GetPacket(ss)){//able to read a full packet?
ts = FLVbuffer[7] * 256*256*256;
ts += FLVbuffer[4] * 256*256;
ts += FLVbuffer[5] * 256;
ts += FLVbuffer[6];
if (ts != 0){
if (fts == 0){fts = ts;ftst = getNowMS();}
ts -= fts;
FLVbuffer[7] = ts / (256*256*256);
FLVbuffer[4] = ts / (256*256);
FLVbuffer[5] = ts / 256;
FLVbuffer[6] = ts % 256;
ts += ftst;
}else{
ftst = getNowMS();
FLVbuffer[7] = ftst / (256*256*256);
FLVbuffer[4] = ftst / (256*256);
FLVbuffer[5] = ftst / 256;
FLVbuffer[6] = ftst % 256;
}
SendMedia((unsigned char)FLVbuffer[0], (unsigned char *)FLVbuffer+11, FLV_len-15, ts);
FLV_Dump();//dump packet and get ready for next
}
if ((SWBerr != SWBaseSocket::ok) && (SWBerr != SWBaseSocket::notReady)){
#ifdef DEBUG
fprintf(stderr, "No more data! :-( (%s)\n", SWBerr.get_error().c_str());
#endif
return 0;//no more input possible! Fail immediately.
}
}
}
//send ACK if we received a whole window
if (rec_cnt - rec_window_at > rec_window_size){
rec_window_at = rec_cnt;
SendCTL(3, rec_cnt);//send ack (msg 3)
}
}
#ifdef DEBUG
fprintf(stderr, "User disconnected.\n");
#endif
return 0;
}//main

View file

@ -1,246 +0,0 @@
#include "chunkstream.cpp" //chunkstream decoding
#include "amf.cpp" //simple AMF0 parsing
std::string streamname = "/tmp/shared_socket";
//gets and parses one chunk
void parseChunk(){
static chunkpack next;
static AMFType amfdata("empty", (unsigned char)0xFF);
static AMFType amfelem("empty", (unsigned char)0xFF);
next = getWholeChunk();
switch (next.msg_type_id){
case 0://does not exist
break;//happens when connection breaks unexpectedly
case 1://set chunk size
chunk_rec_max = ntohl(*(int*)next.data);
#ifdef DEBUG
fprintf(stderr, "CTRL: Set chunk size: %i\n", chunk_rec_max);
#endif
break;
case 2://abort message - we ignore this one
#ifdef DEBUG
fprintf(stderr, "CTRL: Abort message\n");
#endif
//4 bytes of stream id to drop
break;
case 3://ack
#ifdef DEBUG
fprintf(stderr, "CTRL: Acknowledgement\n");
#endif
snd_window_at = ntohl(*(int*)next.data);
snd_window_at = snd_cnt;
break;
case 4:{
#ifdef DEBUG
short int ucmtype = ntohs(*(short int*)next.data);
fprintf(stderr, "CTRL: User control message %hi\n", ucmtype);
#endif
//2 bytes event type, rest = event data
//types:
//0 = stream begin, 4 bytes ID
//1 = stream EOF, 4 bytes ID
//2 = stream dry, 4 bytes ID
//3 = setbufferlen, 4 bytes ID, 4 bytes length
//4 = streamisrecorded, 4 bytes ID
//6 = pingrequest, 4 bytes data
//7 = pingresponse, 4 bytes data
//we don't need to process this
} break;
case 5://window size of other end
#ifdef DEBUG
fprintf(stderr, "CTRL: Window size\n");
#endif
rec_window_size = ntohl(*(int*)next.data);
rec_window_at = rec_cnt;
SendCTL(3, rec_cnt);//send ack (msg 3)
break;
case 6:
#ifdef DEBUG
fprintf(stderr, "CTRL: Set peer bandwidth\n");
#endif
//4 bytes window size, 1 byte limit type (ignored)
snd_window_size = ntohl(*(int*)next.data);
SendCTL(5, snd_window_size);//send window acknowledgement size (msg 5)
break;
case 8:
#ifdef DEBUG
fprintf(stderr, "Received audio data\n");
#endif
break;
case 9:
#ifdef DEBUG
fprintf(stderr, "Received video data\n");
#endif
break;
case 15:
#ifdef DEBUG
fprintf(stderr, "Received AFM3 data message\n");
#endif
break;
case 16:
#ifdef DEBUG
fprintf(stderr, "Received AFM3 shared object\n");
#endif
break;
case 17:
#ifdef DEBUG
fprintf(stderr, "Received AFM3 command message\n");
#endif
break;
case 18:
#ifdef DEBUG
fprintf(stderr, "Received AFM0 data message\n");
#endif
break;
case 19:
#ifdef DEBUG
fprintf(stderr, "Received AFM0 shared object\n");
#endif
break;
case 20:{//AMF0 command message
bool parsed = false;
amfdata = parseAMF(next.data, next.real_len);
#ifdef DEBUG
fprintf(stderr, "Received AFM0 command message:\n");
amfdata.Print();
#endif
if (amfdata.getContentP(0)->StrValue() == "connect"){
#ifdef DEBUG
int tmpint;
tmpint = amfdata.getContentP(2)->getContentP("videoCodecs")->NumValue();
if (tmpint & 0x04){fprintf(stderr, "Sorensen video support detected\n");}
if (tmpint & 0x80){fprintf(stderr, "H264 video support detected\n");}
tmpint = amfdata.getContentP(2)->getContentP("audioCodecs")->NumValue();
if (tmpint & 0x04){fprintf(stderr, "MP3 audio support detected\n");}
if (tmpint & 0x400){fprintf(stderr, "AAC video support detected\n");}
#endif
SendCTL(6, rec_window_size, 0);//send peer bandwidth (msg 6)
SendCTL(5, snd_window_size);//send window acknowledgement size (msg 5)
SendUSR(0, 0);//send UCM StreamBegin (0), stream 0
//send a _result reply
AMFType amfreply("container", (unsigned char)0xFF);
amfreply.addContent(AMFType("", "_result"));//result success
amfreply.addContent(amfdata.getContent(1));//same transaction ID
// amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType(""));//server properties
amfreply.getContentP(2)->addContent(AMFType("fmsVer", "FMS/3,0,1,123"));//stolen from examples
amfreply.getContentP(2)->addContent(AMFType("capabilities", (double)31));//stolen from examples
amfreply.addContent(AMFType(""));//info
amfreply.getContentP(3)->addContent(AMFType("level", "status"));
amfreply.getContentP(3)->addContent(AMFType("code", "NetConnection.Connect.Success"));
amfreply.getContentP(3)->addContent(AMFType("description", "Connection succeeded."));
amfreply.getContentP(3)->addContent(AMFType("capabilities", (double)33));//from red5 server
amfreply.getContentP(3)->addContent(AMFType("fmsVer", "PLS/1,0,0,0"));//from red5 server
SendChunk(3, 20, next.msg_stream_id, amfreply.Pack());
//send onBWDone packet
//amfreply = AMFType("container", (unsigned char)0xFF);
//amfreply.addContent(AMFType("", "onBWDone"));//result success
//amfreply.addContent(AMFType("", (double)0));//zero
//amfreply.addContent(AMFType("", (double)0, 0x05));//null
//SendChunk(3, 20, next.msg_stream_id, amfreply.Pack());
parsed = true;
}//connect
if (amfdata.getContentP(0)->StrValue() == "createStream"){
//send a _result reply
AMFType amfreply("container", (unsigned char)0xFF);
amfreply.addContent(AMFType("", "_result"));//result success
amfreply.addContent(amfdata.getContent(1));//same transaction ID
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType("", (double)1));//stream ID - we use 1
SendChunk(3, 20, next.msg_stream_id, amfreply.Pack());
SendUSR(0, 0);//send UCM StreamBegin (0), stream 0
#ifdef DEBUG
fprintf(stderr, "AMF0 command: createStream result\n");
#endif
parsed = true;
}//createStream
if ((amfdata.getContentP(0)->StrValue() == "getStreamLength") || (amfdata.getContentP(0)->StrValue() == "getMovLen")){
//send a _result reply
AMFType amfreply("container", (unsigned char)0xFF);
amfreply.addContent(AMFType("", "_result"));//result success
amfreply.addContent(amfdata.getContent(1));//same transaction ID
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType("", (double)0));//zero length
SendChunk(3, 20, next.msg_stream_id, amfreply.Pack());
#ifdef DEBUG
fprintf(stderr, "AMF0 command: getStreamLength result\n");
#endif
parsed = true;
}//getStreamLength
if (amfdata.getContentP(0)->StrValue() == "checkBandwidth"){
//send a _result reply
AMFType amfreply("container", (unsigned char)0xFF);
amfreply.addContent(AMFType("", "_result"));//result success
amfreply.addContent(amfdata.getContent(1));//same transaction ID
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
SendChunk(3, 20, 1, amfreply.Pack());
#ifdef DEBUG
fprintf(stderr, "AMF0 command: checkBandwidth result\n");
#endif
parsed = true;
}//checkBandwidth
if ((amfdata.getContentP(0)->StrValue() == "play") || (amfdata.getContentP(0)->StrValue() == "play2")){
//send streambegin
streamname = amfdata.getContentP(3)->StrValue();
for (std::string::iterator i=streamname.end()-1; i>=streamname.begin(); --i){
if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);}
}
streamname = "/tmp/shared_socket_" + streamname;
SendUSR(0, 1);//send UCM StreamBegin (0), stream 1
//send a status reply
AMFType amfreply("container", (unsigned char)0xFF);
amfreply.addContent(AMFType("", "onStatus"));//status reply
amfreply.addContent(amfdata.getContent(1));//same transaction ID
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType(""));//info
amfreply.getContentP(3)->addContent(AMFType("level", "status"));
amfreply.getContentP(3)->addContent(AMFType("code", "NetStream.Play.Reset"));
amfreply.getContentP(3)->addContent(AMFType("description", "Playing and resetting..."));
amfreply.getContentP(3)->addContent(AMFType("details", "PLS"));
amfreply.getContentP(3)->addContent(AMFType("clientid", (double)1));
SendChunk(4, 20, next.msg_stream_id, amfreply.Pack());
amfreply = AMFType("container", (unsigned char)0xFF);
amfreply.addContent(AMFType("", "onStatus"));//status reply
amfreply.addContent(amfdata.getContent(1));//same transaction ID
amfreply.addContent(AMFType("", (double)0, 0x05));//null - command info
amfreply.addContent(AMFType(""));//info
amfreply.getContentP(3)->addContent(AMFType("level", "status"));
amfreply.getContentP(3)->addContent(AMFType("code", "NetStream.Play.Start"));
amfreply.getContentP(3)->addContent(AMFType("description", "Playing!"));
amfreply.getContentP(3)->addContent(AMFType("details", "PLS"));
amfreply.getContentP(3)->addContent(AMFType("clientid", (double)1));
SendChunk(4, 20, 1, amfreply.Pack());
//No clue what this does. Most real servers send it, though...
// amfreply = AMFType("container", (unsigned char)0xFF);
// amfreply.addContent(AMFType("", "|RtmpSampleAccess"));//status reply
// amfreply.addContent(AMFType("", (double)1, 0x01));//bool true - audioaccess
// amfreply.addContent(AMFType("", (double)1, 0x01));//bool true - videoaccess
// SendChunk(4, 20, next.msg_stream_id, amfreply.Pack());
chunk_snd_max = 1024*1024;
SendCTL(1, chunk_snd_max);//send chunk size max (msg 1)
ready4data = true;//start sending video data!
#ifdef DEBUG
fprintf(stderr, "AMF0 command: play result (%s)\n", streamname.c_str());
#endif
parsed = true;
}//createStream
if (!parsed){
#ifdef DEBUG
fprintf(stderr, "AMF0 command not processed! :(\n");
#endif
}
} break;
case 22:
#ifdef DEBUG
fprintf(stderr, "Received aggregate message\n");
#endif
break;
default:
#ifdef DEBUG
fprintf(stderr, "Unknown chunk received! Probably protocol corruption, stopping parsing of incoming data.\n");
#endif
stopparsing = true;
break;
}
}//parseChunk

View file

@ -3,14 +3,12 @@ default: client-install
client: client:
cd Connector_HTTP; $(MAKE) cd Connector_HTTP; $(MAKE)
cd Connector_RTMP; $(MAKE) cd Connector_RTMP; $(MAKE)
cd Connector_RTMPf; $(MAKE)
cd Connector_RAW; $(MAKE) cd Connector_RAW; $(MAKE)
#cd Connector_RTSP; $(MAKE) #cd Connector_RTSP; $(MAKE)
cd Buffer; $(MAKE) cd Buffer; $(MAKE)
client-clean: client-clean:
cd Connector_HTTP; $(MAKE) clean cd Connector_HTTP; $(MAKE) clean
cd Connector_RTMP; $(MAKE) clean cd Connector_RTMP; $(MAKE) clean
cd Connector_RTMPf; $(MAKE) clean
cd Connector_RAW; $(MAKE) clean cd Connector_RAW; $(MAKE) clean
#cd Connector_RTSP; $(MAKE) clean #cd Connector_RTSP; $(MAKE) clean
cd Buffer; $(MAKE) clean cd Buffer; $(MAKE) clean
@ -20,7 +18,6 @@ client-install: client-clean client
cp -f ./Connector_HTTP/Connector_HTTP /usr/bin/ cp -f ./Connector_HTTP/Connector_HTTP /usr/bin/
cd Connector_RTMP; $(MAKE) install cd Connector_RTMP; $(MAKE) install
cp -f ./Connector_RAW/Connector_RAW /usr/bin/ cp -f ./Connector_RAW/Connector_RAW /usr/bin/
cp -f ./Connector_RTMPf/Connector_RTMPf /usr/bin/
#cp -f ./Connector_RTSP/Connector_RTSP /usr/bin/ #cp -f ./Connector_RTSP/Connector_RTSP /usr/bin/
cp -f ./Buffer/Buffer /usr/bin/ cp -f ./Buffer/Buffer /usr/bin/
cp -f ./PLS /etc/xinetd.d/ cp -f ./PLS /etc/xinetd.d/

15
PLS
View file

@ -25,18 +25,3 @@ service ddvtechraw
per_source = 10 per_source = 10
cps = 100 5 cps = 100 5
} }
service ddvtechrtmp
{
disable = no
type = UNLISTED
protocol = tcp
socket_type = stream
user = root
server = /usr/bin/Connector_RTMPf
port = 1935
wait = no
per_source = 10
cps = 100 5
}

View file

@ -46,12 +46,12 @@ int DDV_Listen(int port){
if (ret == 0){ if (ret == 0){
return s; return s;
}else{ }else{
printf("Listen failed! Error: %s\n", strerror(errno)); fprintf(stderr, "Listen failed! Error: %s\n", strerror(errno));
close(s); close(s);
return 0; return 0;
} }
}else{ }else{
printf("Binding failed! Error: %s\n", strerror(errno)); fprintf(stderr, "Binding failed! Error: %s\n", strerror(errno));
close(s); close(s);
return 0; return 0;
} }
@ -77,7 +77,7 @@ bool DDV_write(void * buffer, int todo, int sock){
case EWOULDBLOCK: socketBlocking = true; break; case EWOULDBLOCK: socketBlocking = true; break;
default: default:
socketError = true; socketError = true;
printf("Could not write! %s\n", strerror(errno)); fprintf(stderr, "Could not write! %s\n", strerror(errno));
return false; return false;
break; break;
} }
@ -87,14 +87,14 @@ bool DDV_write(void * buffer, int todo, int sock){
return true; return true;
} }
bool DDV_ready(int sock){ signed int DDV_ready(int sock){
char tmp; char tmp;
int preflags = fcntl(sock, F_GETFL, 0); int preflags = fcntl(sock, F_GETFL, 0);
int postflags = preflags | O_NONBLOCK; int postflags = preflags | O_NONBLOCK;
fcntl(sock, F_SETFL, postflags); fcntl(sock, F_SETFL, postflags);
int r = recv(sock, &tmp, 1, MSG_PEEK); int r = recv(sock, &tmp, 1, MSG_PEEK);
fcntl(sock, F_SETFL, preflags); fcntl(sock, F_SETFL, preflags);
return (r == 1); return r;
} }
bool DDV_read(void * buffer, int todo, int sock){ bool DDV_read(void * buffer, int todo, int sock){
@ -107,7 +107,7 @@ bool DDV_read(void * buffer, int todo, int sock){
case EWOULDBLOCK: socketBlocking = true; break; case EWOULDBLOCK: socketBlocking = true; break;
default: default:
socketError = true; socketError = true;
printf("Could not read! %s\n", strerror(errno)); fprintf(stderr, "Could not read! %s\n", strerror(errno));
return false; return false;
break; break;
} }
@ -129,7 +129,7 @@ int DDV_iwrite(void * buffer, int todo, int sock){
case EWOULDBLOCK: break; case EWOULDBLOCK: break;
default: default:
socketError = true; socketError = true;
printf("Could not write! %s\n", strerror(errno)); fprintf(stderr, "Could not write! %s\n", strerror(errno));
return false; return false;
break; break;
} }
@ -144,7 +144,7 @@ int DDV_iread(void * buffer, int todo, int sock){
case EWOULDBLOCK: break; case EWOULDBLOCK: break;
default: default:
socketError = true; socketError = true;
printf("Could not read! %s\n", strerror(errno)); fprintf(stderr, "Could not read! %s\n", strerror(errno));
return false; return false;
break; break;
} }

View file

@ -69,6 +69,7 @@ bool FLV_GetPacket(FLV_Pack *& p, int sock){
if (FLV_Checkheader(p->data)){ if (FLV_Checkheader(p->data)){
sofar = 0; sofar = 0;
memcpy(FLVHeader, p->data, 13); memcpy(FLVHeader, p->data, 13);
//fwrite(p->data, 13, 1, stdout);//output raw stream
}else{ }else{
All_Hell_Broke_Loose = true; All_Hell_Broke_Loose = true;
fprintf(stderr, "Invalid FLV header. All Hell Broke Loose!\n"); fprintf(stderr, "Invalid FLV header. All Hell Broke Loose!\n");
@ -94,12 +95,11 @@ bool FLV_GetPacket(FLV_Pack *& p, int sock){
testlen += (p->data[p->len-2] << 8); testlen += (p->data[p->len-2] << 8);
testlen += (p->data[p->len-3] << 16); testlen += (p->data[p->len-3] << 16);
testlen += (p->data[p->len-4] << 24); testlen += (p->data[p->len-4] << 24);
if (p->len == testlen){ //fwrite(p->data, p->len, 1, stdout);//output raw stream
fprintf(stderr, "Correct length tag...\n"); if (p->len != testlen){
}else{
fprintf(stderr, "Len: %i, testlen: %i\n", p->len, testlen); fprintf(stderr, "Len: %i, testlen: %i\n", p->len, testlen);
All_Hell_Broke_Loose = true; All_Hell_Broke_Loose = true;
fprintf(stderr, "ReadUntil fail: > 500kb tag? All Hell Broke Loose!\n", strerror(errno)); fprintf(stderr, "ReadUntil fail: Wrong size tag? All Hell Broke Loose!\n");
return false; return false;
} }
done = true; done = true;