diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index 135687c9..1e087e19 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -66,6 +66,7 @@ import ( "math/rand" "reflect" "strconv" + "strings" "unsafe" "github.com/chamaken/cgolmnl/inet" @@ -597,10 +598,10 @@ func C_RTMP_SetupURL(r *C.RTMP, u string) int32 { // AVal *playpath, AVal *app); // parseurl.c +33 func C_RTMP_ParseURL(url *byte, protocol *int32, host *C.AVal, port *uint32, - playpath *C.AVal, app *C.AVal) { + playpath *C.AVal, app *C.AVal) int { var p, end, col, ques, slash *byte - + // TODO: use our logger here // RTMP_Log(RTMP_LOGDEBUG, "Parsing..."); *protocol = RTMP_PROTOCOL_RTMP @@ -610,8 +611,174 @@ func C_RTMP_ParseURL(url *byte, protocol *int32, host *C.AVal, port *uint32, app.av_len = 0 app.av_val = nil - p = str + p = strstr(url, goStrToCStr("://")) + if p == nil { + // TODO: use our logger here + log.Println("RTMP URL: No :// in url!") + return 0 + } + /* + NOTE: the following code nees to be ported if we're using anything other than + rtmp! + { + int len = (int)(p-url); + + if(len == 4 && strncasecmp(url, "rtmp", 4)==0) + *protocol = RTMP_PROTOCOL_RTMP; + else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0) + *protocol = RTMP_PROTOCOL_RTMPT; + else if(len == 5 && strncasecmp(url, "rtmps", 5)==0) + *protocol = RTMP_PROTOCOL_RTMPS; + else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0) + *protocol = RTMP_PROTOCOL_RTMPE; + else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0) + *protocol = RTMP_PROTOCOL_RTMFP; + else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0) + *protocol = RTMP_PROTOCOL_RTMPTE; + else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0) + *protocol = RTMP_PROTOCOL_RTMPTS; + else { + RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n"); + goto parsehost; + } + } + */ + // TODO: implement new logger here + // RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol); + + // Get the hostname + p = (*byte)(incBytePtr(unsafe.Pointer(p), 3)) + + // check for sudden death + if *p == 0 { + // TODO: use new logger here + // RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!"); + return 0 + } + + end = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(strlen(p)))) + col = strchr(p, ':') + ques = strchr(p, '?') + slash = strchr(p, '/') + + { + var hostlen int32 + if slash != nil { + hostlen = int32(uintptr(unsafe.Pointer(slash)) - uintptr(unsafe.Pointer(p))) + } else { + hostlen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) + } + if col != nil && int32(uintptr(unsafe.Pointer(col))-uintptr(unsafe.Pointer(p))) < hostlen { + hostlen = int32(uintptr(unsafe.Pointer(col)) - uintptr(unsafe.Pointer(p))) + } + + if hostlen < 256 { + host.av_val = (*C.char)(unsafe.Pointer(p)) + host.av_len = C.int(hostlen) + // TODO: use new logger with this + //RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host->av_val); + } else { + // TODO: use new logger with this + // RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!"); + } + + p = (*byte)(incBytePtr(unsafe.Pointer(p), int(hostlen))) + } + + // get port number if available + if *p == ':' { + var p2 uint32 + p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) + tmp, _ := strconv.Atoi(cStrToGoStr(p)) + p2 = uint32(tmp) + if p2 > 65535 { + // TODO: use new logger with this + // RTMP_Log(RTMP_LOGWARNING, "Invalid port number!"); + } else { + *port = p2 + } + } + + if slash == nil { + // TODO: use new logger + // RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!"); + return 1 + } + + p = (*byte)(incBytePtr(unsafe.Pointer(slash), 1)) + + { + /* parse application + * + * rtmp://host[:port]/app[/appinstance][/...] + * application = app[/appinstance] + */ + + var slash2 *byte + var slash3 *byte = nil + var slash4 *byte = nil + var applen, appnamelen int32 + + slash2 = strchr(p, '/') + + if slash2 != nil { + slash3 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash2))+ + uintptr(1))), '/') + } + if slash3 != nil { + slash4 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash3))+ + uintptr(1))), '/') + } + + // ondemand, pass all parameters as app + applen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) + appnamelen = applen + + switch { + case ques != nil && strstr(p, goStrToCStr("slist=")) != nil: + appnamelen = int32(uintptr(unsafe.Pointer(ques)) - uintptr(unsafe.Pointer(p))) + case strings.Compare(cStrToGoStr(p)[:9], "ondemand/") == 0: + /* app = ondemand/foobar, only pass app=ondemand */ + applen = 8 + appnamelen = 8 + default: + switch { + case slash4 != nil: + appnamelen = int32(uintptr(unsafe.Pointer(slash4)) - uintptr( + unsafe.Pointer(p))) + case slash3 != nil: + appnamelen = int32(uintptr(unsafe.Pointer(slash3)) - uintptr( + unsafe.Pointer(p))) + case slash2 != nil: + appnamelen = int32(uintptr(unsafe.Pointer(slash2)) - uintptr( + unsafe.Pointer(p))) + } + + applen = appnamelen + } + + app.av_val = (*C.char)(unsafe.Pointer(p)) + app.av_len = C.int(applen) + // TODO: use new logging here + // RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p); + + p = (*byte)(incBytePtr(unsafe.Pointer(p), int(appnamelen))) + } + + if *p == '/' { + p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) + } + + if int(uintptr(unsafe.Pointer(end))-uintptr(unsafe.Pointer(p))) != 0 { + var av C.AVal + av.av_val = (*C.char)(unsafe.Pointer(p)) + av.av_len = C.int(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) + // TODO: port THis + C.RTMP_ParsePlaypath(&av, playpath) + } + + return 1 } // void SocksSetup(RTMP *r, C.AVal* sockshost); @@ -2330,10 +2497,15 @@ func goStrToCStr(str string) *byte { for i := 0; i < l; i++ { slice[i] = *indxBytePtr(ptr, i) } - slice[l] = '\000' + slice[l] = '\x00' return &slice[0] } +// TODO: need a test in rtmp_test.go +func cStrToGoStr(cStr *byte) string { + return string(ptrToSlice(unsafe.Pointer(cStr), int(strlen(cStr)))) +} + // Duplicates a string given as a byte pointer func strdup(str *byte) *byte { length := strlen(str) @@ -2374,6 +2546,7 @@ func strchr(str *byte, val byte) *byte { return nil } +// TODO: need a test in rtmp_test.go // Porting: http://www.ai.mit.edu/projects/im/cam8/cam8/working/CAMlib/tcl/compat/strstr.c func strstr(str *byte, substring *byte) *byte { var a, b *byte