8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libsip / common / sip_parse_generic.c
blob98f459b1b0094141a0d9c339283564e5c2c91f9a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <strings.h>
33 #include <ctype.h>
34 #include <sip.h>
36 #include "sip_miscdefs.h"
37 #include "sip_msg.h"
38 #include "sip_parse_uri.h"
41 * atoi function from a header
43 int
44 sip_atoi(_sip_header_t *sip_header, int *num)
46 boolean_t num_found = B_FALSE;
48 *num = 0;
49 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
50 if (isspace(*sip_header->sip_hdr_current)) {
51 sip_header->sip_hdr_current++;
52 if (num_found)
53 break;
54 } else if (isdigit(*sip_header->sip_hdr_current)) {
55 *num = (*num * 10) +
56 (*sip_header->sip_hdr_current - '0');
57 num_found = B_TRUE;
58 sip_header->sip_hdr_current++;
59 } else {
60 break;
63 if (!num_found)
64 return (EINVAL);
65 return (0);
69 * Find the 'token'
71 int
72 sip_find_token(_sip_header_t *sip_header, char token)
74 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
75 if (token != SIP_COMMA &&
76 *sip_header->sip_hdr_current == SIP_COMMA) {
77 sip_header->sip_hdr_current--;
78 return (1);
80 if (*sip_header->sip_hdr_current++ == token) {
82 * sip_hdr_current points to the char
83 * after the token
85 return (0);
88 return (1);
92 * Find a carriage-return
94 int
95 sip_find_cr(_sip_header_t *sip_header)
97 sip_header->sip_hdr_current = sip_header->sip_hdr_end;
98 while (*sip_header->sip_hdr_current-- != '\n') {
99 if (sip_header->sip_hdr_current == sip_header->sip_hdr_start)
100 return (1);
102 return (0);
106 * Find one of the separator provided, i.e. separator_1st or separator_2nd or
107 * separator_3rd.
110 sip_find_separator(_sip_header_t *sip_header, char separator_1st,
111 char separator_2nd, char separator_3rd, boolean_t ignore_space)
113 assert(separator_1st != (char)NULL || separator_2nd != (char)NULL);
114 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
115 if (ignore_space && (*sip_header->sip_hdr_current == SIP_SP)) {
116 sip_header->sip_hdr_current++;
117 continue;
119 if (isspace(*sip_header->sip_hdr_current) ||
120 (separator_1st != (char)NULL &&
121 (*sip_header->sip_hdr_current == separator_1st)) ||
122 (separator_2nd != (char)NULL &&
123 (*sip_header->sip_hdr_current == separator_2nd)) ||
124 (separator_3rd != (char)NULL &&
125 (*sip_header->sip_hdr_current == separator_3rd))) {
126 return (0);
129 * If we have escape character, go to the next char
131 if (*sip_header->sip_hdr_current == '\\')
132 sip_header->sip_hdr_current++;
133 sip_header->sip_hdr_current++;
135 return (1);
139 * Return when we hit a white space
142 sip_find_white_space(_sip_header_t *sip_header)
144 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
145 if (isspace(*sip_header->sip_hdr_current))
146 return (0);
147 sip_header->sip_hdr_current++;
149 return (1);
153 * Skip to the next non-whitespace
156 sip_skip_white_space(_sip_header_t *sip_header)
158 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
159 if (!isspace(*sip_header->sip_hdr_current))
160 return (0);
161 sip_header->sip_hdr_current++;
163 return (1);
168 * Skip to the non-white space in the reverse direction
171 sip_reverse_skip_white_space(_sip_header_t *sip_header)
173 while (sip_header->sip_hdr_current >= sip_header->sip_hdr_start) {
174 if (!isspace(*sip_header->sip_hdr_current))
175 return (0);
176 sip_header->sip_hdr_current--;
178 return (1);
182 * get to the first non space after ':'
185 sip_parse_goto_values(_sip_header_t *sip_header)
187 if (sip_find_token(sip_header, SIP_HCOLON) != 0)
188 return (1);
189 if (sip_skip_white_space(sip_header) != 0)
190 return (1);
192 return (0);
196 * Skip the current value.
199 sip_goto_next_value(_sip_header_t *sip_header)
201 boolean_t quoted = B_FALSE;
203 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
204 if (*sip_header->sip_hdr_current == SIP_QUOTE) {
205 if (quoted)
206 quoted = B_FALSE;
207 else
208 quoted = B_TRUE;
209 } else if (!quoted &&
210 *sip_header->sip_hdr_current == SIP_COMMA) {
212 * value ends before the COMMA
214 sip_header->sip_hdr_current--;
215 return (0);
217 sip_header->sip_hdr_current++;
219 if (quoted)
220 return (1);
221 return (0);
225 * Parse the header into parameter list. Parameters start with a ';'
228 sip_parse_params(_sip_header_t *sip_header, sip_param_t **parsed_list)
230 sip_param_t *param = NULL;
231 sip_param_t *new_param;
232 char *tmp_ptr;
234 if (parsed_list == NULL)
235 return (0);
237 *parsed_list = NULL;
238 for (;;) {
239 boolean_t quoted_name = B_FALSE;
242 * First check if there are any params
244 if (sip_skip_white_space(sip_header) != 0)
245 return (0);
246 if (*sip_header->sip_hdr_current != SIP_SEMI)
247 return (0);
249 sip_header->sip_hdr_current++;
251 new_param = calloc(1, sizeof (sip_param_t));
252 if (new_param == NULL)
253 return (ENOMEM);
255 if (param != NULL)
256 param->param_next = new_param;
257 else
258 *parsed_list = new_param;
260 param = new_param;
263 * Let's get to the start of the param name
265 if (sip_skip_white_space(sip_header) != 0)
266 return (EPROTO);
268 * start of param name
270 tmp_ptr = sip_header->sip_hdr_current;
271 param->param_name.sip_str_ptr = tmp_ptr;
273 if (sip_find_separator(sip_header, SIP_EQUAL, SIP_SEMI,
274 SIP_COMMA, B_FALSE) != 0) {
275 param->param_name.sip_str_len =
276 sip_header->sip_hdr_current - tmp_ptr;
277 param->param_value.sip_str_ptr = NULL;
278 param->param_value.sip_str_len = 0;
279 return (0);
283 * End of param name
285 param->param_name.sip_str_len =
286 sip_header->sip_hdr_current - tmp_ptr;
288 if (sip_skip_white_space(sip_header) != 0 ||
289 *sip_header->sip_hdr_current == SIP_COMMA) {
290 param->param_value.sip_str_ptr = NULL;
291 param->param_value.sip_str_len = 0;
292 return (0);
294 if (*sip_header->sip_hdr_current == SIP_SEMI) {
295 param->param_value.sip_str_ptr = NULL;
296 param->param_value.sip_str_len = 0;
297 continue;
299 assert(*sip_header->sip_hdr_current == SIP_EQUAL);
302 * We are at EQUAL, lets go beyond that
304 sip_header->sip_hdr_current++;
306 if (sip_skip_white_space(sip_header) != 0)
307 return (EPROTO);
309 if (*sip_header->sip_hdr_current == SIP_QUOTE) {
310 sip_header->sip_hdr_current++;
311 quoted_name = B_TRUE;
315 * start of param value
317 param->param_value.sip_str_ptr = sip_header->sip_hdr_current;
318 tmp_ptr = sip_header->sip_hdr_current;
320 if (quoted_name && sip_find_token(sip_header, SIP_QUOTE) != 0) {
321 return (EPROTO);
322 } else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA,
323 (char)NULL, B_FALSE) != 0) {
324 return (EPROTO);
326 param->param_value.sip_str_len = sip_header->sip_hdr_current -
327 tmp_ptr;
328 if (quoted_name)
329 param->param_value.sip_str_len--;
334 * a header that only has "header_name : " is an empty header
335 * ":" must exist
336 * sip_hdr_current resets to sip_hdr_start before exit
338 boolean_t
339 sip_is_empty_hdr(_sip_header_t *sip_header)
341 if (sip_find_token(sip_header, SIP_HCOLON) != 0) {
342 sip_header->sip_hdr_current = sip_header->sip_hdr_start;
343 return (B_FALSE);
346 if (sip_skip_white_space(sip_header) == 0) {
347 sip_header->sip_hdr_current = sip_header->sip_hdr_start;
348 return (B_FALSE);
351 sip_header->sip_hdr_current = sip_header->sip_hdr_start;
352 return (B_TRUE);
356 * Parsing an empty header, i.e. only has a ":"
359 sip_parse_hdr_empty(_sip_header_t *hdr, sip_parsed_header_t **phdr)
361 sip_parsed_header_t *parsed_header;
363 if (hdr == NULL || phdr == NULL)
364 return (EINVAL);
367 * check if already parsed
369 if (hdr->sip_hdr_parsed != NULL) {
370 *phdr = hdr->sip_hdr_parsed;
371 return (0);
374 *phdr = NULL;
376 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
377 if (parsed_header == NULL)
378 return (ENOMEM);
379 parsed_header->sip_header = hdr;
381 parsed_header->value = NULL;
383 *phdr = parsed_header;
384 return (0);
388 * validate uri str and parse uri using uri_parse()
390 static void
391 sip_parse_uri_str(sip_str_t *sip_str, sip_hdr_value_t *value)
393 int error;
396 * Parse uri
398 if (sip_str->sip_str_len > 0) {
399 value->sip_value_parsed_uri = sip_parse_uri(sip_str, &error);
400 if (value->sip_value_parsed_uri == NULL)
401 return;
402 if (error != 0 ||
403 value->sip_value_parsed_uri->sip_uri_errflags != 0) {
404 value->sip_value_state = SIP_VALUE_BAD;
410 * Some basic common checks before parsing the headers
413 sip_prim_parsers(_sip_header_t *sip_header, sip_parsed_header_t **header)
415 if (sip_header == NULL || header == NULL)
416 return (EINVAL);
419 * check if already parsed
421 if (sip_header->sip_hdr_parsed != NULL) {
422 *header = sip_header->sip_hdr_parsed;
423 return (0);
425 *header = NULL;
427 assert(sip_header->sip_hdr_start == sip_header->sip_hdr_current);
429 if (sip_parse_goto_values(sip_header) != 0)
430 return (EPROTO);
432 return (0);
436 * Parse SIP/2.0 string
439 sip_get_protocol_version(_sip_header_t *sip_header,
440 sip_proto_version_t *sip_proto_version)
442 if (sip_skip_white_space(sip_header) != 0)
443 return (1);
445 if (strncasecmp(sip_header->sip_hdr_current, SIP, strlen(SIP)) == 0) {
446 sip_proto_version->name.sip_str_ptr =
447 sip_header->sip_hdr_current;
448 sip_proto_version->name.sip_str_len = strlen(SIP);
450 if (sip_find_token(sip_header, SIP_SLASH) != 0)
451 return (1);
452 if (sip_skip_white_space(sip_header) != 0)
453 return (1);
455 sip_proto_version->version.sip_str_ptr =
456 sip_header->sip_hdr_current;
457 while (isdigit(*sip_header->sip_hdr_current)) {
458 sip_header->sip_hdr_current++;
459 if (sip_header->sip_hdr_current >=
460 sip_header->sip_hdr_end) {
461 return (1);
464 if (*sip_header->sip_hdr_current != SIP_PERIOD)
465 return (1);
466 sip_header->sip_hdr_current++;
468 if (!isdigit(*sip_header->sip_hdr_current))
469 return (1);
470 while (isdigit(*sip_header->sip_hdr_current)) {
471 sip_header->sip_hdr_current++;
472 if (sip_header->sip_hdr_current >=
473 sip_header->sip_hdr_end) {
474 return (1);
478 sip_proto_version->version.sip_str_len =
479 sip_header->sip_hdr_current -
480 sip_proto_version->version.sip_str_ptr;
481 return (0);
483 return (1);
487 * parser1 parses hdr format
488 * header_name: val1[; par1=pval1;par2=pval2 ..][, val2[;parlist..] ]
489 * val can be str1/str2 or str
490 * headers: Accept, Accept-Encode, Accept-lang, Allow, Content-disp,
491 * Content-Encode, Content-Lang, In-reply-to,
492 * Priority, Require, Supported, Unsupported
493 * Allow-Events, Event, Subscription-State
496 sip_parse_hdr_parser1(_sip_header_t *hdr, sip_parsed_header_t **phdr, char sep)
498 sip_parsed_header_t *parsed_header;
499 int ret;
500 sip_hdr_value_t *value = NULL;
501 sip_hdr_value_t *last_value = NULL;
503 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
504 return (ret);
507 * check if previously parsed
509 if (*phdr != NULL) {
510 hdr->sip_hdr_parsed = *phdr;
511 return (0);
514 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
515 if (parsed_header == NULL)
516 return (ENOMEM);
517 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
518 parsed_header->sip_header = hdr;
520 while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
521 value = calloc(1, sizeof (sip_hdr_value_t));
522 if (value == NULL) {
523 sip_free_phdr(parsed_header);
524 return (ENOMEM);
526 if (last_value != NULL)
527 last_value->sip_next_value = value;
528 else
529 parsed_header->value = (sip_value_t *)value;
531 value->sip_value_start = hdr->sip_hdr_current;
532 value->sip_value_header = parsed_header;
534 if (sip_find_separator(hdr, sep, SIP_COMMA, SIP_SEMI,
535 B_FALSE) == 0) {
536 char c = *hdr->sip_hdr_current;
538 if (isspace(c) && sep == (char)NULL) {
539 value->str_val_ptr = value->sip_value_start;
540 value->str_val_len = hdr->sip_hdr_current -
541 value->sip_value_start;
543 * nothing at the end except space
545 if (sip_skip_white_space(hdr) != 0) {
546 value->sip_value_end =
547 hdr->sip_hdr_current;
548 goto end;
551 * white space skipped
553 c = *(hdr->sip_hdr_current);
557 * only one string until COMMA, use sip_str_t
559 if (c == SIP_COMMA) {
560 char *t = hdr->sip_hdr_current;
562 hdr->sip_hdr_current--;
563 (void) sip_reverse_skip_white_space(hdr);
564 value->str_val_ptr = value->sip_value_start;
565 value->str_val_len = hdr->sip_hdr_current -
566 value->sip_value_start + 1;
567 hdr->sip_hdr_current = t;
568 goto get_next_val;
572 * two strings, use sip_2strs_t
574 if ((sep != (char)NULL) && (c == sep)) {
575 value->strs1_val_ptr = value->sip_value_start;
576 value->strs1_val_len = hdr->sip_hdr_current -
577 value->sip_value_start;
579 value->strs2_val_ptr =
580 (++hdr->sip_hdr_current);
581 if (sip_find_separator(hdr, SIP_SEMI, SIP_COMMA,
582 (char)NULL, B_FALSE) == 0) {
583 char t = *(hdr->sip_hdr_current);
584 value->strs2_val_len =
585 hdr->sip_hdr_current -
586 value->strs2_val_ptr;
588 * if COMMA, no param list, get next val
589 * if SEMI, need to set params list
591 if (t == SIP_COMMA)
592 goto get_next_val;
593 } else { /* the last part */
594 value->strs2_val_len =
595 hdr->sip_hdr_current -
596 value->strs2_val_ptr;
597 value->sip_value_end =
598 hdr->sip_hdr_current;
599 goto end;
601 } else if (sep != (char)NULL) {
602 value->sip_value_state = SIP_VALUE_BAD;
603 goto get_next_val;
607 * c == SEMI, value contains single string
608 * only one string until SEMI, use sip_str_t
610 if (c == SIP_SEMI) {
611 char *t = hdr->sip_hdr_current;
613 hdr->sip_hdr_current--;
615 * get rid of SP at end of value field
617 (void) sip_reverse_skip_white_space(hdr);
618 value->str_val_ptr = value->sip_value_start;
619 value->str_val_len = hdr->sip_hdr_current -
620 value->str_val_ptr + 1;
621 hdr->sip_hdr_current = t;
625 * if SEMI exists in the value, set params list
626 * two situations, there is or not SLASH before SEMI
628 ret = sip_parse_params(hdr, &value->sip_param_list);
629 if (ret == EPROTO) {
630 value->sip_value_state = SIP_VALUE_BAD;
631 } else if (ret != 0) {
632 sip_free_phdr(parsed_header);
633 return (ret);
635 goto get_next_val;
636 } else {
637 value->str_val_ptr = value->sip_value_start;
638 value->str_val_len = hdr->sip_hdr_current -
639 value->sip_value_start;
640 value->sip_value_end = hdr->sip_hdr_current;
641 goto end;
643 get_next_val:
644 if (sip_find_token(hdr, SIP_COMMA) != 0) {
645 value->sip_value_end = hdr->sip_hdr_current;
646 break;
648 value->sip_value_end = hdr->sip_hdr_current - 1;
649 last_value = value;
650 (void) sip_skip_white_space(hdr);
653 end:
654 *phdr = parsed_header;
655 hdr->sip_hdr_parsed = *phdr;
656 return (0);
660 * header_name: int
661 * headers: Expires, Min-Expires
663 /* ARGSUSED */
665 sip_parse_hdr_parser2(_sip_header_t *hdr, sip_parsed_header_t **phdr,
666 int val_type)
668 sip_parsed_header_t *parsed_header;
669 int ret = 0;
670 sip_hdr_value_t *value = NULL;
672 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
673 return (ret);
676 * check if previously parsed
678 if (*phdr != NULL) {
679 hdr->sip_hdr_parsed = *phdr;
680 return (0);
682 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
683 if (parsed_header == NULL)
684 return (ENOMEM);
685 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
686 parsed_header->sip_header = hdr;
688 value = calloc(1, sizeof (sip_hdr_value_t));
689 if (value == NULL) {
690 sip_free_phdr(parsed_header);
691 return (ENOMEM);
694 parsed_header->value = (sip_value_t *)value;
696 value->sip_value_start = hdr->sip_hdr_current;
697 value->sip_value_header = parsed_header;
699 ret = sip_atoi(hdr, &value->int_val);
700 if (ret != 0) {
701 value->int_val = 0;
702 value->sip_value_state = SIP_VALUE_BAD;
705 value->sip_value_end = hdr->sip_hdr_current - 1;
707 *phdr = parsed_header;
708 hdr->sip_hdr_parsed = *phdr;
709 return (0);
713 * parser3 parses hdr format
714 * header_name: <val1>[, <val2>]
715 * Alert-Info, Call-Info, Error-Info, reply-to
718 sip_parse_hdr_parser3(_sip_header_t *hdr, sip_parsed_header_t **phdr, int type,
719 boolean_t parse_uri)
721 sip_parsed_header_t *parsed_header;
722 sip_hdr_value_t *value = NULL;
723 sip_hdr_value_t *last_value = NULL;
724 int ret;
726 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
727 return (ret);
730 * check if previously parsed
732 if (*phdr != NULL) {
733 hdr->sip_hdr_parsed = *phdr;
734 return (0);
736 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
737 if (parsed_header == NULL)
738 return (ENOMEM);
739 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
740 parsed_header->sip_header = hdr;
741 while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
742 int r;
744 value = calloc(1, sizeof (sip_hdr_value_t));
745 if (value == NULL) {
746 sip_free_phdr(parsed_header);
747 return (ENOMEM);
750 if (last_value != NULL)
751 last_value->sip_next_value = value;
752 else
753 parsed_header->value = (sip_value_t *)value;
755 value->sip_value_start = hdr->sip_hdr_current;
756 value->sip_value_header = parsed_header;
758 if (type == SIP_STRS_VAL) {
759 if (sip_find_token(hdr, SIP_LAQUOT) == 0) {
760 char *cur;
763 * record the position after LAQUOT
765 cur = hdr->sip_hdr_current;
767 * get display name and store in str1
769 hdr->sip_hdr_current = value->sip_value_start;
770 if (*(hdr->sip_hdr_current) != SIP_LAQUOT) {
772 * record start pos of display name
774 char *tmp = hdr->sip_hdr_current;
776 if (*hdr->sip_hdr_current ==
777 SIP_QUOTE) {
778 hdr->sip_hdr_current++;
779 tmp++;
780 if (sip_find_token(hdr,
781 SIP_QUOTE) != 0) {
782 value->sip_value_state =
783 SIP_VALUE_BAD;
784 goto get_next_val;
786 hdr->sip_hdr_current -= 2;
787 } else {
788 hdr->sip_hdr_current = cur - 2;
789 (void)
790 sip_reverse_skip_white_space
791 (hdr);
793 value->strs1_val_ptr = tmp;
794 value->strs1_val_len =
795 hdr->sip_hdr_current - tmp + 1;
796 } else {
797 value->strs1_val_ptr = NULL;
798 value->strs1_val_len = 0;
802 * set current to the char after LAQUOT
804 hdr->sip_hdr_current = cur;
805 value->strs2_val_ptr = hdr->sip_hdr_current;
806 if (sip_find_token(hdr, SIP_RAQUOT)) {
808 * no RAQUOT
810 value->strs1_val_ptr = NULL;
811 value->strs1_val_len = 0;
812 value->strs2_val_ptr = NULL;
813 value->strs2_val_len = 0;
814 value->sip_value_state = SIP_VALUE_BAD;
815 goto get_next_val;
817 value->strs2_val_len = hdr->sip_hdr_current -
818 value->strs2_val_ptr - 1;
819 } else {
820 char *cur;
823 * No display name - Only URI.
825 value->strs1_val_ptr = NULL;
826 value->strs1_val_len = 0;
827 cur = value->sip_value_start;
828 hdr->sip_hdr_current = cur;
829 if (sip_find_separator(hdr, SIP_COMMA,
830 (char)NULL, (char)NULL, B_FALSE) != 0) {
831 value->strs2_val_ptr = cur;
832 value->strs2_val_len =
833 hdr->sip_hdr_current -
834 value->strs2_val_ptr - 1;
835 } else if (*hdr->sip_hdr_current == SIP_SP) {
836 value->strs2_val_ptr = cur;
837 cur = hdr->sip_hdr_current - 1;
838 if (sip_skip_white_space(hdr) != 0) {
839 value->strs2_val_len = cur -
840 value->strs2_val_ptr - 1;
841 } else if (*hdr->sip_hdr_current ==
842 SIP_COMMA) {
843 value->strs2_val_len = cur -
844 value->strs2_val_ptr - 1;
845 } else {
846 value->sip_value_state =
847 SIP_VALUE_BAD;
848 goto get_next_val;
850 } else {
851 value->strs2_val_ptr = cur;
852 value->strs2_val_len =
853 hdr->sip_hdr_current -
854 value->strs2_val_ptr;
857 if (parse_uri)
858 sip_parse_uri_str(&value->strs_s2, value);
861 if (type == SIP_STR_VAL) {
863 * alert-info, error-info, call-info
865 if (sip_find_token(hdr, SIP_LAQUOT) == 0) {
866 value->str_val_ptr = hdr->sip_hdr_current;
867 if (sip_find_token(hdr, SIP_RAQUOT) == 0) {
868 value->str_val_len =
869 hdr->sip_hdr_current -
870 value->str_val_ptr - 1;
871 } else {
872 value->str_val_ptr = NULL;
873 value->str_val_len = 0;
874 value->sip_value_state = SIP_VALUE_BAD;
875 goto get_next_val;
877 hdr->sip_hdr_current--;
878 } else {
879 value->str_val_ptr = NULL;
880 value->str_val_len = 0;
881 value->sip_value_state = SIP_VALUE_BAD;
882 goto get_next_val;
884 if (parse_uri)
885 sip_parse_uri_str(&value->str_val, value);
888 r = sip_find_separator(hdr, SIP_COMMA, SIP_SEMI, (char)NULL,
889 B_FALSE);
890 if (r != 0) {
891 value->sip_value_end = hdr->sip_hdr_current;
892 goto end;
894 if (*hdr->sip_hdr_current == SIP_SEMI) {
895 (void) sip_parse_params(hdr,
896 &(value->sip_param_list));
897 goto get_next_val;
900 if (*hdr->sip_hdr_current == SIP_COMMA) {
901 hdr->sip_hdr_current--;
902 goto get_next_val;
904 get_next_val:
905 if (sip_find_token(hdr, SIP_COMMA) != 0) {
906 value->sip_value_end = hdr->sip_hdr_current;
907 break;
909 value->sip_value_end = hdr->sip_hdr_current - 1;
910 last_value = value;
911 (void) sip_skip_white_space(hdr);
914 end:
915 *phdr = parsed_header;
916 hdr->sip_hdr_parsed = *phdr;
917 return (0);
921 * parser4 parses hdr format, the whole field is one single str
922 * header: Subject, MIME-Version, Organization, Server, User-Agent
925 sip_parse_hdr_parser4(_sip_header_t *hdr, sip_parsed_header_t **phdr)
927 sip_parsed_header_t *parsed_header;
928 sip_hdr_value_t *value = NULL;
929 int ret;
931 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
932 return (ret);
935 * check if previously parsed
937 if (*phdr != NULL) {
938 hdr->sip_hdr_parsed = *phdr;
939 return (0);
941 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
942 if (parsed_header == NULL)
943 return (ENOMEM);
944 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
945 parsed_header->sip_header = hdr;
947 value = calloc(1, sizeof (sip_hdr_value_t));
948 if (value == NULL) {
949 sip_free_phdr(parsed_header);
950 return (ENOMEM);
953 parsed_header->value = (sip_value_t *)value;
955 value->sip_value_start = hdr->sip_hdr_current;
956 value->sip_value_header = parsed_header;
958 value->str_val_ptr = hdr->sip_hdr_current;
960 * get rid of CRLF at end
962 value->str_val_len = hdr->sip_hdr_end - value->str_val_ptr - 2;
963 value->sip_value_end = hdr->sip_hdr_end;
965 *phdr = parsed_header;
966 hdr->sip_hdr_parsed = *phdr;
967 return (0);
971 sip_parse_hdr_parser5(_sip_header_t *hdr, sip_parsed_header_t **phdr,
972 boolean_t parse_uri)
974 sip_parsed_header_t *parsed_header;
975 sip_hdr_value_t *value = NULL;
976 sip_param_t *tmp_param;
977 boolean_t first_param = B_TRUE;
978 int ret;
980 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
981 return (ret);
984 * check if previously parsed
986 if (*phdr != NULL) {
987 hdr->sip_hdr_parsed = *phdr;
988 return (0);
990 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
991 if (parsed_header == NULL)
992 return (ENOMEM);
993 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
994 parsed_header->sip_header = hdr;
996 value = calloc(1, sizeof (sip_hdr_value_t));
997 if (value == NULL) {
998 sip_free_phdr(parsed_header);
999 return (ENOMEM);
1002 parsed_header->value = (sip_value_t *)value;
1004 value->sip_value_start = hdr->sip_hdr_current;
1005 value->auth_scheme_ptr = value->sip_value_start;
1006 value->sip_value_header = parsed_header;
1008 * get auth_scheme
1010 if (sip_find_white_space(hdr)) {
1011 value->sip_value_state = SIP_VALUE_BAD;
1012 return (EINVAL);
1014 value->auth_scheme_len = hdr->sip_hdr_current - value->auth_scheme_ptr;
1016 tmp_param = value->auth_param;
1019 * parse auth_param
1021 for (;;) {
1022 char *tmp_cur;
1023 boolean_t quoted_name = B_FALSE;
1024 char quoted_char = (char)0;
1025 sip_param_t *new_param;
1026 boolean_t pval_is_uri = B_FALSE;
1028 if (sip_skip_white_space(hdr) != 0) {
1029 value->sip_value_state = SIP_VALUE_BAD;
1030 return (EPROTO);
1032 tmp_cur = hdr->sip_hdr_current;
1034 new_param = calloc(1, sizeof (sip_param_t));
1035 if (new_param == NULL)
1036 return (ENOMEM);
1038 if (first_param == B_FALSE)
1039 tmp_param->param_next = new_param;
1040 else
1041 value->auth_param = new_param;
1043 tmp_param = new_param;
1044 tmp_param->param_name.sip_str_ptr = tmp_cur;
1046 if (sip_find_separator(hdr, SIP_EQUAL, SIP_COMMA, (char)NULL,
1047 B_FALSE) != 0) {
1048 tmp_param->param_name.sip_str_len =
1049 hdr->sip_hdr_current - tmp_cur;
1050 tmp_param->param_value.sip_str_ptr = NULL;
1051 tmp_param->param_value.sip_str_len = 0;
1052 value->sip_value_end = hdr->sip_hdr_current;
1053 goto end;
1057 * End of param name
1059 tmp_param->param_name.sip_str_len = hdr->sip_hdr_current -
1060 tmp_cur;
1062 if (sip_skip_white_space(hdr) != 0 ||
1063 *hdr->sip_hdr_current == SIP_COMMA) {
1064 tmp_param->param_value.sip_str_ptr = NULL;
1065 tmp_param->param_value.sip_str_len = 0;
1066 continue;
1070 * We are at EQUAL
1072 hdr->sip_hdr_current++;
1074 if (sip_skip_white_space(hdr) != 0) {
1075 value->sip_value_state = SIP_VALUE_BAD;
1076 free(tmp_param);
1077 return (EPROTO);
1080 if (*hdr->sip_hdr_current == SIP_QUOTE ||
1081 *hdr->sip_hdr_current == SIP_LAQUOT) {
1082 if (*hdr->sip_hdr_current == SIP_QUOTE)
1083 quoted_char = SIP_QUOTE;
1084 else {
1085 quoted_char = SIP_RAQUOT;
1086 pval_is_uri = B_TRUE;
1088 hdr->sip_hdr_current++;
1089 quoted_name = B_TRUE;
1093 * start of param value
1095 tmp_cur = hdr->sip_hdr_current;
1096 tmp_param->param_value.sip_str_ptr = tmp_cur;
1097 if (quoted_name) {
1098 if (sip_find_token(hdr, quoted_char) != 0) {
1099 value->sip_value_state = SIP_VALUE_BAD;
1100 free(tmp_param);
1101 return (EPROTO);
1103 tmp_param->param_value.sip_str_len =
1104 hdr->sip_hdr_current - tmp_cur - 1;
1107 if (sip_find_token(hdr, SIP_COMMA) != 0) {
1108 value->sip_value_end = hdr->sip_hdr_current;
1109 goto end;
1110 } else {
1111 if (!quoted_name) {
1112 char *t = hdr->sip_hdr_current;
1113 hdr->sip_hdr_current--;
1114 (void) sip_reverse_skip_white_space(hdr);
1115 tmp_param->param_value.sip_str_len =
1116 hdr->sip_hdr_current - tmp_cur;
1117 hdr->sip_hdr_current = t;
1121 if (first_param == B_TRUE)
1122 first_param = B_FALSE;
1125 * Parse uri
1127 if (pval_is_uri && parse_uri)
1128 sip_parse_uri_str(&tmp_param->param_value, value);
1132 end:
1133 *phdr = parsed_header;
1134 hdr->sip_hdr_parsed = *phdr;
1135 return (0);
1139 * Return the URI in the request startline
1141 static int
1142 _sip_get_request_uri(_sip_header_t *sip_header, sip_message_type_t *msg_info)
1144 int size = 0;
1145 char *start_ptr;
1147 if (sip_skip_white_space(sip_header) != 0)
1148 return (EINVAL);
1149 start_ptr = sip_header->sip_hdr_current;
1151 while (!isspace(*sip_header->sip_hdr_current)) {
1152 if (sip_header->sip_hdr_current >= sip_header->sip_hdr_end)
1153 return (EINVAL);
1154 sip_header->sip_hdr_current++;
1157 size = sip_header->sip_hdr_current - start_ptr;
1159 msg_info->U.sip_request.sip_request_uri.sip_str_ptr = start_ptr;
1160 msg_info->U.sip_request.sip_request_uri.sip_str_len = size;
1161 if (size > 0) { /* Parse uri */
1162 int error;
1164 msg_info->U.sip_request.sip_parse_uri = sip_parse_uri(
1165 &msg_info->U.sip_request.sip_request_uri, &error);
1166 if (msg_info->U.sip_request.sip_parse_uri == NULL)
1167 return (error);
1169 return (0);
1173 * Parse the start line into request/response
1176 sip_parse_first_line(_sip_header_t *sip_header, sip_message_type_t **msg_info)
1178 sip_message_type_t *sip_msg_info;
1179 boolean_t sip_is_request = B_TRUE;
1180 int ret;
1182 if (sip_header == NULL || msg_info == NULL)
1183 return (EINVAL);
1185 if (sip_skip_white_space(sip_header) != 0)
1186 return (EPROTO);
1189 * There is nothing, return
1191 if (sip_header->sip_hdr_current + strlen(SIP_VERSION) >=
1192 sip_header->sip_hdr_end) {
1193 return (EPROTO);
1195 #ifdef __solaris__
1196 assert(mutex_held(&sip_header->sip_hdr_sipmsg->sip_msg_mutex));
1197 #endif
1198 sip_msg_info = malloc(sizeof (sip_message_type_t));
1199 if (sip_msg_info == NULL)
1200 return (ENOMEM);
1203 * let's see if it's a request or a response
1205 ret = sip_get_protocol_version(sip_header,
1206 &sip_msg_info->sip_proto_version);
1207 if (ret == 0) {
1208 sip_is_request = B_FALSE;
1209 } else if (ret == 2) {
1210 free(sip_msg_info);
1211 return (EPROTO);
1214 if (sip_skip_white_space(sip_header) != 0) {
1215 free(sip_msg_info);
1216 return (EPROTO);
1219 if (!sip_is_request) {
1221 * check for status code.
1223 if (sip_skip_white_space(sip_header) != 0) {
1224 free(sip_msg_info);
1225 return (EPROTO);
1227 if (sip_header->sip_hdr_current + SIP_SIZE_OF_STATUS_CODE >=
1228 sip_header->sip_hdr_end) {
1229 free(sip_msg_info);
1230 return (EPROTO);
1233 if (sip_atoi(sip_header,
1234 &sip_msg_info->U.sip_response.sip_response_code)) {
1235 free(sip_msg_info);
1236 return (EPROTO);
1239 if (sip_msg_info->U.sip_response.sip_response_code < 100 ||
1240 sip_msg_info->U.sip_response.sip_response_code > 700) {
1241 free(sip_msg_info);
1242 return (EPROTO);
1246 * get reason phrase.
1248 if (sip_skip_white_space(sip_header) != 0) {
1249 sip_msg_info->sip_resp_phrase_len = 0;
1250 sip_msg_info->sip_resp_phrase_ptr = NULL;
1251 } else {
1252 sip_msg_info->sip_resp_phrase_ptr =
1253 sip_header->sip_hdr_current;
1254 if (sip_find_cr(sip_header) != 0) {
1255 free(sip_msg_info);
1256 return (EPROTO);
1258 sip_msg_info->sip_resp_phrase_len =
1259 sip_header->sip_hdr_current -
1260 sip_msg_info->sip_resp_phrase_ptr;
1262 sip_msg_info->is_request = B_FALSE;
1263 } else {
1264 int i;
1266 * It's a request.
1268 sip_msg_info->is_request = B_TRUE;
1269 for (i = 1; i < MAX_SIP_METHODS; i++) {
1270 if (strncmp(sip_methods[i].name,
1271 sip_header->sip_hdr_current,
1272 sip_methods[i].len) == 0) {
1273 sip_msg_info->sip_req_method = i;
1274 sip_header->sip_hdr_current +=
1275 sip_methods[i].len;
1276 if (!isspace(*sip_header->sip_hdr_current++) ||
1277 !isalpha(*sip_header->sip_hdr_current)) {
1278 free(sip_msg_info);
1279 return (EPROTO);
1282 if ((ret = _sip_get_request_uri(sip_header,
1283 sip_msg_info)) != 0) {
1284 free(sip_msg_info);
1285 return (ret);
1289 * Get SIP version
1291 ret = sip_get_protocol_version(sip_header,
1292 &sip_msg_info->sip_proto_version);
1293 if (ret != 0) {
1294 free(sip_msg_info);
1295 return (EPROTO);
1297 goto done;
1300 free(sip_msg_info);
1301 return (EPROTO);
1303 done:
1304 sip_msg_info->sip_next = *msg_info;
1305 *msg_info = sip_msg_info;
1306 return (0);