Skip to content

Commit 6832fe4

Browse files
committed
proto_ws: use thread memory for handshake headers
Partially revert e30a355 by parsing the HTTP handshake header list directly with thread memory. This removes the pkg allocator lock while retaining support for overlapping SIP and HTTP header names through the low-level scanner.
1 parent c9fb284 commit 6832fe4

3 files changed

Lines changed: 73 additions & 42 deletions

File tree

‎modules/proto_ws/ws_handshake_common.h‎

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
#ifndef _WS_HANDSHAKE_H_
2727
#define _WS_HANDSHAKE_H_
2828

29-
#include <pthread.h>
30-
3129
#include "../../ip_addr.h"
3230

3331
#define HTTP_SEP "\r\n"
@@ -121,21 +119,60 @@ static int complete_ws_trace( struct tcp_connection* conn, trans_trace_status st
121119
#define WS_TRACE_MAX 1024
122120
static char ws_trace_buf[WS_TRACE_MAX];
123121

124-
static pthread_mutex_t ws_http_parse_lock = PTHREAD_MUTEX_INITIALIZER;
122+
static inline int ws_parse_headers(struct sip_msg *msg)
123+
{
124+
struct hdr_field *hf;
125+
char *tmp, *rest, *end;
126+
127+
tmp = msg->unparsed;
128+
end = msg->buf + msg->len;
129+
130+
while (tmp < end) {
131+
hf = thread_malloc(sizeof *hf);
132+
if (!hf) {
133+
LM_ERR("thread memory allocation failed\n");
134+
return -1;
135+
}
136+
137+
memset(hf, 0, sizeof *hf);
138+
hf->type = HDR_ERROR_T;
139+
rest = get_hdr_field_aux(tmp, end, hf, 0);
140+
141+
if (hf->type == HDR_ERROR_T) {
142+
LM_INFO("bad header field\n");
143+
thread_free(hf);
144+
return -1;
145+
}
146+
147+
if (hf->type == HDR_EOH_T) {
148+
msg->eoh = tmp;
149+
msg->unparsed = tmp;
150+
thread_free(hf);
151+
return 0;
152+
}
153+
154+
if (!msg->headers)
155+
msg->headers = hf;
156+
else
157+
msg->last_header->next = hf;
158+
msg->last_header = hf;
159+
tmp = rest;
160+
}
161+
162+
msg->unparsed = tmp;
163+
return 0;
164+
}
125165

126-
/*
127-
* The handshake is parsed on a TCP IO thread, with the core SIP parser, which
128-
* allocates the header list from the process' pkg memory. pkg memory is not
129-
* thread safe, so ws_http_parse_lock must cover both the parsing and the
130-
* release of that list - releasing it unlocked races with another thread
131-
* parsing (and allocating) at the same time.
132-
*/
133166
static inline void ws_free_parsed_headers(struct sip_msg *msg)
134167
{
135-
pthread_mutex_lock(&ws_http_parse_lock);
136-
free_hdr_field_lst(msg->headers);
168+
struct hdr_field *hf, *next;
169+
170+
for (hf = msg->headers; hf; hf = next) {
171+
next = hf->next;
172+
thread_free(hf);
173+
}
137174
msg->headers = NULL;
138-
pthread_mutex_unlock(&ws_http_parse_lock);
175+
msg->last_header = NULL;
139176
}
140177

141178
/* safety checks */
@@ -810,13 +847,10 @@ static int ws_parse_req_handshake(struct tcp_connection *c, char *msg, int len)
810847
memset(&tmp_msg, 0, sizeof(struct sip_msg));
811848
tmp_msg.len = len;
812849
tmp_msg.buf = tmp_msg.unparsed = msg;
813-
pthread_mutex_lock(&ws_http_parse_lock);
814-
if (parse_headers_aux(&tmp_msg, HDR_EOH_F, 0,0) < 0) {
815-
pthread_mutex_unlock(&ws_http_parse_lock);
850+
if (ws_parse_headers(&tmp_msg) < 0) {
816851
LM_ERR("cannot parse headers\n%.*s\n", len, msg);
817852
goto ws_error;
818853
}
819-
pthread_mutex_unlock(&ws_http_parse_lock);
820854
/* verify headers according to RFC6455 */
821855
for (hf = tmp_msg.headers; hf; hf = hf->next) {
822856
if (hf->type != HDR_OTHER_T)
@@ -1091,13 +1125,10 @@ static int ws_parse_rpl_handshake(struct tcp_connection *c, char *msg, int len)
10911125
memset(&tmp_msg, 0, sizeof(struct sip_msg));
10921126
tmp_msg.len = len;
10931127
tmp_msg.buf = tmp_msg.unparsed = msg;
1094-
pthread_mutex_lock(&ws_http_parse_lock);
1095-
if (parse_headers_aux(&tmp_msg, HDR_EOH_F, 0, 0) < 0) {
1096-
pthread_mutex_unlock(&ws_http_parse_lock);
1128+
if (ws_parse_headers(&tmp_msg) < 0) {
10971129
LM_ERR("cannot parse headers\n%.*s\n", len, msg);
10981130
goto ws_error;
10991131
}
1100-
pthread_mutex_unlock(&ws_http_parse_lock);
11011132
/* verify headers according to RFC6455 */
11021133
for (hf = tmp_msg.headers; hf; hf = hf->next) {
11031134
if (hf->type != HDR_OTHER_T)

‎parser/msg_parser.c‎

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ char* get_hdr_field_aux(char* buf, char* end, struct hdr_field* hdr,int sip_well
108108
case HDR_VIA_T:
109109
/* keep number of vias parsed -- we want to report it in
110110
replies for diagnostic purposes */
111-
via_cnt++;
111+
if (sip_well_known_parse)
112+
via_cnt++;
112113
if (sip_well_known_parse) {
113114
vb=pkg_malloc(sizeof(struct via_body));
114115
if (vb==0){
@@ -356,12 +357,15 @@ char* get_hdr_field_aux(char* buf, char* end, struct hdr_field* hdr,int sip_well
356357
return tmp;
357358

358359
error_bad_hdr:
359-
set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM,
360-
"error parsing headers");
361-
set_err_reply(400, "bad headers");
360+
if (sip_well_known_parse) {
361+
set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM,
362+
"error parsing headers");
363+
set_err_reply(400, "bad headers");
364+
}
362365
error:
363366
LM_DBG("error exit\n");
364-
update_stat( bad_msg_hdr, 1);
367+
if (sip_well_known_parse)
368+
update_stat(bad_msg_hdr, 1);
365369
hdr->type=HDR_ERROR_T;
366370
hdr->len=tmp-hdr->name.s;
367371
return tmp;
@@ -379,7 +383,7 @@ char* get_hdr_field_aux(char* buf, char* end, struct hdr_field* hdr,int sip_well
379383
give you the first occurrence of a header you are interested in,
380384
look at check_transaction_quadruple
381385
*/
382-
int parse_headers_aux(struct sip_msg* msg, hdr_flags_t flags, int next, int sip_well_known_parse)
386+
int parse_headers(struct sip_msg *msg, hdr_flags_t flags, int next)
383387
{
384388
struct hdr_field *hf;
385389
char* tmp;
@@ -408,7 +412,7 @@ int parse_headers_aux(struct sip_msg* msg, hdr_flags_t flags, int next, int sip_
408412
}
409413
memset(hf,0, sizeof(struct hdr_field));
410414
hf->type=HDR_ERROR_T;
411-
rest=get_hdr_field_aux(tmp, msg->buf+msg->len, hf,sip_well_known_parse);
415+
rest=get_hdr_field_aux(tmp, msg->buf+msg->len, hf, 1);
412416
switch (hf->type){
413417
case HDR_ERROR_T:
414418
LM_INFO("bad header field\n");
@@ -590,21 +594,19 @@ int parse_headers_aux(struct sip_msg* msg, hdr_flags_t flags, int next, int sip_
590594
link_sibling_hdr(h_via1,hf);
591595
msg->parsed_flag|=HDR_VIA_F;
592596
LM_DBG("via found, flags=%llx\n", (unsigned long long)flags);
593-
if (sip_well_known_parse) {
594-
if (msg->via1==0) {
595-
LM_DBG("this is the first via\n");
596-
msg->h_via1=hf;
597-
msg->via1=hf->parsed;
598-
if (msg->via1->next){
599-
msg->via2=msg->via1->next;
600-
msg->parsed_flag|=HDR_VIA2_F;
601-
}
602-
} else
597+
if (msg->via1==0) {
598+
LM_DBG("this is the first via\n");
599+
msg->h_via1=hf;
600+
msg->via1=hf->parsed;
601+
if (msg->via1->next){
602+
msg->via2=msg->via1->next;
603+
msg->parsed_flag|=HDR_VIA2_F;
604+
}
605+
} else
603606
if (msg->via2==0) {
604607
msg->via2=hf->parsed;
605608
msg->parsed_flag|=HDR_VIA2_F;
606609
}
607-
}
608610
break;
609611
case HDR_FEATURE_CAPS_T:
610612
link_sibling_hdr(feature_caps, hf);

‎parser/msg_parser.h‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,7 @@ extern int sdp_get_custom_body(struct sip_msg *msg, str *body);
377377
int parse_msg_opt(char* buf, unsigned int len, struct sip_msg* msg,
378378
int free_on_err);
379379

380-
#define parse_headers(msg, flags,next) parse_headers_aux(msg,flags,next, 1)
381-
382-
int parse_headers_aux(struct sip_msg* msg, hdr_flags_t flags, int next, int sip_well_known_parse);
380+
int parse_headers(struct sip_msg *msg, hdr_flags_t flags, int next);
383381

384382
#define get_hdr_field(buf,end,hdr) get_hdr_field_aux(buf,end,hdr,1)
385383

0 commit comments

Comments
 (0)