Index: rtmpsuck.c =================================================================== --- rtmpsuck.c (revision 550) +++ rtmpsuck.c (working copy) @@ -249,18 +249,18 @@ r2 = malloc(len+1); memcpy(r2, r1, len); r2[len] = '\0'; - server->rc.Link.hostname.av_val = r2; + server->rc.Link.server.host.av_val = r2; r1 = strrchr(r2, ':'); if (r1) { - server->rc.Link.hostname.av_len = r1 - r2; + server->rc.Link.server.host.av_len = r1 - r2; *r1++ = '\0'; - server->rc.Link.port = atoi(r1); + server->rc.Link.server.port = atoi(r1); } else { - server->rc.Link.hostname.av_len = len; - server->rc.Link.port = 1935; + server->rc.Link.server.host.av_len = len; + server->rc.Link.server.port = 1935; } } pval.av_val = NULL; @@ -977,7 +977,7 @@ server->f_cur = NULL; free(buf); /* Should probably be done by RTMP_Close() ... */ - server->rc.Link.hostname.av_val = NULL; + server->rc.Link.server.host.av_val = NULL; server->rc.Link.tcUrl.av_val = NULL; server->rc.Link.swfUrl.av_val = NULL; server->rc.Link.pageUrl.av_val = NULL; Index: rtmpgw.c =================================================================== --- rtmpgw.c (revision 550) +++ rtmpgw.c (working copy) @@ -944,6 +944,7 @@ break; case 'S': STR2AVAL(req->sockshost, arg); + break; case 'q': RTMP_debuglevel = RTMP_LOGCRIT; break; Index: librtmp/rtmp.c =================================================================== --- librtmp/rtmp.c (revision 550) +++ librtmp/rtmp.c (working copy) @@ -85,6 +85,12 @@ RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE } RTMPTCmd; +typedef enum { + RTMP_HTTP_WRONG_CODE = -2, + RTMP_HTTP_BAD = -1, + RTMP_HTTP_OK = 0 +} RTMPHTTPstatus; + static int DumpMetaData(AMFObject *obj); static int HandShake(RTMP *r, int FP9HandShake); static int SocksNegotiate(RTMP *r); @@ -116,7 +122,7 @@ static void DecodeTEA(AVal *key, AVal *text); static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len); -static int HTTP_read(RTMP *r, int fill); +static RTMPHTTPstatus HTTP_read(RTMP *r, int fill); #ifndef _WIN32 static int clk_tck; @@ -338,6 +344,8 @@ int dStart, int dStop, int bLiveStream, long int timeout) { + char* http_proxy = getenv("http_proxy"); + RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]); RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val); RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port); @@ -387,20 +395,45 @@ if (socksport) hostname[socksport - sockshost->av_val] = '\0'; - r->Link.sockshost.av_val = hostname; - r->Link.sockshost.av_len = strlen(hostname); + r->Link.socksProxy.host.av_val = hostname; + r->Link.socksProxy.host.av_len = strlen(hostname); - r->Link.socksport = socksport ? atoi(socksport + 1) : 1080; - RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val, - r->Link.socksport); + r->Link.socksProxy.port = socksport ? atoi(socksport + 1) : 1080; + RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.socksProxy.host.av_val, + r->Link.socksProxy.port); } else { - r->Link.sockshost.av_val = NULL; - r->Link.sockshost.av_len = 0; - r->Link.socksport = 0; + r->Link.socksProxy.host.av_val = NULL; + r->Link.socksProxy.host.av_len = 0; + r->Link.socksProxy.port = 0; } + if(http_proxy) + { + /* skip protocol, e.g. http:// */ + char* str = strstr(http_proxy, "://"); + if(str) http_proxy = str + 3; + + const char *httpport = strchr(http_proxy, ':'); + char *hostname = strdup(http_proxy); + + if (httpport) + hostname[httpport - http_proxy] = '\0'; + r->Link.httpProxy.host.av_val = hostname; + r->Link.httpProxy.host.av_len = strlen(hostname); + + r->Link.httpProxy.port = httpport ? atoi(httpport + 1) : 80; + RTMP_Log(RTMP_LOGDEBUG, "Connecting via HTTP proxy: %s:%d", r->Link.httpProxy.host.av_val, + r->Link.httpProxy.port); + } + else + { + r->Link.httpProxy.host.av_val = NULL; + r->Link.httpProxy.host.av_len = 0; + r->Link.httpProxy.port = 0; + } + if (tcUrl && tcUrl->av_len) r->Link.tcUrl = *tcUrl; if (swfUrl && swfUrl->av_len) @@ -427,18 +460,18 @@ r->Link.timeout = timeout; r->Link.protocol = protocol; - r->Link.hostname = *host; - r->Link.port = port; + r->Link.server.host = *host; + r->Link.server.port = port; r->Link.playpath = *playpath; - if (r->Link.port == 0) + if (r->Link.server.port == 0) { if (protocol & RTMP_FEATURE_SSL) - r->Link.port = 443; + r->Link.server.port = 443; else if (protocol & RTMP_FEATURE_HTTP) - r->Link.port = 80; + r->Link.server.port = 80; else - r->Link.port = 1935; + r->Link.server.port = 1935; } } @@ -455,7 +488,7 @@ int omisc; char *use; } options[] = { - { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0, + { AVC("socks"), OFF(Link.socksProxy.host), OPT_STR, 0, "Use the specified SOCKS proxy" }, { AVC("app"), OFF(Link.app), OPT_STR, 0, "Name of target app on server" }, @@ -661,11 +694,11 @@ *ptr = '\0'; len = strlen(url); - ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname, + ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.server.host, &port, &r->Link.playpath0, &r->Link.app); if (!ret) return ret; - r->Link.port = port; + r->Link.server.port = port; r->Link.playpath = r->Link.playpath0; while (ptr) { @@ -724,14 +757,14 @@ } else { - len = r->Link.hostname.av_len + r->Link.app.av_len + + len = r->Link.server.host.av_len + r->Link.app.av_len + sizeof("rtmpte://:65535/"); r->Link.tcUrl.av_val = malloc(len); r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len, "%s://%.*s:%d/%.*s", RTMPProtocolStringsLower[r->Link.protocol], - r->Link.hostname.av_len, r->Link.hostname.av_val, - r->Link.port, + r->Link.server.host.av_len, r->Link.server.host.av_val, + r->Link.server.port, r->Link.app.av_len, r->Link.app.av_val); r->Link.lFlags |= RTMP_LF_FTCU; } @@ -748,14 +781,14 @@ (unsigned char *)r->Link.SWFHash, r->Link.swfAge); #endif - if (r->Link.port == 0) + if (r->Link.server.port == 0) { if (r->Link.protocol & RTMP_FEATURE_SSL) - r->Link.port = 443; + r->Link.server.port = 443; else if (r->Link.protocol & RTMP_FEATURE_HTTP) - r->Link.port = 80; + r->Link.server.port = 80; else - r->Link.port = 1935; + r->Link.server.port = 1935; } return TRUE; } @@ -816,7 +849,7 @@ return FALSE; } - if (r->Link.socksport) + if (r->Link.socksProxy.port) { RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__); if (!SocksNegotiate(r)) @@ -902,24 +935,26 @@ RTMP_Connect(RTMP *r, RTMPPacket *cp) { struct sockaddr_in service; - if (!r->Link.hostname.av_len) + RTMPSockInfo* sock; + + if (!r->Link.server.host.av_len) return FALSE; memset(&service, 0, sizeof(struct sockaddr_in)); service.sin_family = AF_INET; - if (r->Link.socksport) - { + if (r->Link.socksProxy.port) /* Connect via SOCKS */ - if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport)) - return FALSE; - } + sock = &r->Link.socksProxy; + else if (r->Link.httpProxy.port) + /* Connect via HTTP proxy */ + sock = &r->Link.httpProxy; else - { /* Connect directly */ - if (!add_addr_info(&service, &r->Link.hostname, r->Link.port)) + sock = &r->Link.server; + + if (!add_addr_info(&service, &sock->host, sock->port)) return FALSE; - } if (!RTMP_Connect0(r, (struct sockaddr *)&service)) return FALSE; @@ -936,14 +971,14 @@ struct sockaddr_in service; memset(&service, 0, sizeof(struct sockaddr_in)); - add_addr_info(&service, &r->Link.hostname, r->Link.port); + add_addr_info(&service, &r->Link.server.host, r->Link.server.port); addr = htonl(service.sin_addr.s_addr); { char packet[] = { 4, 1, /* SOCKS 4, connect */ - (r->Link.port >> 8) & 0xFF, - (r->Link.port) & 0xFF, + (r->Link.server.port >> 8) & 0xFF, + (r->Link.server.port) & 0xFF, (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF, (char)(addr >> 8) & 0xFF, (char)addr & 0xFF, 0 @@ -1281,7 +1319,10 @@ return 0; } } - HTTP_read(r, 0); + if(HTTP_read(r, 0) == RTMP_HTTP_WRONG_CODE) { + RTMP_Close(r); + return 0; + } } if (r->m_resplen && !r->m_sb.sb_size) RTMPSockBuf_Fill(&r->m_sb); @@ -3634,17 +3675,32 @@ HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len) { char hbuf[512]; - int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n" + char sbuf[512]; + + if(r->Link.httpProxy.port) { + /* Provide HTTP URL when using proxy */ + snprintf(sbuf, sizeof(sbuf), "http://%.*s:%d", + r->Link.server.host.av_len, r->Link.server.host.av_val, + r->Link.server.port); + } else { + sbuf[0] = '\0'; + } + + int hlen = snprintf(hbuf, sizeof(hbuf), "POST %s/%s%s/%d HTTP/1.1\r\n" "Host: %.*s:%d\r\n" "Accept: */*\r\n" "User-Agent: Shockwave Flash\n" "Connection: Keep-Alive\n" "Cache-Control: no-cache\r\n" "Content-type: application/x-fcs\r\n" - "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd], + "Content-length: %d\r\n\r\n", + sbuf, + RTMPT_cmds[cmd], r->m_clientID.av_val ? r->m_clientID.av_val : "", - r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val, - r->Link.port, len); + r->m_msgCounter, + r->Link.server.host.av_len, r->Link.server.host.av_val, + r->Link.server.port, + len); RTMPSockBuf_Send(&r->m_sb, hbuf, hlen); hlen = RTMPSockBuf_Send(&r->m_sb, buf, len); r->m_msgCounter++; @@ -3652,29 +3708,42 @@ return hlen; } -static int +static RTMPHTTPstatus HTTP_read(RTMP *r, int fill) { char *ptr; int hlen; + int type; if (fill) RTMPSockBuf_Fill(&r->m_sb); if (r->m_sb.sb_size < 144) - return -1; - if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13)) - return -1; - ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200"); + return RTMP_HTTP_BAD; + if (strncmp(r->m_sb.sb_start, "HTTP/1.1 ", 9)) { + return RTMP_HTTP_BAD; + } + ptr = r->m_sb.sb_start + 9; + if(!((ptr[0] & 0xf0) == 0x30 && + (ptr[1] & 0xf0) == 0x30 && + (ptr[2] & 0xf0) == 0x30 && + ptr[3] == ' ')) { + return RTMP_HTTP_BAD; + } + type = atoi(ptr); + if(type != 200) { /* 200 is HTTP OK */ + RTMP_Log(RTMP_LOGDEBUG, "Wrong HTTP code (got %i expected 200):\n%.*s", type, r->m_sb.sb_size, r->m_sb.sb_start); + return RTMP_HTTP_WRONG_CODE; + } while ((ptr = strstr(ptr, "Content-"))) { if (!strncasecmp(ptr+8, "length:", 7)) break; ptr += 8; } if (!ptr) - return -1; + return RTMP_HTTP_BAD; hlen = atoi(ptr+16); ptr = strstr(ptr+16, "\r\n\r\n"); if (!ptr) - return -1; + return RTMP_HTTP_BAD; ptr += 4; r->m_sb.sb_size -= ptr - r->m_sb.sb_start; r->m_sb.sb_start = ptr; @@ -3685,7 +3754,7 @@ r->m_clientID.av_len = hlen; r->m_clientID.av_val = malloc(hlen+1); if (!r->m_clientID.av_val) - return -1; + return RTMP_HTTP_BAD; r->m_clientID.av_val[0] = '/'; memcpy(r->m_clientID.av_val+1, ptr, hlen-1); r->m_clientID.av_val[hlen] = 0; @@ -3698,7 +3767,7 @@ r->m_sb.sb_start++; r->m_sb.sb_size--; } - return 0; + return RTMP_HTTP_OK; } #define MAX_IGNORED_FRAMES 50 Index: librtmp/rtmp.h =================================================================== --- librtmp/rtmp.h (revision 550) +++ librtmp/rtmp.h (working copy) @@ -114,6 +114,12 @@ void *sb_ssl; } RTMPSockBuf; + typedef struct RTMPSockInfo + { + AVal host; + unsigned short port; + } RTMPSockInfo; + void RTMPPacket_Reset(RTMPPacket *p); void RTMPPacket_Dump(RTMPPacket *p); int RTMPPacket_Alloc(RTMPPacket *p, int nSize); @@ -123,8 +129,9 @@ typedef struct RTMP_LNK { - AVal hostname; - AVal sockshost; + RTMPSockInfo server; + RTMPSockInfo socksProxy; + RTMPSockInfo httpProxy; AVal playpath0; /* parsed from URL */ AVal playpath; /* passed in explicitly */ @@ -155,9 +162,6 @@ int protocol; int timeout; /* connection timeout in seconds */ - unsigned short socksport; - unsigned short port; - #ifdef CRYPTO #define RTMP_SWF_HASHLEN 32 void *dh; /* for encryption */