rtmp协议分析---HTTP_get分析

在分析rtmpdump源代码时,发现一个http协议,感觉挺有意思的,就摘录下来。

主要是在RTMP_HashSWF函数中看到的。

HTTPResult HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
{
	char *host, *path;
	char *p1, *p2;
	char hbuf[256];
	int port = 80;
#ifdef CRYPTO
	int ssl = 0;
#endif
	int hlen, flen = 0;
	int rc, i;
	int len_known;
	HTTPResult ret = HTTPRES_OK;
	struct sockaddr_in sa;
	RTMPSockBuf sb = {0};

	http->status = -1;

	memset(&sa, 0, sizeof(struct sockaddr_in));
	sa.sin_family = AF_INET;

	/* we only handle http here */
	//判断是否是https or http
	if (strncasecmp(url, "http", 4))
		return HTTPRES_BAD_REQUEST;

	if (url[4] == 's')
	{
#ifdef CRYPTO
		ssl = 1;
		port = 443;
		if (!RTMP_TLS_ctx)
			RTMP_TLS_Init();
#else
		return HTTPRES_BAD_REQUEST;
#endif
	}

	p1 = strchr(url + 4, ':');
	if (!p1 || strncmp(p1, "://", 3))
		return HTTPRES_BAD_REQUEST;

	host = p1 + 3;
	path = strchr(host, '/');
	hlen = path - host;
	strncpy(hbuf, host, hlen);
	hbuf[hlen] = '\0';
	host = hbuf;
	p1 = strrchr(host, ':');
	if (p1)
	{
		*p1++ = '\0';
		port = atoi(p1);
	}

	sa.sin_addr.s_addr = inet_addr(host);
	if (sa.sin_addr.s_addr == INADDR_NONE)
	{
		struct hostent *hp = gethostbyname(host);
		if (!hp || !hp->h_addr)
		return HTTPRES_LOST_CONNECTION;
		sa.sin_addr = *(struct in_addr *)hp->h_addr;
	}
	sa.sin_port = htons(port);
	sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sb.sb_socket == -1)
		return HTTPRES_LOST_CONNECTION;
	i = sprintf(sb.sb_buf, "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferrer: %.*s\r\n", path, AGENT, host, (int)(path - url + 1),
	        url);
	if (http->date[0])
		i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date);
	i += sprintf(sb.sb_buf + i, "\r\n");

	if (connect(sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0)
	{
		ret = HTTPRES_LOST_CONNECTION;
		goto leave;
	}
#ifdef CRYPTO
	if (ssl)
	{
#ifdef NO_SSL
		RTMP_Log(RTMP_LOGERROR, "%s, No SSL/TLS support", __FUNCTION__);
		ret = HTTPRES_BAD_REQUEST;
		goto leave;
#else
		TLS_client(RTMP_TLS_ctx, sb.sb_ssl);
		TLS_setfd(sb.sb_ssl, sb.sb_socket);
		if ((i = TLS_connect(sb.sb_ssl)) < 0)
		{
			RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
			ret = HTTPRES_LOST_CONNECTION;
			goto leave;
		}
#endif
	}
#endif
	RTMPSockBuf_Send(&sb, sb.sb_buf, i);

	/* set timeout */
#define HTTP_TIMEOUT	5
	{
		SET_RCVTIMEO(tv, HTTP_TIMEOUT);
		if (setsockopt(sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
		{
			RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", __FUNCTION__, HTTP_TIMEOUT);
		}
	}

	sb.sb_size = 0;
	sb.sb_timedout = FALSE;
	if (RTMPSockBuf_Fill(&sb) < 1)
	{
		ret = HTTPRES_LOST_CONNECTION;
		goto leave;
	}
	if (strncmp(sb.sb_buf, "HTTP/1", 6))
	{
		ret = HTTPRES_BAD_REQUEST;
		goto leave;
	}

	p1 = strchr(sb.sb_buf, ' ');
	rc = atoi(p1 + 1);
	http->status = rc;

	if (rc >= 300)
	{
		if (rc == 304)
		{
			ret = HTTPRES_OK_NOT_MODIFIED;
			goto leave;
		}
		else if (rc == 404)
			ret = HTTPRES_NOT_FOUND;
		else if (rc >= 500)
			ret = HTTPRES_SERVER_ERROR;
		else if (rc >= 400)
			ret = HTTPRES_BAD_REQUEST;
		else
			ret = HTTPRES_REDIRECTED;
	}

	p1 = memchr(sb.sb_buf, '\n', sb.sb_size);
	if (!p1)
	{
		ret = HTTPRES_BAD_REQUEST;
		goto leave;
	}
	sb.sb_start = p1 + 1;
	sb.sb_size -= sb.sb_start - sb.sb_buf;

	while ((p2 = memchr(sb.sb_start, '\r', sb.sb_size)))
	{
		if (*sb.sb_start == '\r')
		{
			sb.sb_start += 2;
			sb.sb_size -= 2;
			break;
		}
		else if (!strncasecmp(sb.sb_start, "Content-Length: ", sizeof("Content-Length: ") - 1))
		{
			flen = atoi(sb.sb_start + sizeof("Content-Length: ") - 1);
		}
		else if (!strncasecmp(sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ") - 1))
		{
			*p2 = '\0';
			strcpy(http->date, sb.sb_start + sizeof("Last-Modified: ") - 1);
		}
		p2 += 2;
		sb.sb_size -= p2 - sb.sb_start;
		sb.sb_start = p2;
		if (sb.sb_size < 1)
		{
			if (RTMPSockBuf_Fill(&sb) < 1)
			{
				ret = HTTPRES_LOST_CONNECTION;
				goto leave;
			}
		}
	}

	len_known = flen > 0;
	while ((!len_known || flen > 0) && (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0))
	{
		cb(sb.sb_start, 1, sb.sb_size, http->data);
		if (len_known)
			flen -= sb.sb_size;
		http->size += sb.sb_size;
		sb.sb_size = 0;
	}

	if (flen > 0)
		ret = HTTPRES_LOST_CONNECTION;

	leave: RTMPSockBuf_Close(&sb);
	return ret;
}


回调函数中:

static size_t swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream)
{
	struct info *i = stream;
	char *p = ptr;
	size_t len = size * nmemb;

	if (i->first)
	{
		i->first = 0;
		/* compressed? */
		if (!strncmp(p, "CWS", 3))
		{
			*p = 'F';
			i->zlib = 1;
		}
		HMAC_crunch(i->ctx, (unsigned char * )p, 8);
		p += 8;
		len -= 8;
		i->size = 8;
	}

	if (i->zlib)
	{
		unsigned char out[CHUNK];
		i->zs->next_in = (unsigned char *)p;
		i->zs->avail_in = len;
		do
		{
			i->zs->avail_out = CHUNK;
			i->zs->next_out = out;
			inflate(i->zs, Z_NO_FLUSH);
			len = CHUNK - i->zs->avail_out;
			i->size += len;
			HMAC_crunch(i->ctx, out, len);
		} while (i->zs->avail_out == 0);
	}
	else
	{
		i->size += len;
		HMAC_crunch(i->ctx, (unsigned char * )p, len);
	}
	return size * nmemb;
}


看了一个,跟我之前写的很相似,可以用于以后的参考

你可能感兴趣的:(RTMP)