diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index ee99b572..95ca0b8f 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -149,13 +149,9 @@ var ( } ) -// int RTMP_IsConnected(RTMP *r); -// rtmp.c +363 -func C_RTMP_IsConnected(r *C_RTMP) int32 { - if r.m_sb.sb_socket != -1 { - return 1 - } - return 0 +// TODO: find location in c file +func SET_RCVTIMEO(tv *int32, s int32) { + *tv = s * 1000 } func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { @@ -194,6 +190,12 @@ func startSession(rtmp *C_RTMP, u string, timeout uint32) (*C_RTMP, error) { return rtmp, nil } +// uint32_t RTMP_GetTime(); +// rtmp.c +156 +func C_RTMP_GetTime() int32 { + return int32(time.Now().UnixNano() / 1000000) +} + // RTMP* RTMP_IsConnected(); // rtmp.c +317 func C_RTMP_Alloc() *C_RTMP { @@ -218,6 +220,59 @@ func C_RTMP_Init(r *C_RTMP) { r.Link.swfAge = 30 } +// void RTMP_EnableWrite(RTMP *r); +// rtmp.c +351 +func C_RTMP_EnableWrite(r *C_RTMP) { + r.Link.protocol |= RTMP_FEATURE_WRITE +} + +// int RTMP_IsConnected(RTMP *r); +// rtmp.c +363 +func C_RTMP_IsConnected(r *C_RTMP) int32 { + if r.m_sb.sb_socket != -1 { + return 1 + } + return 0 +} + +// void RTMP_SetBufferMS(RTMP *r, int size); +// rtmp.c +381 +func C_RTMP_SetBufferMS(r *C_RTMP, size int32) { + r.m_nBufferMS = int32(size) +} + +// void SocksSetup(RTMP *r, C_AVal* sockshost); +// rtmp.c +410 +func C_SocksSetup(r *C_RTMP, sockshost *C_AVal) { + if sockshost.av_len != 0 { + socksport := strchr((*byte)(unsafe.Pointer(sockshost.av_val)), ':') + hostname := strdup((*byte)(unsafe.Pointer(sockshost.av_val))) + + if unsafe.Pointer(socksport) != nil { + *indxBytePtr(unsafe.Pointer(hostname), + int(uintptr(decBytePtr(unsafe.Pointer(socksport), + int(uintptr(unsafe.Pointer(sockshost.av_val))))))) = '\000' + r.Link.sockshost.av_val = (*byte)(unsafe.Pointer(hostname)) + r.Link.sockshost.av_len = int32(strlen(hostname)) + + value, err := strconv.Atoi(string(ptrToSlice(unsafe.Pointer(uintptr( + unsafe.Pointer(socksport))+uintptr(1)), int(strlen((*byte)(unsafe.Pointer( + uintptr(unsafe.Pointer(socksport))+uintptr(1)))))+1))) + if err != nil { + log.Println("C_SocksSetup: bad string conversion!") + } + if uintptr(unsafe.Pointer(socksport)) == 0 { + value = 1080 + } + r.Link.socksport = uint16(value) + } + } else { + r.Link.sockshost.av_val = nil + r.Link.sockshost.av_len = 0 + r.Link.socksport = 0 + } +} + // int RTMP_SetupURL(RTMP *r, char* url); // rtmp.c +757 // NOTE: code dealing with rtmp over http has been disregarded @@ -292,38 +347,6 @@ func C_RTMP_SetupURL(r *C_RTMP, u string) int32 { return 1 } -// void SocksSetup(RTMP *r, C_AVal* sockshost); -// rtmp.c +410 -func C_SocksSetup(r *C_RTMP, sockshost *C_AVal) { - if sockshost.av_len != 0 { - socksport := strchr((*byte)(unsafe.Pointer(sockshost.av_val)), ':') - hostname := strdup((*byte)(unsafe.Pointer(sockshost.av_val))) - - if unsafe.Pointer(socksport) != nil { - *indxBytePtr(unsafe.Pointer(hostname), - int(uintptr(decBytePtr(unsafe.Pointer(socksport), - int(uintptr(unsafe.Pointer(sockshost.av_val))))))) = '\000' - r.Link.sockshost.av_val = (*byte)(unsafe.Pointer(hostname)) - r.Link.sockshost.av_len = int32(strlen(hostname)) - - value, err := strconv.Atoi(string(ptrToSlice(unsafe.Pointer(uintptr( - unsafe.Pointer(socksport))+uintptr(1)), int(strlen((*byte)(unsafe.Pointer( - uintptr(unsafe.Pointer(socksport))+uintptr(1)))))+1))) - if err != nil { - log.Println("C_SocksSetup: bad string conversion!") - } - if uintptr(unsafe.Pointer(socksport)) == 0 { - value = 1080 - } - r.Link.socksport = uint16(value) - } - } else { - r.Link.sockshost.av_val = nil - r.Link.sockshost.av_len = 0 - r.Link.socksport = 0 - } -} - /* func rtmpClose(r *C_RTMP) { closeInternal(r, 0) @@ -408,55 +431,6 @@ func closeInternal(r *C_RTMP, reconnect int32) { } */ -// void RTMP_EnableWrite(RTMP *r); -// rtmp.c +351 -func C_RTMP_EnableWrite(r *C_RTMP) { - r.Link.protocol |= RTMP_FEATURE_WRITE -} - -// void RTMP_SetBufferMS(RTMP *r, int size); -// rtmp.c +381 -func C_RTMP_SetBufferMS(r *C_RTMP, size int32) { - r.m_nBufferMS = int32(size) -} - -// int RTMP_Connect(RTMP *r, RTMPPacket* cp); -// rtmp.c +1032 -func C_RTMP_Connect(r *C_RTMP, cp *C_RTMPPacket) int { - // TODO: port this - var service C.sockaddr_in - - if r.Link.hostname.av_len == 0 { - return 0 - } - memset((*byte)(unsafe.Pointer(&service)), 0, int(unsafe.Sizeof(service))) - - // TODO: port this - service.sin_family = C.AF_INET - - if r.Link.socksport != 0 { - // TODO: port this - if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.sockshost)), C.int(r.Link.socksport)) == 0 { - return 0 - } - } else { - // connect directly - if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.hostname)), - C.int(r.Link.port)) == 0 { - return 0 - } - } - //if C.RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { - if C_RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { - return 0 - } - - r.m_bSendCounter = 1 - - return int(C_RTMP_Connect1(r, cp)) - //return int(C.RTMP_Connect1(r, cp)) -} - // int RTMP_Connect0(RTMP *r, struct sockaddr* service); // rtmp.c +906 func C_RTMP_Connect0(r *C_RTMP, service *C.sockaddr) int { @@ -505,6 +479,65 @@ func C_RTMP_Connect0(r *C_RTMP, service *C.sockaddr) int { return 1 } +// int RTMP_Connect1(RTMP* r, RTMPPacket* cp); +// rtmp.c +978 +func C_RTMP_Connect1(r *C_RTMP, cp *C_RTMPPacket) int { + if debugMode { + log.Println("... connected, handshaking...") + } + //if C.HandShake(r, 1) == 0 { + if C_HandShake(r, 1) == 0 { + log.Println("C_RTMP_Connect1: handshake failed!") + return 0 + } + if debugMode { + log.Println("... handshaked...") + } + //if C.SendConnectPacket(r, cp) == 0 { + if C_SendConnectPacket(r, cp) == 0 { + log.Println("RTMP connect failed!") + return 0 + } + return 1 +} + +// int RTMP_Connect(RTMP *r, RTMPPacket* cp); +// rtmp.c +1032 +func C_RTMP_Connect(r *C_RTMP, cp *C_RTMPPacket) int { + // TODO: port this + var service C.sockaddr_in + + if r.Link.hostname.av_len == 0 { + return 0 + } + memset((*byte)(unsafe.Pointer(&service)), 0, int(unsafe.Sizeof(service))) + + // TODO: port this + service.sin_family = C.AF_INET + + if r.Link.socksport != 0 { + // TODO: port this + if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.sockshost)), C.int(r.Link.socksport)) == 0 { + return 0 + } + } else { + // connect directly + if C.add_addr_info(&service, (*C.AVal)(unsafe.Pointer(&r.Link.hostname)), + C.int(r.Link.port)) == 0 { + return 0 + } + } + //if C.RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { + if C_RTMP_Connect0(r, (*C.sockaddr)(unsafe.Pointer(&service))) == 0 { + return 0 + } + + r.m_bSendCounter = 1 + + return int(C_RTMP_Connect1(r, cp)) + //return int(C.RTMP_Connect1(r, cp)) +} + // int SocksNegotiate(RTMP* r); // rtmp.c +1062 func C_SocksNegotiate(r *C_RTMP) int { @@ -542,115 +575,6 @@ func C_SocksNegotiate(r *C_RTMP) int { } } -// TODO: find location in c file -func SET_RCVTIMEO(tv *int32, s int32) { - *tv = s * 1000 -} - -// int RTMP_Connect1(RTMP* r, RTMPPacket* cp); -// rtmp.c +978 -func C_RTMP_Connect1(r *C_RTMP, cp *C_RTMPPacket) int { - if debugMode { - log.Println("... connected, handshaking...") - } - //if C.HandShake(r, 1) == 0 { - if C_HandShake(r, 1) == 0 { - log.Println("C_RTMP_Connect1: handshake failed!") - return 0 - } - if debugMode { - log.Println("... handshaked...") - } - //if C.SendConnectPacket(r, cp) == 0 { - if C_SendConnectPacket(r, cp) == 0 { - log.Println("RTMP connect failed!") - return 0 - } - return 1 -} - -// int HandShake(RTMP* r, int FP9HandShake); -// rtmp.c +3744 -func C_HandShake(r *C_RTMP, FP9HandShake int32) int { - var bMatch int - //uptime := uint32(0) - //suptime := uint32(0) - //typ := byte(0) - var uptime, suptime uint32 - var typ byte - //clientbuf := make([]byte, RTMP_SIG_SIZE+1) - var clientbuf [RTMP_SIG_SIZE + 1]byte - clientsig := (*byte)(incBytePtr(unsafe.Pointer(&clientbuf[0]), 1)) - //serversig := make([]byte, RTMP_SIG_SIZE) - var serversig [RTMP_SIG_SIZE]byte - - clientbuf[0] = 0x03 // not encrypted - - // TODO: port rtmp_getTime - //uptime = inet.Htonl(uint32(C.RTMP_GetTime())) - uptime = inet.Htonl(uint32(C_RTMP_GetTime())) - memmove(unsafe.Pointer(clientsig), unsafe.Pointer(&uptime), 4) - - memset(indxBytePtr(unsafe.Pointer(clientsig), 4), 0, 4) - - for i := 8; i < RTMP_SIG_SIZE; i++ { - *indxBytePtr(unsafe.Pointer(clientsig), i) = byte(rand.Intn(256)) - } - - if C_WriteN(r, unsafe.Pointer(&clientbuf[0]), RTMP_SIG_SIZE+1) == 0 { - return 0 - } - - //if C.ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { - if C_ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { - return 0 - } - - if debugMode { - log.Println("C_HandShake: Type answer: %v", typ) - } - if typ != clientbuf[0] { - log.Println("C_HandShake: type mismatch: client sent %v, server sent: %v", - clientbuf[0], typ) - } - if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - return 0 - } - - // decode server response - memmove(unsafe.Pointer(&suptime), unsafe.Pointer(&serversig[0]), 4) - suptime = inet.Ntohl(suptime) - - // 2nd part of handshake - if C_WriteN(r, unsafe.Pointer(&serversig[0]), RTMP_SIG_SIZE) == 0 { - return 0 - } - - if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { - return 0 - } - - // TODO: find golang memcmp - bMatch = 0 - if memcmp(unsafe.Pointer(&serversig[0]), unsafe.Pointer(clientsig), - RTMP_SIG_SIZE) == 0 { - bMatch = 1 - } - - if bMatch == 0 { - log.Println("Client signature does not match!") - } - return 1 -} - -// uint32_t RTMP_GetTime(); -// rtmp.c +156 -func C_RTMP_GetTime() int32 { - return int32(time.Now().UnixNano() / 1000000) -} - // int ReadN(RTMP* r, char* buffer, int n); // rtmp.c +1390 func C_ReadN(r *C_RTMP, buffer *byte, n int) int { @@ -712,61 +636,6 @@ func C_ReadN(r *C_RTMP, buffer *byte, n int) int { return nOriginalSize - n } -// int RTMPSockBuf_Fill(RTMPSockBuf* sb); -// rtmp.c +4253 -func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { - var nBytes int - - if sb.sb_size == 0 { - sb.sb_start = &sb.sb_buf[0] - } - - for { - nBytes = int(unsafe.Sizeof(sb.sb_buf)) - 1 - int(sb.sb_size) - - int(uintptr(unsafe.Pointer(sb.sb_start))-uintptr(unsafe.Pointer( - &sb.sb_buf[0]))) - - // TODO: figure out what to do with recv - nBytes = int(C.recv(C.int(sb.sb_socket), unsafe.Pointer(uintptr(unsafe.Pointer( - sb.sb_start))+uintptr(int(sb.sb_size))), C.size_t(nBytes), 0)) - - if nBytes != -1 { - sb.sb_size += int32(nBytes) - } else { - log.Println("C_RTMPSockBuf_Fill: recv error!") - } - break - } - return nBytes -} - -// int SendBytesReceived(RTMP* r); -// rtmp.c +2080 -func C_SendBytesReceived(r *C_RTMP) int { - var packet C_RTMPPacket - var pbuf [256]byte - pend := (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), 256)) - - packet.m_nChannel = 0x02 /* control channel (invoke) */ - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM - packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT - packet.m_nTimeStamp = 0 - packet.m_nInfoField2 = 0 - packet.m_hasAbsTimestamp = 0 - packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), - RTMP_MAX_HEADER_SIZE)) - - packet.m_nBodySize = 4 - - C_AMF_EncodeInt32((*byte)(unsafe.Pointer(packet.m_body)), pend, int32(r.m_nBytesIn)) - // C.AMF_EncodeInt32(packet.m_body, (*byte)(unsafe.Pointer(pend)), r.m_nBytesIn) - - r.m_nBytesInSent = r.m_nBytesIn - - //return int(C.RTMP_SendPacket(r, &packet, 0)) - return C_RTMP_SendPacket(r, &packet, 0) -} - // int SendConnectPacket(RTMP* r, RTMPPacket* cp); // rtmp.c +1579 func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { @@ -947,6 +816,137 @@ func C_SendConnectPacket(r *C_RTMP, cp *C_RTMPPacket) int { return C_RTMP_SendPacket(r, &packet, 1) } +// int SendBytesReceived(RTMP* r); +// rtmp.c +2080 +func C_SendBytesReceived(r *C_RTMP) int { + var packet C_RTMPPacket + var pbuf [256]byte + pend := (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), 256)) + + packet.m_nChannel = 0x02 /* control channel (invoke) */ + packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM + packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT + packet.m_nTimeStamp = 0 + packet.m_nInfoField2 = 0 + packet.m_hasAbsTimestamp = 0 + packet.m_body = (*byte)(incBytePtr(unsafe.Pointer(&pbuf[0]), + RTMP_MAX_HEADER_SIZE)) + + packet.m_nBodySize = 4 + + C_AMF_EncodeInt32((*byte)(unsafe.Pointer(packet.m_body)), pend, int32(r.m_nBytesIn)) + // C.AMF_EncodeInt32(packet.m_body, (*byte)(unsafe.Pointer(pend)), r.m_nBytesIn) + + r.m_nBytesInSent = r.m_nBytesIn + + //return int(C.RTMP_SendPacket(r, &packet, 0)) + return C_RTMP_SendPacket(r, &packet, 0) +} + +// int HandShake(RTMP* r, int FP9HandShake); +// rtmp.c +3744 +func C_HandShake(r *C_RTMP, FP9HandShake int32) int { + var bMatch int + //uptime := uint32(0) + //suptime := uint32(0) + //typ := byte(0) + var uptime, suptime uint32 + var typ byte + //clientbuf := make([]byte, RTMP_SIG_SIZE+1) + var clientbuf [RTMP_SIG_SIZE + 1]byte + clientsig := (*byte)(incBytePtr(unsafe.Pointer(&clientbuf[0]), 1)) + //serversig := make([]byte, RTMP_SIG_SIZE) + var serversig [RTMP_SIG_SIZE]byte + + clientbuf[0] = 0x03 // not encrypted + + // TODO: port rtmp_getTime + //uptime = inet.Htonl(uint32(C.RTMP_GetTime())) + uptime = inet.Htonl(uint32(C_RTMP_GetTime())) + memmove(unsafe.Pointer(clientsig), unsafe.Pointer(&uptime), 4) + + memset(indxBytePtr(unsafe.Pointer(clientsig), 4), 0, 4) + + for i := 8; i < RTMP_SIG_SIZE; i++ { + *indxBytePtr(unsafe.Pointer(clientsig), i) = byte(rand.Intn(256)) + } + + if C_WriteN(r, unsafe.Pointer(&clientbuf[0]), RTMP_SIG_SIZE+1) == 0 { + return 0 + } + + //if C.ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { + if C_ReadN(r, (*byte)(unsafe.Pointer(&typ)), 1) != 1 { + return 0 + } + + if debugMode { + log.Println("C_HandShake: Type answer: %v", typ) + } + if typ != clientbuf[0] { + log.Println("C_HandShake: type mismatch: client sent %v, server sent: %v", + clientbuf[0], typ) + } + if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + return 0 + } + + // decode server response + memmove(unsafe.Pointer(&suptime), unsafe.Pointer(&serversig[0]), 4) + suptime = inet.Ntohl(suptime) + + // 2nd part of handshake + if C_WriteN(r, unsafe.Pointer(&serversig[0]), RTMP_SIG_SIZE) == 0 { + return 0 + } + + if C_ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + //if C.ReadN(r, (*byte)(unsafe.Pointer(&serversig[0])), RTMP_SIG_SIZE) != RTMP_SIG_SIZE { + return 0 + } + + // TODO: find golang memcmp + bMatch = 0 + if memcmp(unsafe.Pointer(&serversig[0]), unsafe.Pointer(clientsig), + RTMP_SIG_SIZE) == 0 { + bMatch = 1 + } + + if bMatch == 0 { + log.Println("Client signature does not match!") + } + return 1 +} + +// int RTMPSockBuf_Fill(RTMPSockBuf* sb); +// rtmp.c +4253 +func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int { + var nBytes int + + if sb.sb_size == 0 { + sb.sb_start = &sb.sb_buf[0] + } + + for { + nBytes = int(unsafe.Sizeof(sb.sb_buf)) - 1 - int(sb.sb_size) - + int(uintptr(unsafe.Pointer(sb.sb_start))-uintptr(unsafe.Pointer( + &sb.sb_buf[0]))) + + // TODO: figure out what to do with recv + nBytes = int(C.recv(C.int(sb.sb_socket), unsafe.Pointer(uintptr(unsafe.Pointer( + sb.sb_start))+uintptr(int(sb.sb_size))), C.size_t(nBytes), 0)) + + if nBytes != -1 { + sb.sb_size += int32(nBytes) + } else { + log.Println("C_RTMPSockBuf_Fill: recv error!") + } + break + } + return nBytes +} + // int RTMP_ConnectStream(RTMP* r, int seekTime); // rtmp.c +1099 func C_RTMP_ConnectStream(r *C_RTMP, seekTime int32) int {