libc: make stdio_impl.h an internal libc header
[unleashed/tickless.git] / usr / src / lib / libsip / common / sip_parse_generic.c
blobdb4b4ba49b8b7f1608efb9b965b16904d7e19496
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 #include <stdlib.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <strings.h>
31 #include <ctype.h>
32 #include <sip.h>
34 #include "sip_miscdefs.h"
35 #include "sip_msg.h"
36 #include "sip_parse_uri.h"
39 * atoi function from a header
41 int
42 sip_atoi(_sip_header_t *sip_header, int *num)
44 boolean_t num_found = B_FALSE;
46 *num = 0;
47 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
48 if (isspace(*sip_header->sip_hdr_current)) {
49 sip_header->sip_hdr_current++;
50 if (num_found)
51 break;
52 } else if (isdigit(*sip_header->sip_hdr_current)) {
53 *num = (*num * 10) +
54 (*sip_header->sip_hdr_current - '0');
55 num_found = B_TRUE;
56 sip_header->sip_hdr_current++;
57 } else {
58 break;
61 if (!num_found)
62 return (EINVAL);
63 return (0);
67 * Find the 'token'
69 int
70 sip_find_token(_sip_header_t *sip_header, char token)
72 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
73 if (token != SIP_COMMA &&
74 *sip_header->sip_hdr_current == SIP_COMMA) {
75 sip_header->sip_hdr_current--;
76 return (1);
78 if (*sip_header->sip_hdr_current++ == token) {
80 * sip_hdr_current points to the char
81 * after the token
83 return (0);
86 return (1);
90 * Find a carriage-return
92 int
93 sip_find_cr(_sip_header_t *sip_header)
95 sip_header->sip_hdr_current = sip_header->sip_hdr_end;
96 while (*sip_header->sip_hdr_current-- != '\n') {
97 if (sip_header->sip_hdr_current == sip_header->sip_hdr_start)
98 return (1);
100 return (0);
104 * Find one of the separator provided, i.e. separator_1st or separator_2nd or
105 * separator_3rd.
108 sip_find_separator(_sip_header_t *sip_header, char separator_1st,
109 char separator_2nd, char separator_3rd, boolean_t ignore_space)
111 assert(separator_1st != SIP_NUL || separator_2nd != SIP_NUL);
112 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
113 if (ignore_space && (*sip_header->sip_hdr_current == SIP_SP)) {
114 sip_header->sip_hdr_current++;
115 continue;
117 if (isspace(*sip_header->sip_hdr_current) ||
118 (separator_1st != SIP_NUL &&
119 (*sip_header->sip_hdr_current == separator_1st)) ||
120 (separator_2nd != SIP_NUL &&
121 (*sip_header->sip_hdr_current == separator_2nd)) ||
122 (separator_3rd != SIP_NUL &&
123 (*sip_header->sip_hdr_current == separator_3rd))) {
124 return (0);
127 * If we have escape character, go to the next char
129 if (*sip_header->sip_hdr_current == '\\')
130 sip_header->sip_hdr_current++;
131 sip_header->sip_hdr_current++;
133 return (1);
137 * Return when we hit a white space
140 sip_find_white_space(_sip_header_t *sip_header)
142 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
143 if (isspace(*sip_header->sip_hdr_current))
144 return (0);
145 sip_header->sip_hdr_current++;
147 return (1);
151 * Skip to the next non-whitespace
154 sip_skip_white_space(_sip_header_t *sip_header)
156 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
157 if (!isspace(*sip_header->sip_hdr_current))
158 return (0);
159 sip_header->sip_hdr_current++;
161 return (1);
166 * Skip to the non-white space in the reverse direction
169 sip_reverse_skip_white_space(_sip_header_t *sip_header)
171 while (sip_header->sip_hdr_current >= sip_header->sip_hdr_start) {
172 if (!isspace(*sip_header->sip_hdr_current))
173 return (0);
174 sip_header->sip_hdr_current--;
176 return (1);
180 * get to the first non space after ':'
183 sip_parse_goto_values(_sip_header_t *sip_header)
185 if (sip_find_token(sip_header, SIP_HCOLON) != 0)
186 return (1);
187 if (sip_skip_white_space(sip_header) != 0)
188 return (1);
190 return (0);
194 * Skip the current value.
197 sip_goto_next_value(_sip_header_t *sip_header)
199 boolean_t quoted = B_FALSE;
201 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
202 if (*sip_header->sip_hdr_current == SIP_QUOTE) {
203 if (quoted)
204 quoted = B_FALSE;
205 else
206 quoted = B_TRUE;
207 } else if (!quoted &&
208 *sip_header->sip_hdr_current == SIP_COMMA) {
210 * value ends before the COMMA
212 sip_header->sip_hdr_current--;
213 return (0);
215 sip_header->sip_hdr_current++;
217 if (quoted)
218 return (1);
219 return (0);
223 * Parse the header into parameter list. Parameters start with a ';'
226 sip_parse_params(_sip_header_t *sip_header, sip_param_t **parsed_list)
228 sip_param_t *param = NULL;
229 sip_param_t *new_param;
230 char *tmp_ptr;
232 if (parsed_list == NULL)
233 return (0);
235 *parsed_list = NULL;
236 for (;;) {
237 boolean_t quoted_name = B_FALSE;
240 * First check if there are any params
242 if (sip_skip_white_space(sip_header) != 0)
243 return (0);
244 if (*sip_header->sip_hdr_current != SIP_SEMI)
245 return (0);
247 sip_header->sip_hdr_current++;
249 new_param = calloc(1, sizeof (sip_param_t));
250 if (new_param == NULL)
251 return (ENOMEM);
253 if (param != NULL)
254 param->param_next = new_param;
255 else
256 *parsed_list = new_param;
258 param = new_param;
261 * Let's get to the start of the param name
263 if (sip_skip_white_space(sip_header) != 0)
264 return (EPROTO);
266 * start of param name
268 tmp_ptr = sip_header->sip_hdr_current;
269 param->param_name.sip_str_ptr = tmp_ptr;
271 if (sip_find_separator(sip_header, SIP_EQUAL, SIP_SEMI,
272 SIP_COMMA, B_FALSE) != 0) {
273 param->param_name.sip_str_len =
274 sip_header->sip_hdr_current - tmp_ptr;
275 param->param_value.sip_str_ptr = NULL;
276 param->param_value.sip_str_len = 0;
277 return (0);
281 * End of param name
283 param->param_name.sip_str_len =
284 sip_header->sip_hdr_current - tmp_ptr;
286 if (sip_skip_white_space(sip_header) != 0 ||
287 *sip_header->sip_hdr_current == SIP_COMMA) {
288 param->param_value.sip_str_ptr = NULL;
289 param->param_value.sip_str_len = 0;
290 return (0);
292 if (*sip_header->sip_hdr_current == SIP_SEMI) {
293 param->param_value.sip_str_ptr = NULL;
294 param->param_value.sip_str_len = 0;
295 continue;
297 assert(*sip_header->sip_hdr_current == SIP_EQUAL);
300 * We are at EQUAL, lets go beyond that
302 sip_header->sip_hdr_current++;
304 if (sip_skip_white_space(sip_header) != 0)
305 return (EPROTO);
307 if (*sip_header->sip_hdr_current == SIP_QUOTE) {
308 sip_header->sip_hdr_current++;
309 quoted_name = B_TRUE;
313 * start of param value
315 param->param_value.sip_str_ptr = sip_header->sip_hdr_current;
316 tmp_ptr = sip_header->sip_hdr_current;
318 if (quoted_name && sip_find_token(sip_header, SIP_QUOTE) != 0) {
319 return (EPROTO);
320 } else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA,
321 SIP_NUL, B_FALSE) != 0) {
322 return (EPROTO);
324 param->param_value.sip_str_len = sip_header->sip_hdr_current -
325 tmp_ptr;
326 if (quoted_name)
327 param->param_value.sip_str_len--;
332 * a header that only has "header_name : " is an empty header
333 * ":" must exist
334 * sip_hdr_current resets to sip_hdr_start before exit
336 boolean_t
337 sip_is_empty_hdr(_sip_header_t *sip_header)
339 if (sip_find_token(sip_header, SIP_HCOLON) != 0) {
340 sip_header->sip_hdr_current = sip_header->sip_hdr_start;
341 return (B_FALSE);
344 if (sip_skip_white_space(sip_header) == 0) {
345 sip_header->sip_hdr_current = sip_header->sip_hdr_start;
346 return (B_FALSE);
349 sip_header->sip_hdr_current = sip_header->sip_hdr_start;
350 return (B_TRUE);
354 * Parsing an empty header, i.e. only has a ":"
357 sip_parse_hdr_empty(_sip_header_t *hdr, sip_parsed_header_t **phdr)
359 sip_parsed_header_t *parsed_header;
361 if (hdr == NULL || phdr == NULL)
362 return (EINVAL);
365 * check if already parsed
367 if (hdr->sip_hdr_parsed != NULL) {
368 *phdr = hdr->sip_hdr_parsed;
369 return (0);
372 *phdr = NULL;
374 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
375 if (parsed_header == NULL)
376 return (ENOMEM);
377 parsed_header->sip_header = hdr;
379 parsed_header->value = NULL;
381 *phdr = parsed_header;
382 return (0);
386 * validate uri str and parse uri using uri_parse()
388 static void
389 sip_parse_uri_str(sip_str_t *sip_str, sip_hdr_value_t *value)
391 int error;
394 * Parse uri
396 if (sip_str->sip_str_len > 0) {
397 value->sip_value_parsed_uri = sip_parse_uri(sip_str, &error);
398 if (value->sip_value_parsed_uri == NULL)
399 return;
400 if (error != 0 ||
401 value->sip_value_parsed_uri->sip_uri_errflags != 0) {
402 value->sip_value_state = SIP_VALUE_BAD;
408 * Some basic common checks before parsing the headers
411 sip_prim_parsers(_sip_header_t *sip_header, sip_parsed_header_t **header)
413 if (sip_header == NULL || header == NULL)
414 return (EINVAL);
417 * check if already parsed
419 if (sip_header->sip_hdr_parsed != NULL) {
420 *header = sip_header->sip_hdr_parsed;
421 return (0);
423 *header = NULL;
425 assert(sip_header->sip_hdr_start == sip_header->sip_hdr_current);
427 if (sip_parse_goto_values(sip_header) != 0)
428 return (EPROTO);
430 return (0);
434 * Parse SIP/2.0 string
437 sip_get_protocol_version(_sip_header_t *sip_header,
438 sip_proto_version_t *sip_proto_version)
440 if (sip_skip_white_space(sip_header) != 0)
441 return (1);
443 if (strncasecmp(sip_header->sip_hdr_current, SIP, strlen(SIP)) == 0) {
444 sip_proto_version->name.sip_str_ptr =
445 sip_header->sip_hdr_current;
446 sip_proto_version->name.sip_str_len = strlen(SIP);
448 if (sip_find_token(sip_header, SIP_SLASH) != 0)
449 return (1);
450 if (sip_skip_white_space(sip_header) != 0)
451 return (1);
453 sip_proto_version->version.sip_str_ptr =
454 sip_header->sip_hdr_current;
455 while (isdigit(*sip_header->sip_hdr_current)) {
456 sip_header->sip_hdr_current++;
457 if (sip_header->sip_hdr_current >=
458 sip_header->sip_hdr_end) {
459 return (1);
462 if (*sip_header->sip_hdr_current != SIP_PERIOD)
463 return (1);
464 sip_header->sip_hdr_current++;
466 if (!isdigit(*sip_header->sip_hdr_current))
467 return (1);
468 while (isdigit(*sip_header->sip_hdr_current)) {
469 sip_header->sip_hdr_current++;
470 if (sip_header->sip_hdr_current >=
471 sip_header->sip_hdr_end) {
472 return (1);
476 sip_proto_version->version.sip_str_len =
477 sip_header->sip_hdr_current -
478 sip_proto_version->version.sip_str_ptr;
479 return (0);
481 return (1);
485 * parser1 parses hdr format
486 * header_name: val1[; par1=pval1;par2=pval2 ..][, val2[;parlist..] ]
487 * val can be str1/str2 or str
488 * headers: Accept, Accept-Encode, Accept-lang, Allow, Content-disp,
489 * Content-Encode, Content-Lang, In-reply-to,
490 * Priority, Require, Supported, Unsupported
491 * Allow-Events, Event, Subscription-State
494 sip_parse_hdr_parser1(_sip_header_t *hdr, sip_parsed_header_t **phdr, char sep)
496 sip_parsed_header_t *parsed_header;
497 int ret;
498 sip_hdr_value_t *value = NULL;
499 sip_hdr_value_t *last_value = NULL;
501 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
502 return (ret);
505 * check if previously parsed
507 if (*phdr != NULL) {
508 hdr->sip_hdr_parsed = *phdr;
509 return (0);
512 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
513 if (parsed_header == NULL)
514 return (ENOMEM);
515 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
516 parsed_header->sip_header = hdr;
518 while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
519 value = calloc(1, sizeof (sip_hdr_value_t));
520 if (value == NULL) {
521 sip_free_phdr(parsed_header);
522 return (ENOMEM);
524 if (last_value != NULL)
525 last_value->sip_next_value = value;
526 else
527 parsed_header->value = (sip_value_t *)value;
529 value->sip_value_start = hdr->sip_hdr_current;
530 value->sip_value_header = parsed_header;
532 if (sip_find_separator(hdr, sep, SIP_COMMA, SIP_SEMI,
533 B_FALSE) == 0) {
534 char c = *hdr->sip_hdr_current;
536 if (isspace(c) && sep == SIP_NUL) {
537 value->str_val_ptr = value->sip_value_start;
538 value->str_val_len = hdr->sip_hdr_current -
539 value->sip_value_start;
541 * nothing at the end except space
543 if (sip_skip_white_space(hdr) != 0) {
544 value->sip_value_end =
545 hdr->sip_hdr_current;
546 goto end;
549 * white space skipped
551 c = *(hdr->sip_hdr_current);
555 * only one string until COMMA, use sip_str_t
557 if (c == SIP_COMMA) {
558 char *t = hdr->sip_hdr_current;
560 hdr->sip_hdr_current--;
561 (void) sip_reverse_skip_white_space(hdr);
562 value->str_val_ptr = value->sip_value_start;
563 value->str_val_len = hdr->sip_hdr_current -
564 value->sip_value_start + 1;
565 hdr->sip_hdr_current = t;
566 goto get_next_val;
570 * two strings, use sip_2strs_t
572 if ((sep != SIP_NUL) && (c == sep)) {
573 value->strs1_val_ptr = value->sip_value_start;
574 value->strs1_val_len = hdr->sip_hdr_current -
575 value->sip_value_start;
577 value->strs2_val_ptr =
578 (++hdr->sip_hdr_current);
579 if (sip_find_separator(hdr, SIP_SEMI, SIP_COMMA,
580 SIP_NUL, B_FALSE) == 0) {
581 char t = *(hdr->sip_hdr_current);
582 value->strs2_val_len =
583 hdr->sip_hdr_current -
584 value->strs2_val_ptr;
586 * if COMMA, no param list, get next val
587 * if SEMI, need to set params list
589 if (t == SIP_COMMA)
590 goto get_next_val;
591 } else { /* the last part */
592 value->strs2_val_len =
593 hdr->sip_hdr_current -
594 value->strs2_val_ptr;
595 value->sip_value_end =
596 hdr->sip_hdr_current;
597 goto end;
599 } else if (sep != SIP_NUL) {
600 value->sip_value_state = SIP_VALUE_BAD;
601 goto get_next_val;
605 * c == SEMI, value contains single string
606 * only one string until SEMI, use sip_str_t
608 if (c == SIP_SEMI) {
609 char *t = hdr->sip_hdr_current;
611 hdr->sip_hdr_current--;
613 * get rid of SP at end of value field
615 (void) sip_reverse_skip_white_space(hdr);
616 value->str_val_ptr = value->sip_value_start;
617 value->str_val_len = hdr->sip_hdr_current -
618 value->str_val_ptr + 1;
619 hdr->sip_hdr_current = t;
623 * if SEMI exists in the value, set params list
624 * two situations, there is or not SLASH before SEMI
626 ret = sip_parse_params(hdr, &value->sip_param_list);
627 if (ret == EPROTO) {
628 value->sip_value_state = SIP_VALUE_BAD;
629 } else if (ret != 0) {
630 sip_free_phdr(parsed_header);
631 return (ret);
633 goto get_next_val;
634 } else {
635 value->str_val_ptr = value->sip_value_start;
636 value->str_val_len = hdr->sip_hdr_current -
637 value->sip_value_start;
638 value->sip_value_end = hdr->sip_hdr_current;
639 goto end;
641 get_next_val:
642 if (sip_find_token(hdr, SIP_COMMA) != 0) {
643 value->sip_value_end = hdr->sip_hdr_current;
644 break;
646 value->sip_value_end = hdr->sip_hdr_current - 1;
647 last_value = value;
648 (void) sip_skip_white_space(hdr);
651 end:
652 *phdr = parsed_header;
653 hdr->sip_hdr_parsed = *phdr;
654 return (0);
658 * header_name: int
659 * headers: Expires, Min-Expires
661 /* ARGSUSED */
663 sip_parse_hdr_parser2(_sip_header_t *hdr, sip_parsed_header_t **phdr,
664 int val_type)
666 sip_parsed_header_t *parsed_header;
667 int ret = 0;
668 sip_hdr_value_t *value = NULL;
670 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
671 return (ret);
674 * check if previously parsed
676 if (*phdr != NULL) {
677 hdr->sip_hdr_parsed = *phdr;
678 return (0);
680 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
681 if (parsed_header == NULL)
682 return (ENOMEM);
683 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
684 parsed_header->sip_header = hdr;
686 value = calloc(1, sizeof (sip_hdr_value_t));
687 if (value == NULL) {
688 sip_free_phdr(parsed_header);
689 return (ENOMEM);
692 parsed_header->value = (sip_value_t *)value;
694 value->sip_value_start = hdr->sip_hdr_current;
695 value->sip_value_header = parsed_header;
697 ret = sip_atoi(hdr, &value->int_val);
698 if (ret != 0) {
699 value->int_val = 0;
700 value->sip_value_state = SIP_VALUE_BAD;
703 value->sip_value_end = hdr->sip_hdr_current - 1;
705 *phdr = parsed_header;
706 hdr->sip_hdr_parsed = *phdr;
707 return (0);
711 * parser3 parses hdr format
712 * header_name: <val1>[, <val2>]
713 * Alert-Info, Call-Info, Error-Info, reply-to
716 sip_parse_hdr_parser3(_sip_header_t *hdr, sip_parsed_header_t **phdr, int type,
717 boolean_t parse_uri)
719 sip_parsed_header_t *parsed_header;
720 sip_hdr_value_t *value = NULL;
721 sip_hdr_value_t *last_value = NULL;
722 int ret;
724 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
725 return (ret);
728 * check if previously parsed
730 if (*phdr != NULL) {
731 hdr->sip_hdr_parsed = *phdr;
732 return (0);
734 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
735 if (parsed_header == NULL)
736 return (ENOMEM);
737 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
738 parsed_header->sip_header = hdr;
739 while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
740 int r;
742 value = calloc(1, sizeof (sip_hdr_value_t));
743 if (value == NULL) {
744 sip_free_phdr(parsed_header);
745 return (ENOMEM);
748 if (last_value != NULL)
749 last_value->sip_next_value = value;
750 else
751 parsed_header->value = (sip_value_t *)value;
753 value->sip_value_start = hdr->sip_hdr_current;
754 value->sip_value_header = parsed_header;
756 if (type == SIP_STRS_VAL) {
757 if (sip_find_token(hdr, SIP_LAQUOT) == 0) {
758 char *cur;
761 * record the position after LAQUOT
763 cur = hdr->sip_hdr_current;
765 * get display name and store in str1
767 hdr->sip_hdr_current = value->sip_value_start;
768 if (*(hdr->sip_hdr_current) != SIP_LAQUOT) {
770 * record start pos of display name
772 char *tmp = hdr->sip_hdr_current;
774 if (*hdr->sip_hdr_current ==
775 SIP_QUOTE) {
776 hdr->sip_hdr_current++;
777 tmp++;
778 if (sip_find_token(hdr,
779 SIP_QUOTE) != 0) {
780 value->sip_value_state =
781 SIP_VALUE_BAD;
782 goto get_next_val;
784 hdr->sip_hdr_current -= 2;
785 } else {
786 hdr->sip_hdr_current = cur - 2;
787 (void)
788 sip_reverse_skip_white_space
789 (hdr);
791 value->strs1_val_ptr = tmp;
792 value->strs1_val_len =
793 hdr->sip_hdr_current - tmp + 1;
794 } else {
795 value->strs1_val_ptr = NULL;
796 value->strs1_val_len = 0;
800 * set current to the char after LAQUOT
802 hdr->sip_hdr_current = cur;
803 value->strs2_val_ptr = hdr->sip_hdr_current;
804 if (sip_find_token(hdr, SIP_RAQUOT)) {
806 * no RAQUOT
808 value->strs1_val_ptr = NULL;
809 value->strs1_val_len = 0;
810 value->strs2_val_ptr = NULL;
811 value->strs2_val_len = 0;
812 value->sip_value_state = SIP_VALUE_BAD;
813 goto get_next_val;
815 value->strs2_val_len = hdr->sip_hdr_current -
816 value->strs2_val_ptr - 1;
817 } else {
818 char *cur;
821 * No display name - Only URI.
823 value->strs1_val_ptr = NULL;
824 value->strs1_val_len = 0;
825 cur = value->sip_value_start;
826 hdr->sip_hdr_current = cur;
827 if (sip_find_separator(hdr, SIP_COMMA,
828 SIP_NUL, SIP_NUL, B_FALSE) != 0) {
829 value->strs2_val_ptr = cur;
830 value->strs2_val_len =
831 hdr->sip_hdr_current -
832 value->strs2_val_ptr - 1;
833 } else if (*hdr->sip_hdr_current == SIP_SP) {
834 value->strs2_val_ptr = cur;
835 cur = hdr->sip_hdr_current - 1;
836 if (sip_skip_white_space(hdr) != 0) {
837 value->strs2_val_len = cur -
838 value->strs2_val_ptr - 1;
839 } else if (*hdr->sip_hdr_current ==
840 SIP_COMMA) {
841 value->strs2_val_len = cur -
842 value->strs2_val_ptr - 1;
843 } else {
844 value->sip_value_state =
845 SIP_VALUE_BAD;
846 goto get_next_val;
848 } else {
849 value->strs2_val_ptr = cur;
850 value->strs2_val_len =
851 hdr->sip_hdr_current -
852 value->strs2_val_ptr;
855 if (parse_uri)
856 sip_parse_uri_str(&value->strs_s2, value);
859 if (type == SIP_STR_VAL) {
861 * alert-info, error-info, call-info
863 if (sip_find_token(hdr, SIP_LAQUOT) == 0) {
864 value->str_val_ptr = hdr->sip_hdr_current;
865 if (sip_find_token(hdr, SIP_RAQUOT) == 0) {
866 value->str_val_len =
867 hdr->sip_hdr_current -
868 value->str_val_ptr - 1;
869 } else {
870 value->str_val_ptr = NULL;
871 value->str_val_len = 0;
872 value->sip_value_state = SIP_VALUE_BAD;
873 goto get_next_val;
875 hdr->sip_hdr_current--;
876 } else {
877 value->str_val_ptr = NULL;
878 value->str_val_len = 0;
879 value->sip_value_state = SIP_VALUE_BAD;
880 goto get_next_val;
882 if (parse_uri)
883 sip_parse_uri_str(&value->str_val, value);
886 r = sip_find_separator(hdr, SIP_COMMA, SIP_SEMI, SIP_NUL,
887 B_FALSE);
888 if (r != 0) {
889 value->sip_value_end = hdr->sip_hdr_current;
890 goto end;
892 if (*hdr->sip_hdr_current == SIP_SEMI) {
893 (void) sip_parse_params(hdr,
894 &(value->sip_param_list));
895 goto get_next_val;
898 if (*hdr->sip_hdr_current == SIP_COMMA) {
899 hdr->sip_hdr_current--;
900 goto get_next_val;
902 get_next_val:
903 if (sip_find_token(hdr, SIP_COMMA) != 0) {
904 value->sip_value_end = hdr->sip_hdr_current;
905 break;
907 value->sip_value_end = hdr->sip_hdr_current - 1;
908 last_value = value;
909 (void) sip_skip_white_space(hdr);
912 end:
913 *phdr = parsed_header;
914 hdr->sip_hdr_parsed = *phdr;
915 return (0);
919 * parser4 parses hdr format, the whole field is one single str
920 * header: Subject, MIME-Version, Organization, Server, User-Agent
923 sip_parse_hdr_parser4(_sip_header_t *hdr, sip_parsed_header_t **phdr)
925 sip_parsed_header_t *parsed_header;
926 sip_hdr_value_t *value = NULL;
927 int ret;
929 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
930 return (ret);
933 * check if previously parsed
935 if (*phdr != NULL) {
936 hdr->sip_hdr_parsed = *phdr;
937 return (0);
939 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
940 if (parsed_header == NULL)
941 return (ENOMEM);
942 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
943 parsed_header->sip_header = hdr;
945 value = calloc(1, sizeof (sip_hdr_value_t));
946 if (value == NULL) {
947 sip_free_phdr(parsed_header);
948 return (ENOMEM);
951 parsed_header->value = (sip_value_t *)value;
953 value->sip_value_start = hdr->sip_hdr_current;
954 value->sip_value_header = parsed_header;
956 value->str_val_ptr = hdr->sip_hdr_current;
958 * get rid of CRLF at end
960 value->str_val_len = hdr->sip_hdr_end - value->str_val_ptr - 2;
961 value->sip_value_end = hdr->sip_hdr_end;
963 *phdr = parsed_header;
964 hdr->sip_hdr_parsed = *phdr;
965 return (0);
969 sip_parse_hdr_parser5(_sip_header_t *hdr, sip_parsed_header_t **phdr,
970 boolean_t parse_uri)
972 sip_parsed_header_t *parsed_header;
973 sip_hdr_value_t *value = NULL;
974 sip_param_t *tmp_param;
975 boolean_t first_param = B_TRUE;
976 int ret;
978 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
979 return (ret);
982 * check if previously parsed
984 if (*phdr != NULL) {
985 hdr->sip_hdr_parsed = *phdr;
986 return (0);
988 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
989 if (parsed_header == NULL)
990 return (ENOMEM);
991 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
992 parsed_header->sip_header = hdr;
994 value = calloc(1, sizeof (sip_hdr_value_t));
995 if (value == NULL) {
996 sip_free_phdr(parsed_header);
997 return (ENOMEM);
1000 parsed_header->value = (sip_value_t *)value;
1002 value->sip_value_start = hdr->sip_hdr_current;
1003 value->auth_scheme_ptr = value->sip_value_start;
1004 value->sip_value_header = parsed_header;
1006 * get auth_scheme
1008 if (sip_find_white_space(hdr)) {
1009 value->sip_value_state = SIP_VALUE_BAD;
1010 return (EINVAL);
1012 value->auth_scheme_len = hdr->sip_hdr_current - value->auth_scheme_ptr;
1014 tmp_param = value->auth_param;
1017 * parse auth_param
1019 for (;;) {
1020 char *tmp_cur;
1021 boolean_t quoted_name = B_FALSE;
1022 char quoted_char = '\0';
1023 sip_param_t *new_param;
1024 boolean_t pval_is_uri = B_FALSE;
1026 if (sip_skip_white_space(hdr) != 0) {
1027 value->sip_value_state = SIP_VALUE_BAD;
1028 return (EPROTO);
1030 tmp_cur = hdr->sip_hdr_current;
1032 new_param = calloc(1, sizeof (sip_param_t));
1033 if (new_param == NULL)
1034 return (ENOMEM);
1036 if (first_param == B_FALSE)
1037 tmp_param->param_next = new_param;
1038 else
1039 value->auth_param = new_param;
1041 tmp_param = new_param;
1042 tmp_param->param_name.sip_str_ptr = tmp_cur;
1044 if (sip_find_separator(hdr, SIP_EQUAL, SIP_COMMA, SIP_NUL,
1045 B_FALSE) != 0) {
1046 tmp_param->param_name.sip_str_len =
1047 hdr->sip_hdr_current - tmp_cur;
1048 tmp_param->param_value.sip_str_ptr = NULL;
1049 tmp_param->param_value.sip_str_len = 0;
1050 value->sip_value_end = hdr->sip_hdr_current;
1051 goto end;
1055 * End of param name
1057 tmp_param->param_name.sip_str_len = hdr->sip_hdr_current -
1058 tmp_cur;
1060 if (sip_skip_white_space(hdr) != 0 ||
1061 *hdr->sip_hdr_current == SIP_COMMA) {
1062 tmp_param->param_value.sip_str_ptr = NULL;
1063 tmp_param->param_value.sip_str_len = 0;
1064 continue;
1068 * We are at EQUAL
1070 hdr->sip_hdr_current++;
1072 if (sip_skip_white_space(hdr) != 0) {
1073 value->sip_value_state = SIP_VALUE_BAD;
1074 free(tmp_param);
1075 return (EPROTO);
1078 if (*hdr->sip_hdr_current == SIP_QUOTE ||
1079 *hdr->sip_hdr_current == SIP_LAQUOT) {
1080 if (*hdr->sip_hdr_current == SIP_QUOTE)
1081 quoted_char = SIP_QUOTE;
1082 else {
1083 quoted_char = SIP_RAQUOT;
1084 pval_is_uri = B_TRUE;
1086 hdr->sip_hdr_current++;
1087 quoted_name = B_TRUE;
1091 * start of param value
1093 tmp_cur = hdr->sip_hdr_current;
1094 tmp_param->param_value.sip_str_ptr = tmp_cur;
1095 if (quoted_name) {
1096 if (sip_find_token(hdr, quoted_char) != 0) {
1097 value->sip_value_state = SIP_VALUE_BAD;
1098 free(tmp_param);
1099 return (EPROTO);
1101 tmp_param->param_value.sip_str_len =
1102 hdr->sip_hdr_current - tmp_cur - 1;
1105 if (sip_find_token(hdr, SIP_COMMA) != 0) {
1106 value->sip_value_end = hdr->sip_hdr_current;
1107 goto end;
1108 } else {
1109 if (!quoted_name) {
1110 char *t = hdr->sip_hdr_current;
1111 hdr->sip_hdr_current--;
1112 (void) sip_reverse_skip_white_space(hdr);
1113 tmp_param->param_value.sip_str_len =
1114 hdr->sip_hdr_current - tmp_cur;
1115 hdr->sip_hdr_current = t;
1119 if (first_param == B_TRUE)
1120 first_param = B_FALSE;
1123 * Parse uri
1125 if (pval_is_uri && parse_uri)
1126 sip_parse_uri_str(&tmp_param->param_value, value);
1130 end:
1131 *phdr = parsed_header;
1132 hdr->sip_hdr_parsed = *phdr;
1133 return (0);
1137 * Return the URI in the request startline
1139 static int
1140 _sip_get_request_uri(_sip_header_t *sip_header, sip_message_type_t *msg_info)
1142 int size = 0;
1143 char *start_ptr;
1145 if (sip_skip_white_space(sip_header) != 0)
1146 return (EINVAL);
1147 start_ptr = sip_header->sip_hdr_current;
1149 while (!isspace(*sip_header->sip_hdr_current)) {
1150 if (sip_header->sip_hdr_current >= sip_header->sip_hdr_end)
1151 return (EINVAL);
1152 sip_header->sip_hdr_current++;
1155 size = sip_header->sip_hdr_current - start_ptr;
1157 msg_info->U.sip_request.sip_request_uri.sip_str_ptr = start_ptr;
1158 msg_info->U.sip_request.sip_request_uri.sip_str_len = size;
1159 if (size > 0) { /* Parse uri */
1160 int error;
1162 msg_info->U.sip_request.sip_parse_uri = sip_parse_uri(
1163 &msg_info->U.sip_request.sip_request_uri, &error);
1164 if (msg_info->U.sip_request.sip_parse_uri == NULL)
1165 return (error);
1167 return (0);
1171 * Parse the start line into request/response
1174 sip_parse_first_line(_sip_header_t *sip_header, sip_message_type_t **msg_info)
1176 sip_message_type_t *sip_msg_info;
1177 boolean_t sip_is_request = B_TRUE;
1178 int ret;
1180 if (sip_header == NULL || msg_info == NULL)
1181 return (EINVAL);
1183 if (sip_skip_white_space(sip_header) != 0)
1184 return (EPROTO);
1187 * There is nothing, return
1189 if (sip_header->sip_hdr_current + strlen(SIP_VERSION) >=
1190 sip_header->sip_hdr_end) {
1191 return (EPROTO);
1193 #ifdef __solaris__
1194 assert(mutex_held(&sip_header->sip_hdr_sipmsg->sip_msg_mutex));
1195 #endif
1196 sip_msg_info = malloc(sizeof (sip_message_type_t));
1197 if (sip_msg_info == NULL)
1198 return (ENOMEM);
1201 * let's see if it's a request or a response
1203 ret = sip_get_protocol_version(sip_header,
1204 &sip_msg_info->sip_proto_version);
1205 if (ret == 0) {
1206 sip_is_request = B_FALSE;
1207 } else if (ret == 2) {
1208 free(sip_msg_info);
1209 return (EPROTO);
1212 if (sip_skip_white_space(sip_header) != 0) {
1213 free(sip_msg_info);
1214 return (EPROTO);
1217 if (!sip_is_request) {
1219 * check for status code.
1221 if (sip_skip_white_space(sip_header) != 0) {
1222 free(sip_msg_info);
1223 return (EPROTO);
1225 if (sip_header->sip_hdr_current + SIP_SIZE_OF_STATUS_CODE >=
1226 sip_header->sip_hdr_end) {
1227 free(sip_msg_info);
1228 return (EPROTO);
1231 if (sip_atoi(sip_header,
1232 &sip_msg_info->U.sip_response.sip_response_code)) {
1233 free(sip_msg_info);
1234 return (EPROTO);
1237 if (sip_msg_info->U.sip_response.sip_response_code < 100 ||
1238 sip_msg_info->U.sip_response.sip_response_code > 700) {
1239 free(sip_msg_info);
1240 return (EPROTO);
1244 * get reason phrase.
1246 if (sip_skip_white_space(sip_header) != 0) {
1247 sip_msg_info->sip_resp_phrase_len = 0;
1248 sip_msg_info->sip_resp_phrase_ptr = NULL;
1249 } else {
1250 sip_msg_info->sip_resp_phrase_ptr =
1251 sip_header->sip_hdr_current;
1252 if (sip_find_cr(sip_header) != 0) {
1253 free(sip_msg_info);
1254 return (EPROTO);
1256 sip_msg_info->sip_resp_phrase_len =
1257 sip_header->sip_hdr_current -
1258 sip_msg_info->sip_resp_phrase_ptr;
1260 sip_msg_info->is_request = B_FALSE;
1261 } else {
1262 int i;
1264 * It's a request.
1266 sip_msg_info->is_request = B_TRUE;
1267 for (i = 1; i < MAX_SIP_METHODS; i++) {
1268 if (strncmp(sip_methods[i].name,
1269 sip_header->sip_hdr_current,
1270 sip_methods[i].len) == 0) {
1271 sip_msg_info->sip_req_method = i;
1272 sip_header->sip_hdr_current +=
1273 sip_methods[i].len;
1274 if (!isspace(*sip_header->sip_hdr_current++) ||
1275 !isalpha(*sip_header->sip_hdr_current)) {
1276 free(sip_msg_info);
1277 return (EPROTO);
1280 if ((ret = _sip_get_request_uri(sip_header,
1281 sip_msg_info)) != 0) {
1282 free(sip_msg_info);
1283 return (ret);
1287 * Get SIP version
1289 ret = sip_get_protocol_version(sip_header,
1290 &sip_msg_info->sip_proto_version);
1291 if (ret != 0) {
1292 free(sip_msg_info);
1293 return (EPROTO);
1295 goto done;
1298 free(sip_msg_info);
1299 return (EPROTO);
1301 done:
1302 sip_msg_info->sip_next = *msg_info;
1303 *msg_info = sip_msg_info;
1304 return (0);