diff --git a/http.c b/http.c index cbc79710..1ab57324 100644 --- a/http.c +++ b/http.c @@ -41,44 +41,7 @@ #include "strtab.h" #include "rtp.h" #include "tsmux.h" -#include "tcp.h" - -#define http_printf(x, fmt...) tcp_printf(&(x)->hc_tcp_session, fmt) - -typedef struct http_arg { - LIST_ENTRY(http_arg) link; - char *key; - char *val; -} http_arg_t; - - -typedef struct http_connection { - tcp_session_t hc_tcp_session; /* Must be first */ - char *hc_url; - int hc_keep_alive; - - LIST_HEAD(, http_arg) hc_args; - - enum { - HTTP_CON_WAIT_REQUEST, - HTTP_CON_READ_HEADER, - HTTP_CON_END, - } hc_state; - - enum { - HTTP_CMD_GET, - } hc_cmd; - - enum { - HTTP_VERSION_0_9, - HTTP_VERSION_1_0, - HTTP_VERSION_1_1, - } hc_version; - - char *hc_username; - char *hc_password; -} http_connection_t; - +#include "http.h" static struct strtab HTTP_cmdtab[] = { { "GET", HTTP_CMD_GET }, @@ -93,86 +56,6 @@ static struct strtab HTTP_versiontab[] = { }; - -/* - * Delete all arguments associated with an HTTP connection - */ -static void -http_con_flush_args(http_connection_t *hc) -{ - http_arg_t *ra; - while((ra = LIST_FIRST(&hc->hc_args)) != NULL) { - LIST_REMOVE(ra, link); - free(ra->key); - free(ra->val); - free(ra); - } -} - - -/** - * Find an argument associated with an HTTP connection - */ -static char * -http_con_get_arg(http_connection_t *hc, char *name) -{ - http_arg_t *ra; - LIST_FOREACH(ra, &hc->hc_args, link) - if(!strcasecmp(ra->key, name)) - return ra->val; - return NULL; -} - - -/** - * Set an argument associated with an HTTP connection - */ -static void -http_con_set_arg(http_connection_t *hc, char *key, char *val) -{ - http_arg_t *ra; - - LIST_FOREACH(ra, &hc->hc_args, link) - if(!strcasecmp(ra->key, key)) - break; - - if(ra == NULL) { - ra = malloc(sizeof(http_arg_t)); - LIST_INSERT_HEAD(&hc->hc_args, ra, link); - ra->key = strdup(key); - } else { - free(ra->val); - } - ra->val = strdup(val); -} - - -/* - * Split a string in components delimited by 'delimiter' - */ -static int -tokenize(char *buf, char **vec, int vecsize, int delimiter) -{ - int n = 0; - - while(1) { - while((*buf > 0 && *buf < 33) || *buf == delimiter) - buf++; - if(*buf == 0) - break; - vec[n++] = buf; - if(n == vecsize) - break; - while(*buf > 32 && *buf != delimiter) - buf++; - if(*buf == 0) - break; - *buf = 0; - buf++; - } - return n; -} - /* * HTTP status code to string */ @@ -297,7 +180,7 @@ http_process_request(http_connection_t *hc) uint8_t authbuf[150]; /* Set keep-alive status */ - v = http_con_get_arg(hc, "connection"); + v = http_arg_get(&hc->hc_args, "connection"); switch(hc->hc_version) { case HTTP_VERSION_0_9: @@ -316,11 +199,11 @@ http_process_request(http_connection_t *hc) } /* Extract authorization */ - if((v = http_con_get_arg(hc, "Authorization")) != NULL) { - if((n = tokenize(v, argv, 2, -1)) == 2) { + if((v = http_arg_get(&hc->hc_args, "Authorization")) != NULL) { + if((n = http_tokenize(v, argv, 2, -1)) == 2) { n = av_base64_decode(authbuf, argv[1], sizeof(authbuf) - 1); authbuf[n] = 0; - if((n = tokenize((char *)authbuf, argv, 2, ':')) == 2) { + if((n = http_tokenize((char *)authbuf, argv, 2, ':')) == 2) { hc->hc_username = strdup(argv[0]); hc->hc_password = strdup(argv[1]); } @@ -368,13 +251,13 @@ http_con_parse(void *aux, char *buf) switch(hc->hc_state) { case HTTP_CON_WAIT_REQUEST: - http_con_flush_args(hc); + http_arg_flush(&hc->hc_args); if(hc->hc_url != NULL) { free(hc->hc_url); hc->hc_url = NULL; } - n = tokenize(buf, argv, 3, -1); + n = http_tokenize(buf, argv, 3, -1); if(n < 2) return EBADRQC; @@ -401,7 +284,7 @@ http_con_parse(void *aux, char *buf) if(*buf == 0) /* Empty crlf line, end of header lines */ return http_process_request(hc); - n = tokenize(buf, argv, 2, -1); + n = http_tokenize(buf, argv, 2, -1); if(n < 2) break; @@ -409,7 +292,7 @@ http_con_parse(void *aux, char *buf) if(c == NULL) break; *c = 0; - http_con_set_arg(hc, argv[0], argv[1]); + http_arg_set(&hc->hc_args, argv[0], argv[1]); break; case HTTP_CON_END: @@ -425,7 +308,7 @@ http_con_parse(void *aux, char *buf) static void http_disconnect(http_connection_t *hc) { - http_con_flush_args(hc); + http_arg_flush(&hc->hc_args); free(hc->hc_url); } @@ -463,3 +346,90 @@ http_start(void) tcp_create_server(9980, sizeof(http_connection_t), "http", http_tcp_callback); } + + + + + + + + + +/* + * Delete all arguments associated with a connection + */ +void +http_arg_flush(struct http_arg_list *list) +{ + http_arg_t *ra; + while((ra = LIST_FIRST(list)) != NULL) { + LIST_REMOVE(ra, link); + free(ra->key); + free(ra->val); + free(ra); + } +} + + +/** + * Find an argument associated with a connection + */ +char * +http_arg_get(struct http_arg_list *list, char *name) +{ + http_arg_t *ra; + LIST_FOREACH(ra, list, link) + if(!strcasecmp(ra->key, name)) + return ra->val; + return NULL; +} + + +/** + * Set an argument associated with a connection + */ +void +http_arg_set(struct http_arg_list *list, char *key, char *val) +{ + http_arg_t *ra; + + LIST_FOREACH(ra, list, link) + if(!strcasecmp(ra->key, key)) + break; + + if(ra == NULL) { + ra = malloc(sizeof(http_arg_t)); + LIST_INSERT_HEAD(list, ra, link); + ra->key = strdup(key); + } else { + free(ra->val); + } + ra->val = strdup(val); +} + + +/* + * Split a string in components delimited by 'delimiter' + */ +int +http_tokenize(char *buf, char **vec, int vecsize, int delimiter) +{ + int n = 0; + + while(1) { + while((*buf > 0 && *buf < 33) || *buf == delimiter) + buf++; + if(*buf == 0) + break; + vec[n++] = buf; + if(n == vecsize) + break; + while(*buf > 32 && *buf != delimiter) + buf++; + if(*buf == 0) + break; + *buf = 0; + buf++; + } + return n; +} diff --git a/http.h b/http.h index 7db1fc76..5a61b750 100644 --- a/http.h +++ b/http.h @@ -19,6 +19,57 @@ #ifndef HTTP_H_ #define HTTP_H_ +#include "tcp.h" + +#define http_printf(x, fmt...) tcp_printf(&(x)->hc_tcp_session, fmt) + +LIST_HEAD(http_arg_list, http_arg); + +typedef struct http_arg { + LIST_ENTRY(http_arg) link; + char *key; + char *val; +} http_arg_t; + + +typedef struct http_connection { + tcp_session_t hc_tcp_session; /* Must be first */ + char *hc_url; + int hc_keep_alive; + + struct http_arg_list hc_args; + + enum { + HTTP_CON_WAIT_REQUEST, + HTTP_CON_READ_HEADER, + HTTP_CON_END, + } hc_state; + + enum { + HTTP_CMD_GET, + } hc_cmd; + + enum { + HTTP_VERSION_0_9, + HTTP_VERSION_1_0, + HTTP_VERSION_1_1, + } hc_version; + + char *hc_username; + char *hc_password; +} http_connection_t; + + + + void http_start(void); +void http_arg_flush(struct http_arg_list *list); + +char *http_arg_get(struct http_arg_list *list, char *name); + +void http_arg_set(struct http_arg_list *list, char *key, char *val); + +int http_tokenize(char *buf, char **vec, int vecsize, int delimiter); + #endif /* HTTP_H_ */ diff --git a/rtsp.c b/rtsp.c index 063defec..31055df5 100644 --- a/rtsp.c +++ b/rtsp.c @@ -40,6 +40,7 @@ #include "rtp.h" #include "tsmux.h" #include "tcp.h" +#include "http.h" #include #include @@ -88,7 +89,7 @@ typedef struct rtsp_connection { tcp_session_t rc_tcp_session; /* Must be first */ char *rc_url; - LIST_HEAD(, rtsp_arg) rc_args; + struct http_arg_list rc_args; enum { RTSP_CON_WAIT_REQUEST, @@ -257,95 +258,6 @@ rtsp_session_destroy(rtsp_session_t *rs) -/* - * Delete all arguments associated with an RTSP connection - */ -static void -rtsp_con_flush_args(rtsp_connection_t *rc) -{ - rtsp_arg_t *ra; - while((ra = LIST_FIRST(&rc->rc_args)) != NULL) { - LIST_REMOVE(ra, link); - free(ra->key); - free(ra->val); - free(ra); - } -} - - -/** - * Find an argument associated with an RTSP connection - */ -static char * -rtsp_con_get_arg(rtsp_connection_t *rc, char *name) -{ - rtsp_arg_t *ra; - LIST_FOREACH(ra, &rc->rc_args, link) - if(!strcasecmp(ra->key, name)) - return ra->val; - return NULL; -} - - -/** - * Set an argument associated with an RTSP connection - */ -static void -rtsp_con_set_arg(rtsp_connection_t *rc, char *key, char *val) -{ - rtsp_arg_t *ra; - - LIST_FOREACH(ra, &rc->rc_args, link) - if(!strcasecmp(ra->key, key)) - break; - - if(ra == NULL) { - ra = malloc(sizeof(rtsp_arg_t)); - LIST_INSERT_HEAD(&rc->rc_args, ra, link); - ra->key = strdup(key); - } else { - free(ra->val); - } - ra->val = strdup(val); -#if 0 - if(!strcasecmp(key, "User-Agent")) { - free(rc->rc_logname); - - snprintf(buf, sizeof(buf), "%s:%d [%s]", - inet_ntoa(rc->rc_from.sin_addr), ntohs(rc->rc_from.sin_port), - val); - rc->rc_logname = strdup(buf); - } -#endif -} - - -/* - * Split a string in components delimited by 'delimiter' - */ -static int -tokenize(char *buf, char **vec, int vecsize, int delimiter) -{ - int n = 0; - - while(1) { - while((*buf > 0 && *buf < 33) || *buf == delimiter) - buf++; - if(*buf == 0) - break; - vec[n++] = buf; - if(n == vecsize) - break; - while(*buf > 32 && *buf != delimiter) - buf++; - if(*buf == 0) - break; - *buf = 0; - buf++; - } - return n; -} - /* * RTSP return code to string */ @@ -384,7 +296,7 @@ rtsp_reply_error(rtsp_connection_t *rc, int error, const char *errstr) syslog(LOG_INFO, "rtsp: %s: %s", tcp_logname(&rc->rc_tcp_session), errstr); rcprintf(rc, "RTSP/1.0 %d %s\r\n", error, errstr); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n"); } @@ -406,7 +318,7 @@ rtsp_get_session(rtsp_connection_t *rc) } - if((ses = rtsp_con_get_arg(rc, "session")) == NULL) { + if((ses = http_arg_get(&rc->rc_args, "session")) == NULL) { rtsp_reply_error(rc, RTSP_STATUS_SESSION, NULL); return NULL; } @@ -438,7 +350,7 @@ rtsp_cmd_play(rtsp_connection_t *rc) if(rs == NULL) return; - if((c = rtsp_con_get_arg(rc, "range")) != NULL) { + if((c = http_arg_get(&rc->rc_args, "range")) != NULL) { start = AV_NOPTS_VALUE; } else { start = AV_NOPTS_VALUE; @@ -460,7 +372,7 @@ rtsp_cmd_play(rtsp_connection_t *rc) "Session: %u\r\n", rs->rs_id); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n"); @@ -496,7 +408,7 @@ rtsp_cmd_pause(rtsp_connection_t *rc) "Session: %u\r\n", rs->rs_id); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n"); @@ -528,17 +440,17 @@ rtsp_cmd_setup(rtsp_connection_t *rc) client_ports[0] = 0; client_ports[1] = 0; - if((t = rtsp_con_get_arg(rc, "transport")) == NULL) { + if((t = http_arg_get(&rc->rc_args, "transport")) == NULL) { rtsp_reply_error(rc, RTSP_STATUS_TRANSPORT, NULL); return; } - nt = tokenize(t, transports, 10, ','); + nt = http_tokenize(t, transports, 10, ','); /* Select a transport we can accept */ for(i = 0; i < nt; i++) { - np = tokenize(transports[i], params, 10, ';'); + np = http_tokenize(transports[i], params, 10, ';'); if(np == 0) continue; @@ -552,13 +464,13 @@ rtsp_cmd_setup(rtsp_connection_t *rc) for(j = 1; j < np; j++) { - if((navp = tokenize(params[j], avp, 2, '=')) == 0) + if((navp = http_tokenize(params[j], avp, 2, '=')) == 0) continue; if(navp == 1 && !strcmp(avp[0], "unicast")) { ismulticast = 0; } else if(navp == 2 && !strcmp(avp[0], "client_port")) { - nports = tokenize(avp[1], ports, 2, '-'); + nports = http_tokenize(avp[1], ports, 2, '-'); if(nports > 0) client_ports[0] = atoi(ports[0]); if(nports > 1) client_ports[1] = atoi(ports[1]); } @@ -594,7 +506,7 @@ rtsp_cmd_setup(rtsp_connection_t *rc) rs->rs_server_port[0], rs->rs_server_port[1]); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n"); @@ -633,7 +545,7 @@ rtsp_cmd_describe(rtsp_connection_t *rc) "Content-Length: %d\r\n", strlen(sdpreply)); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n%s", sdpreply); @@ -657,7 +569,7 @@ rtsp_cmd_options(rtsp_connection_t *rc) "RTSP/1.0 200 OK\r\n" "Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n"); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n"); } @@ -680,7 +592,7 @@ rtsp_cmd_teardown(rtsp_connection_t *rc) "Session: %u\r\n", rs->rs_id); - if((c = rtsp_con_get_arg(rc, "cseq")) != NULL) + if((c = http_arg_get(&rc->rc_args, "cseq")) != NULL) rcprintf(rc, "CSeq: %s\r\n", c); rcprintf(rc, "\r\n"); @@ -700,13 +612,13 @@ rtsp_con_parse(void *aux, char *buf) switch(rc->rc_state) { case RTSP_CON_WAIT_REQUEST: - rtsp_con_flush_args(rc); + http_arg_flush(&rc->rc_args); if(rc->rc_url != NULL) { free(rc->rc_url); rc->rc_url = NULL; } - n = tokenize(buf, argv, 3, -1); + n = http_tokenize(buf, argv, 3, -1); if(n < 3) return EBADRQC; @@ -738,7 +650,7 @@ rtsp_con_parse(void *aux, char *buf) break; } - n = tokenize(buf, argv, 2, -1); + n = http_tokenize(buf, argv, 2, -1); if(n < 2) break; @@ -746,7 +658,7 @@ rtsp_con_parse(void *aux, char *buf) if(c == NULL) break; *c = 0; - rtsp_con_set_arg(rc, argv[0], argv[1]); + http_arg_set(&rc->rc_args, argv[0], argv[1]); break; case RTSP_CON_END: @@ -764,7 +676,7 @@ rtsp_disconnect(rtsp_connection_t *rc) { rtsp_session_t *rs; - rtsp_con_flush_args(rc); + http_arg_flush(&rc->rc_args); while((rs = LIST_FIRST(&rc->rc_sessions)) != NULL) rtsp_session_destroy(rs);