long .vd

@hellfire11

Albania, รข

Joined Apr 2016

World Rank: #26844 (1 points)

Institution: TP

AMF.cpp 143: unsigned int numberElement = 0; Buffer.cpp 79: //Xu li truong hop het buffer 88: (*ppBuffer) = data_pos; Buffer.h remove 1 13: //#include "log.h" 14: #pragma once RTMP.cpp #include "rtmp.h" #include "RTMP_LOG.h" #define FLOW_CODE #define PREFIX "[%s]: " #define FUNCTION __FUNCTION__ /*Temp*/ int32_t GetTime() { #if defined(WIN32) return timeGetTime(); #else struct tms t; return times(&t); #endif } /** * Send * @param buffer: * @param length: * @returns: */ int RTMP::Send(char* buffer, int length) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE int nbyte_send = 0; return 0; } /** * Receive * @param buffer: * @param length: * @returns: */ int RTMP::Receive(char* buffer, int len) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE int nbyte_send = 0; return 0; } /** * Send data * @param buffer: buffer data * @param length: length of data can be read * @returns: number of bytes was sent */ //int RTMP::SendRTMPMessage(char* buffer, int length) //{ // int nByteSent = 0, result = length; // char* pBuffer = buffer; // while (length > 0) // { // nByteSent = send(service.connect_socket, pBuffer, length, 0); // assert(nByteSent > 0); // length -= nByteSent; // pBuffer += nByteSent; // } // // return result - length; //} /** * received data from Server * @param r: contains network information which used to connect contains receiver data * @param buffer: buffer store data * @param len: length of data can be read * @returns: length of data was received */ //int RTMP::ReceiveRTMPMessage(char* buffer, int length) //{ // int nByteRecv = 0, result = length; // char* pBuffer = buffer; // while (length > 0) // { // nByteRecv = recv(service.connect_socket, pBuffer, length, 0); // assert(nByteRecv > 0); // length -= nByteRecv; // // pBuffer += nByteRecv; // } // // return result - length; //} /** * Handle the connection via socket between Client and Server * @param hostname: server domain or IP * @param port: port connect * @returns: true == success */ bool RTMP::SocketConnect(const char* hostname, const unsigned short port) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE ConfigSocket(hostname, port); SOCKET _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert(_socket != SOCKET_ERROR && "Cannot init socket"); //assert(connect(_socket, (sockaddr*)&(service.sockAddr), sizeof(service.sockAddr)) >= 0); int iResult = connect(_socket, (SOCKADDR *)& (service.sockAddr), sizeof(service.sockAddr)); if (iResult == SOCKET_ERROR) { RTMP_LOG(PREFIX"Connect function failed with error: %d\n", FUNCTION, WSAGetLastError()); iResult = closesocket(_socket); if (iResult == SOCKET_ERROR) RTMP_LOG(PREFIX"losesocket function failed with error: %d\n", FUNCTION, WSAGetLastError()); WSACleanup(); return false; } DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000; setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, "1", 1); service.connect_socket = _socket; return true; } /** * decode the host name to IP Address * @param hostname: * @param port: * @returns: */ bool RTMP::ConfigSocket(const char* hostname, const unsigned short port) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE if (hostname == NULL || strlen(hostname) == 0 || port < 0) { RTMP_LOG(PREFIX"Hostname or port is invalid\n", FUNCTION); return false; } service.sockAddr.sin_family = AF_INET; service.sockAddr.sin_addr.s_addr = inet_addr(hostname); service.sockAddr.sin_port = htons((u_short)port); if (service.sockAddr.sin_addr.s_addr == INADDR_NONE) { //assert(strlen(hostname) != 0 && isalpha(hostname[0]) && "Host name have no value"); if (!isalpha(hostname[0])) { RTMP_LOG(PREFIX"Hostname is invalid\n", FUNCTION); return false; } struct hostent *remoteHost = gethostbyname(hostname); //assert(remoteHost != NULL && "Cannot decode the hostname"); if (remoteHost == NULL) { RTMP_LOG(PREFIX"Cannot decode the hostname\n", FUNCTION); return false; } memcpy(&(service.sockAddr.sin_addr), remoteHost->h_addr_list[0], remoteHost->h_length); } return true; } int RTMP::AMFEncodeNumber64(char* buffer, double value) { char* pBuffer = buffer; *pBuffer++ = 0x00; uint64_t x = *((uint64_t*)&value); memcpy(pBuffer, &x, 8); SWAP64(pBuffer); pBuffer += 8; return RESULT(pBuffer, buffer, 9); } int RTMP::AMFEncodeNumber32(char* buffer, int value) { char* pBuffer = buffer; memcpy(pBuffer, &value, 4); SWAP32(pBuffer); pBuffer += 4; return RESULT(pBuffer, buffer, 4); } int RTMP::AMFEncodeNumber24(char* buffer, int value) { char* pBuffer = buffer; memcpy(pBuffer, &value, 3); SWAP(pBuffer[0], pBuffer[2]); pBuffer += 3; return RESULT(pBuffer, buffer, 3); } int RTMP::AMFEncodeNumber16(char* buffer, unsigned short value) { char* pBuffer = buffer; memcpy(pBuffer, &value, 2); SWAP16(pBuffer); pBuffer += 2; return RESULT(pBuffer, buffer, 2); } int RTMP::AMFEncodeBoolean(char* buffer, bool value) { char* pBuffer = buffer; *pBuffer++ = 0x01; *pBuffer = value ? 0x01 : 0x00; pBuffer++; return RESULT(pBuffer, buffer, 2); } int RTMP::AMFEncodeString(char* buffer, char* str, int length) { if (length > 0xffff) { return AMFEncodeLongString(buffer, str, length); } char* pBuffer = buffer; *pBuffer++ = 0x02; pBuffer += AMFEncodeNumber16(pBuffer, (unsigned short)length); memcpy(pBuffer, str, length); pBuffer += strlen(str); return RESULT(pBuffer, buffer, length + 3); } int RTMP::AMFEncodeStringKey(char * buffer, char * str, int length) { char* pBuffer = buffer; pBuffer += AMFEncodeNumber16(pBuffer, (unsigned short)length); memcpy(pBuffer, str, length); pBuffer += strlen(str); return RESULT(pBuffer, buffer, length + 2); } int RTMP::AMFEncodeObject(char* buffer, char* objName, int length) { char* pBuffer = buffer; *pBuffer++ = 0x03; pBuffer += AMFEncodeNumber16(pBuffer, (unsigned short)length); memcpy(pBuffer, objName, length); pBuffer += strlen(objName); return RESULT(pBuffer, buffer, length + 3); } int RTMP::AMFEncodeMovieclip() { return 0; } int RTMP::AMFEncodeNull() { return 0; } int RTMP::AMFEncodeUndefined() { return 0; } /** * Initiates use of the Winsock DLL by a process. * @param null * @returns null */ RTMP::RTMP() { WSAData wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); byte_read = 0; chunk_size = CHUNK_SIZE_DEFAULT; if (!vect_message_arrived.empty()) { vect_message_arrived.clear(); } if (!vect_command_sent.empty()) { vect_command_sent.clear(); } memset(chunk_message.data, 0, sizeof(chunk_message)); } RTMP::~RTMP() { } bool RTMP::ConnectToServer(const char* hostname, const unsigned short port) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE if (!SocketConnect(hostname, port)) { return false; } InitBuffer(service.port, service.connect_socket); if (!HandShake()) { return false; } service.app = "BigBuckBunny_115k.mov"; service.transaction_id = 1.0; service.flash_vers = "WIN 10,0,32,18"; service.swfURL = NULL_STRING; service.tcURL = "rtmp://184.72.239.149/vod/BigBuckBunny_115k.mov"; service.capabilities = "9947.57"; service.audio_codecs = 3191.0; service.video_codecs = 252.0; service.video_function = 1.0; service.pageUrl = NULL_STRING; service.object_encoding = 3.0; chunk_message.header.chunk_type = 0x00; chunk_message.header.chunk_stream_id = 0x03; chunk_message.header.message_length = 0; chunk_message.header.message_stream_id = 0; chunk_message.header.message_type_id = 0; chunk_message.header.timestamp = 0; chunk_message.header.extended_timestamp = 0; ConnectPacket(); RTMPMessage packet; ReceiveRTMPPacket(packet); return true; } int RTMP::ReadRTMPPacketHeader(RTMPMessage & packet) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE BYTE *pBuffer = nullptr; INT32 nbyte_read = 0; if (iBuffer->Read(&pBuffer, 1) != 1) { //LOG("%s: Read data failed!"); return -1; } nbyte_read++; packet.header.chunk_type = (pBuffer[0] >> 6); //2bits high packet.header.chunk_stream_id = (pBuffer[0] & 0x3F); //6bits low if (packet.header.chunk_stream_id == 0) { if (iBuffer->Read(&pBuffer, 1) != 1) { //LOG("%s: Read data failed!"); return -1; } packet.header.chunk_stream_id += pBuffer[0]; nbyte_read++; } else if (packet.header.chunk_stream_id == 1) { if (iBuffer->Read(&pBuffer, 2) != 2) { //LOG("%s: Read data failed!"); return -1; } unsigned short cs_id = 0; RTMP::AMFDecodeNumber16((char*)pBuffer, 2, cs_id); packet.header.chunk_stream_id = cs_id + 64; nbyte_read += 2; } if (packet.header.chunk_type < 3) { if (iBuffer->Read(&pBuffer, 3) != 3) { //false return -1; } RTMP::AMFDecodeNumber24((char*)pBuffer, 3, packet.header.timestamp); nbyte_read += 3; } if (packet.header.chunk_type < 2) { if (iBuffer->Read(&pBuffer, 4) != 4) { //flase return -1; } RTMP::AMFDecodeNumber24((char*)pBuffer, 3, packet.header.message_length); packet.header.message_type_id = pBuffer[3]; nbyte_read += 4; } if (packet.header.chunk_type < 1) { if (iBuffer->Read(&pBuffer, 4) != 4) { //flase return -1; } packet.header.message_stream_id = *((UINT32*)pBuffer); nbyte_read += 4; } if (packet.header.timestamp == 0xFFFFFF) { if (iBuffer->Read(&pBuffer, 4) != 4) { //false return -1; } RTMP::AMFDecodeNumber32((char*)pBuffer, 4, packet.header.extended_timestamp); nbyte_read += 4; } return nbyte_read; } /* //Define message type ID #define RTMP_SET_CHUNK_SIZE 0x01 #define RTMP_ABORT_MESSAGE 0x02 #define RTMP_ACKNOWLEDGEMENT 0x03 #define RTMP_USER_CONTROL_MESSAGE 0x04 #define RTMP_WINDOW_ACK_SIZE 0x05 #define RTMP_SET_PEER_BAND_WIDTH 0x06 #define RTMP_AUDIO_MESSAGE 0x08 #define RTMP_VIDEO_MESSAGE 0x09 #define RTMP_SHARE_OBJECT_AMF0 0x13 #define RTMP_SHARE_OBJECT_AMF3 0x10 #define RTMP_DATA_MESSAGE_AMF0 0x12 #define RTMP_DATA_MESSAGE_AMF3 0x0F #define RTMP_AGGREGATE_MESSAGE 0x16 #define RMTP_COMMAND_MESSAGE_AMF0 0x14 #define RTMP_COMMAND_MESSAGE_AMF3 0x11 */ int RTMP::HandlePacket(RTMPMessage & packet) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE switch (packet.header.message_type_id) { case RTMP_SET_CHUNK_SIZE: //0x01 { unsigned int new_chunk_size = 0; RTMP::AMFDecodeNumber32(packet.data, 4, new_chunk_size); SetChunkSize(new_chunk_size); break; } case RTMP_ABORT_MESSAGE: //0x02 { unsigned int chunk_stream_id_abort = *(unsigned int*)(packet.data); //Notification abort chunk stream id break; } case RTMP_ACKNOWLEDGEMENT: //0x03 { //Notification... break; } case RTMP_USER_CONTROL_MESSAGE: //0x04 { UserControlMessage(packet); break; } case RTMP_WINDOW_ACK_SIZE: //0x05 { break; } case RTMP_SET_PEER_BAND_WIDTH: //0x06 { break; } case RTMP_AUDIO_MESSAGE: //0x08 { break; } case RTMP_VIDEO_MESSAGE: //0x09 { break; } case RTMP_SHARE_OBJECT_AMF0: //0x13 { break; } case RTMP_SHARE_OBJECT_AMF3: //0x10 { break; } case RTMP_DATA_MESSAGE_AMF0: //0x12 { break; } case RTMP_DATA_MESSAGE_AMF3: //0x0F { break; } case RTMP_AGGREGATE_MESSAGE: //0x16 { break; } case RMTP_COMMAND_MESSAGE_AMF0: //0x14 { break; } case RTMP_COMMAND_MESSAGE_AMF3: //0x11 { break; } default: { } } return 0; } //Note: Message Stream ID store little endian int RTMP::ReceiveRTMPPacket(RTMPMessage & packet) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE BYTE *pBuffer = nullptr; INT32 nbyte_read = 0; nbyte_read = ReadRTMPPacketHeader(packet); if (iBuffer->Read(&pBuffer, packet.header.message_length) != packet.header.message_length) { //false return -1; } memcpy(packet.data, pBuffer, packet.header.message_length); nbyte_read += packet.header.message_length; return nbyte_read; } bool RTMP::HandShake() { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE //assert(service.connect_socket > 0); #define MAX_PACKET_LENGTH 1536 BYTE client_signal[MAX_PACKET_LENGTH + 1], *pclient_send = nullptr; BYTE server_signal[MAX_PACKET_LENGTH + 1], *pserver_send = nullptr; memset(client_signal, 0, MAX_PACKET_LENGTH + 1); memset(server_signal, 0, MAX_PACKET_LENGTH + 1); client_signal[0] = 0x03; unsigned int epoch_time = GetTime(); memcpy(client_signal + 1, &epoch_time, sizeof(epoch_time)); SWAP32((client_signal + 1)); for (int i = 9; i < MAX_PACKET_LENGTH + 1; i++) { client_signal[i] = i % 256; } //Send C0 + C1 //if (SendRTMPMessage(client_signal, MAX_PACKET_LENGTH + 1) != MAX_PACKET_LENGTH + 1) //{ // return false; //} if (oBuffer->Write(client_signal, MAX_PACKET_LENGTH + 1) != MAX_PACKET_LENGTH + 1) { RTMP_LOG(PREFIX"Send C0+C1 failed\n", FUNCTION); return false; } //Read S0 //if (ReceiveRTMPMessage(server_signal, 1) != 1 // && server_signal[0] != 0x03) //{ // return false; //} if (iBuffer->Read( &pserver_send, 1) != 1 || pserver_send[0] != 0x03) //may be null? { RTMP_LOG(PREFIX"C0 and S0 not match\n", FUNCTION); return false; } ////Read S1 //if (ReceiveRTMPMessage(server_signal, MAX_PACKET_LENGTH) != MAX_PACKET_LENGTH) //{ // return false; //} if (iBuffer->Read(&pserver_send, MAX_PACKET_LENGTH) != MAX_PACKET_LENGTH) { RTMP_LOG(PREFIX"Read S1 failed\n", FUNCTION); return false; } ////Send C2(S1) //if (SendRTMPMessage(server_signal, MAX_PACKET_LENGTH) != MAX_PACKET_LENGTH) //{ // return false; //} if (oBuffer->Write(server_signal, MAX_PACKET_LENGTH) != MAX_PACKET_LENGTH) { RTMP_LOG(PREFIX"Send C2 failed\n", FUNCTION); return false; } ////Read S2 //if (ReceiveRTMPMessage(server_signal + 1, MAX_PACKET_LENGTH) != MAX_PACKET_LENGTH) //{ // return false; //} if (iBuffer->Read(&pserver_send, MAX_PACKET_LENGTH) != MAX_PACKET_LENGTH) { RTMP_LOG(PREFIX"Read S2 failed\n", FUNCTION); return false; } if (memcmp(client_signal + 1, pserver_send, MAX_PACKET_LENGTH)) { RTMP_LOG(PREFIX"C1 and S2 not match\n", FUNCTION); return false; } return true; } void RTMP::InitBuffer(UINT32 port, SOCKET socket) { SAFE_DELETE(iBuffer); SAFE_DELETE(oBuffer); iBuffer = new IBuffer(port, socket); oBuffer = new OBuffer(port, socket); } void RTMP::SetChunkSize(int new_chunk_size) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE chunk_size = new_chunk_size; } void RTMP::AbortMessage() { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE } //rtmp_specification_1.0.pdf section 6.2, 7.1.7 void RTMP::UserControlMessage(RTMPMessage &packet) { #ifdef FLOW_CODE RTMP_LOG(PREFIX"\n", FUNCTION); #endif // FLOW_CODE if (packet.header.message_length < 6) { RTMP_LOG(PREFIX"Payload data not enough\n"); return; } unsigned short event_type = 0; RTMP::AMFDecodeNumber16(packet.data, 2, event_type); switch (event_type) { case 0x00: //Stream begin case 0x01: //Stream EOF case 0x02: //Stream dry case 0x03: //Set Buffer Length case 0x04: //Stream Is Recorded case 0x06: //Ping request case 0x07: //Ping response default: { } } } int RTMP::AMFEncodeLongString(char* buffer, char* str, int length) { char* pBuffer = buffer; *pBuffer++ = 0x0c; pBuffer += AMFEncodeNumber32(pBuffer, length); memcpy(pBuffer, str, length); return RESULT(pBuffer, buffer, length + 5); } int RTMP::AMFEncodeUnsupported() { return 0; } int RTMP::AMFEncodeRecordset() { return 0; } int RTMP::AMFEncodeXMLDocument() { return 0; } int RTMP::AMFEncodeTypedObject() { return 0; } int RTMP::AMFDecodeNumber64(char* buffer, int length, double & value) { if (length < 8) { return -1; } char str[8] = { 0 }; memcpy(str, buffer, 8); SWAP64(str); value = *(double *)(&str); return 8; } int RTMP::AMFDecodeNumber32(char* buffer, int length, unsigned int & value) { if (length < 4) { return -1; } char str[4] = { 0 }; memcpy(str, buffer, 4); SWAP32(str); value = *(int *)(&str); return 4; } int RTMP::AMFDecodeNumber24(char* buffer, int length, unsigned int & value) { if (length < 3) { return -1; } char str[3] = { 0 }; memcpy(str, buffer, 3); SWAP(str[0], str[2]); value = *(unsigned short *)(&str); return 3; } int RTMP::AMFDecodeNumber16(char* buffer, int length, unsigned short & value) { if (length < 2) { return -1; } char str[2] = { 0 }; memcpy(str, buffer, 2); SWAP16(str); value = *(unsigned short *)(&str); return 2; } int RTMP::AMFDecodeBoolean(char* buffer, int length, bool & value) { if (length < 1) { return -1; } value = buffer[0] == 0 ? false : true; return 1; } int RTMP::AMFDecodeString(char* buffer, STRING & str, int length) { STRING ss(buffer, length); str = ss; return length; } int RTMP::AMFDecodeObject(char* buffer, STRING & objName, int length) { return 0; } int RTMP::AMFEncodeReference() { return 0; } int RTMP::AMFEncodeECMAArray() { return 0; } int RTMP::AMFEncodeObjectEnd(char* buffer) { char* pBuffer = buffer; *pBuffer++ = 0x00; *pBuffer++ = 0x00; *pBuffer++ = 0x09; return RESULT(pBuffer, buffer, 3); } int RTMP::AMFEncodeStrictArray() { return 0; } int RTMP::AMFEncodeDate() { return 0; } /* 1. C->S: csid = 3, sid = 0, connect 2. S->C: csid = 2, sid = 0, serverBW csid = 2, sid = 0, clientBW csid = 2, sid = 0, ping (stream begin, stream ID = 0) csid = 2, sid = 0, chunkSize csid = 3, sid = 0, _result 3. C->S: csid = 2, sid = 0, serverBW 4. C->S: csid = 3, sid = 0, createStream (client stream ID = 2) 5. S->C: csid = 3, sid = 0, _result (client stream ID = 2, server stream ID = 1) 6. C->S: csid = 2, sid = 0, ping (set buffer size, stream ID = 1, size = 0) csid = 8, sid = 1, publish csid = 8, sid = 1, notify 7. S->C: csid = 2, sid = 0, ping (stream begin, stream ID = 1) 8. C->S: csid = 4, sid = 1, audio data 9. S->C: csid = 3, sid = 1, onStatus 10. C->S: csid = 6, sid = 1, video data */ /* RTMP Chunk Stream uses message type IDs 1, 2, 3, 5, and 6 for protocol control messages. These messages contain information needed by the RTMP Chunk Stream protocol. These protocol control messages MUST have message stream ID 0 (known as the control stream) and be sent in chunk stream ID 2. Protocol control messages take effect as soon as they are received; their timestamps are ignored. */ /* NetConnection is the default communication channel, which has a stream ID 0. Protocol and a few command messages, including createStream, use the default communication channel. */ int RTMP::ConnectPacket() { #ifdef FLOW_CODE RTMP_LOG(PREFIX"n", FUNCTION); #endif // FLOW_CODE char buffer[MAXIMUM_MESSAGE_SIZE] = { 0 }; int nbyte_buffer = 0, nbyte_header = 0; buffer[nbyte_buffer] = 0x00; buffer[nbyte_buffer] |= 0x03; //fmt nbyte_buffer++; memset(buffer + nbyte_buffer, 0, 4); //timestamp nbyte_buffer += 4; memset(buffer + nbyte_buffer, 0, 3); //reuse for message length nbyte_buffer += 3; buffer[nbyte_buffer] = 0x14; //message type ID 0x14 AMF0 nbyte_buffer++; memset(buffer + nbyte_buffer, 0, 4); //message stream ID 0x00 nbyte_buffer += 4; //Continue payload data //Command name + transaction nbyte_header = nbyte_buffer; nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, "connect", 7); nbyte_buffer += RTMP::AMFEncodeNumber64(buffer + nbyte_buffer, 1.0); buffer[nbyte_buffer] = 0x03; nbyte_buffer++; //Object nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "app", 3); nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, service.app, strlen(service.app)); nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "flashver", 8); nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, service.flash_vers, strlen(service.flash_vers)); //nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "swfUrl", 6); //nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, service.swfURL, strlen(service.swfURL)); nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "tcUrl", 5); nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, service.tcURL, strlen(service.tcURL)); //nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "swfUrl", 6); //nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, service.swfURL, strlen(service.swfURL)); /*nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "capabilities", 12); nbyte_buffer += RTMP::AMFEncodeString(buffer + nbyte_buffer, service.capabilities, strlen(service.capabilities));*/ nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "audioCodes", 10); nbyte_buffer += RTMP::AMFEncodeNumber64(buffer + nbyte_buffer, service.audio_codecs); nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "videoCodes", 10); nbyte_buffer += RTMP::AMFEncodeNumber64(buffer + nbyte_buffer, service.video_codecs); nbyte_buffer += RTMP::AMFEncodeStringKey(buffer + nbyte_buffer, "objectEncoding", 14); nbyte_buffer += RTMP::AMFEncodeNumber64(buffer + nbyte_buffer, service.object_encoding); //End of Object buffer[nbyte_buffer++] = 0x00; buffer[nbyte_buffer++] = 0x00; buffer[nbyte_buffer++] = 0x09; RTMP::AMFEncodeNumber24(buffer + 5, nbyte_buffer - nbyte_header); if (oBuffer->Write((BYTE*)buffer, nbyte_buffer) != nbyte_buffer) { RTMP_LOG(PREFIX"Send data failed\n", FUNCTION); return -1; } return nbyte_buffer; } RTMP.h #pragma once /********************************************************************** * File: rtmp.h * * Last edit: 27-Nov-2017 * Last Editor: LongVD2 * * Notes: This file define rtmp property, funct * * Copyright(C) 2008-2015 by Fuji Xerox Co., Ltd. All rights reserved. * Other Copyright information **********************************************************************/ #ifndef __RTMP_H__ #define __RTMP_H__ #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #endif // !_WINSOCK_DEPRECATED_NO_WARNINGS //#ifndef __WINSOCKAPI__ //#define __WINSOCKAPI__ // //#include <WinSock2.h> //#include <Windows.h> // //#endif // !__WINSOCKAPI__ #include "Buffer.h" #include <stdlib.h> #include <stdint.h> #include <assert.h> #include <vector> #include <iostream> #include <bitset> #pragma comment (lib, "Ws2_32.lib") #pragma comment (lib, "Mswsock.lib") #pragma comment (lib, "AdvApi32.lib") #pragma comment (lib, "Winmm.lib") #define VECTOR std::vector #define STRING std::string #define SOCKET_READ_TIMEOUT_SEC 30 #define MAXIMUM_MESSAGE_SIZE int(1<<14) //exactly 1<<24 (3bytes packet length) #define CHUNK_SIZE_DEFAULT 128 #define NULL_STRING "null" #define SWAP(x,y) (x)==(y)?(x):((x)^=(y),(y)^=(x),(x)^=(y)) #define SWAP64(ptr)\ ((SWAP(ptr[0],ptr[7])),\ (SWAP(ptr[1],ptr[6])),\ (SWAP(ptr[2],ptr[5])),\ (SWAP(ptr[3],ptr[4]))) #define SWAP32(ptr)\ ((SWAP(ptr[0],ptr[3])),\ (SWAP(ptr[1],ptr[2]))) #define SWAP16(ptr)\ ((SWAP(ptr[0],ptr[1]))) #define RESULT(pBuffer, buffer, size) (((pBuffer) - (buffer)) == (size) ? (size) : -1) //Define message type ID #define RTMP_SET_CHUNK_SIZE 0x01 #define RTMP_ABORT_MESSAGE 0x02 #define RTMP_ACKNOWLEDGEMENT 0x03 #define RTMP_USER_CONTROL_MESSAGE 0x04 #define RTMP_WINDOW_ACK_SIZE 0x05 #define RTMP_SET_PEER_BAND_WIDTH 0x06 #define RTMP_AUDIO_MESSAGE 0x08 #define RTMP_VIDEO_MESSAGE 0x09 #define RTMP_SHARE_OBJECT_AMF0 0x13 #define RTMP_SHARE_OBJECT_AMF3 0x10 #define RTMP_DATA_MESSAGE_AMF0 0x12 #define RTMP_DATA_MESSAGE_AMF3 0x0F #define RTMP_AGGREGATE_MESSAGE 0x16 #define RMTP_COMMAND_MESSAGE_AMF0 0x14 #define RTMP_COMMAND_MESSAGE_AMF3 0x11 typedef struct Service //contains params Server host and Client { char* host; char* app; char* protocol; char* flash_vers; char* swfURL; char* tcURL; char* capabilities; char* pageUrl; double object_encoding; double transaction_id; double audio_codecs; double video_codecs; double video_function; UINT32 port; struct sockaddr_in sockAddr; SOCKET connect_socket; Service() { transaction_id = 0.0; port = -1; memset(&sockAddr, 0, sizeof(sockAddr)); connect_socket = 0; } }Service; typedef struct RTMPHeader //Chunk Header max 18bytes { BYTE chunk_type; //fmt BYTE message_type_id; //Type ID UINT32 chunk_stream_id; //CS-ID UINT32 timestamp; UINT32 message_length; UINT32 message_stream_id; UINT32 extended_timestamp; RTMPHeader() : chunk_type(0) , message_type_id(0) , timestamp(0) , message_length(0) , message_stream_id(0) , extended_timestamp(0){} }RTMPHeader; typedef struct RTMPMessage //Communication message { RTMPHeader header; char data[MAXIMUM_MESSAGE_SIZE + 1]; //Nomarly 128 bytes, can be changed by SetChunkSize RTMPMessage() { memset(data, 0, sizeof(data)); } }RTMPMessage; class RTMP { private: IBuffer* iBuffer; //start pointer to data OBuffer* oBuffer; //end pointer to data UINT32 byte_read; //number bytes dont read UINT32 chunk_size; //ChunkSize which accepted between Client and Server, default 128 bytes Service service; RTMPMessage chunk_message; //Current message arrived VECTOR<RTMPHeader> vect_message_arrived; //Contains all message header arrived, it reuse for ChunkType 0,1,2,3 VECTOR<STRING> vect_command_sent; //Save command Sent from Client and waiting Server responsed public: RTMP(); ~RTMP(); /** * \brief * Config param to connect the Server * @param r: Be filled data like IP, hostname, port number.. * @param hostName: * @param port: * @returns: TRUE if successful, otherwise return FALSE */ bool ConnectToServer(const char* hostname, const unsigned short port); int ReceiveRTMPPacket(RTMPMessage &packet); protected: /** * \brief * Handle "Handshake" which is first step connection Server * @returns: TRUE if successful, otherwise return FALSE */ bool HandShake(); void InitBuffer(UINT32 port, SOCKET socket); /* * Protocol Control Message * These messages contain information needed by the RTMP Chunk Stream protocol * Message Stream ID 0x00 (know as the Control Stream) * Chunk Stream ID 0x02 * Ignore Timestamp */ void SetChunkSize(int new_chunk_size); //Message Type ID 0x01 void AbortMessage(); //Message Type ID 0x02 void Acknowledgement(); //Message Type ID 0x03 void UserControlMessage(RTMPMessage &packet); //Message Type ID 0x04 void WindowAckSize(); //Message Type ID 0x05 void SetPeerBandwidth(); //Message Type ID 0x06 /* * RTMP Command Message * These messages are exchanged between the Server and the Client (audio, media, command ... message). * Command messages carry the AMF encoded commands between the client and the server. * Message Stream ID 0x00 (know as the Control Stream) * Chunk Stream ID 0x03 (?) */ void AudioMessage(); //Message Type ID 0x08 void VideoMessage(); //Message Type ID 0x09 void ShareObject(); //Message Type ID 0x13 || 0x10 (AMF0 || AMF3) void DataMessage(); //Message Type ID 0x12 || 0x0F void AggregateMessage(); //Message Type ID 0x16 void CommandMessage(); //Message Type ID 0x14 || 0x11 /* * Protocol Funct * Make connections and exchange data with the Server. */ bool SocketConnect(const char* hostname, const unsigned short port); bool ConfigSocket(const char* hostname, const unsigned short port); int Send(char* buffer, int len); int Receive(char* buffer, int len); //int SendRTMPMessage(char* buffer, int len); //int ReceiveRTMPMessage(char* buffer, int len); int ConnectPacket(); int ReadRTMPPacketHeader(RTMPMessage &packet); int HandlePacket(RTMPMessage &packet); public: /* * AMF0 Decoded * Receive data - Decode * Send data - Encode * Ref: http://download.macromedia.com/pub/labs/amf/amf0_spec_121207.pdf */ int AMFEncodeNumber64(char* buffer, double value); //0x00 int AMFEncodeNumber32(char* buffer, int value); int AMFEncodeNumber24(char* buffer, int value); int AMFEncodeNumber16(char* buffer, unsigned short value); int AMFEncodeBoolean(char* buffer, bool value); //0x01 int AMFEncodeString(char* buffer, char* str, int length); //0x02 int AMFEncodeStringKey(char* buffer, char* str, int length); int AMFEncodeObject(char* buffer, char* objName, int length); //0x03 int AMFEncodeMovieclip(); //0x04 int AMFEncodeNull(); //0x05 int AMFEncodeUndefined(); //0x06 int AMFEncodeReference(); //0x07 int AMFEncodeECMAArray(); //0x08 int AMFEncodeObjectEnd(char* buffer); //0x09 int AMFEncodeStrictArray(); //0x0a int AMFEncodeDate(); //0x0b int AMFEncodeLongString(char* buffer, char* str, int length); //0x0c int AMFEncodeUnsupported(); //0x0d int AMFEncodeRecordset(); //0x0e int AMFEncodeXMLDocument(); //0x0f int AMFEncodeTypedObject(); //0x10 static int AMFDecodeNumber64(char* buffer, int length, double &value); //0x00 static int AMFDecodeNumber32(char* buffer, int length, unsigned int &value); static int AMFDecodeNumber24(char* buffer, int length, unsigned int &value); static int AMFDecodeNumber16(char* buffer, int length, unsigned short &value); static int AMFDecodeBoolean(char* buffer, int length, bool &value); //0x01 static int AMFDecodeString(char* buffer, STRING &str, int length); //0x02 static int AMFDecodeObject(char* buffer, STRING &objName, int length); //0x03 static int AMFDecodeMovieclip(); //0x04 static int AMFDecodeNull(); //0x05 static int AMFDecodeUndefined(); //0x06 static int AMFDecodeReference(); //0x07 static int AMFDecodeECMAArray(); //0x08 static int AMFDecodeObjectEnd(char* buffer); //0x09 static int AMFDecodeStrictArray(); //0x0a static int AMFDecodeDate(); //0x0b static int AMFDecodeLongString(char* buffer, char* str, int length); //0x0c static int AMFDecodeUnsupported(); //0x0d static int AMFDecodeRecordset(); //0x0e static int AMFDecodeXMLDocument(); //0x0f static int AMFDecodeTypedObject(); //0x10 }; #endif // !__RTMP_H__ RTMP_LOG #ifndef __RTMP_LOG_H__ #define __RTMP_LOG_H__ #pragma once #include <stdio.h> #include <stdarg.h> #include <string.h> #define MAX_BUFFER_LOG_SIZE 1024 //#define LOG_ERROR 0 //flag print error log //#define LOG_NORMAL 1 //flag print normal log //#define DEBUG_LOG //define to print debug log //#define _in_ //input param //#define _out_ //output param //#define _in_out_ //in&out param #define RTMP_ERROR(error) (RTMPError(error)) #define RTMP_LOG RTMPLOG void RTMPLOG(const char *format, ...) { char szLogBuffer[MAX_BUFFER_LOG_SIZE + 1]; va_list args; va_start(args, format); vsnprintf(szLogBuffer, MAX_BUFFER_LOG_SIZE, format, args); printf("%s\n", szLogBuffer); va_end(args); return; } /** * print socket error * @param error: socket error code * @returns errmsg: The error message which be depended on the error code */ char* RTMPError(int error) { char szErrmsg[MAX_BUFFER_LOG_SIZE + 1]; strerror_s(szErrmsg, MAX_BUFFER_LOG_SIZE + 1, error); return szErrmsg; } #endif // !__RTMP_LOG_H__

Activity over the last year

Effectiveness

 Problems solved
24
 Solutions submitted
147

Problems