📄 sip_parser.c
字号:
sip_method_name_publish, /* If you add something here, add also them to sip_method_d! */ NULL};/** Get canonic method name. */char const *sip_method_name(sip_method_t method, char const *name){ const size_t N = sizeof(sip_method_names)/sizeof(sip_method_names[0]); if (method > 0 && (size_t)method <= N) return sip_method_names[method]; else if (method == 0) return name; else return NULL;}/**Parse a SIP method name. * * Parse a SIP method name and return a code corresponding to the method. * The address of the first non-LWS character after method name is stored in * @a *ss. * * @param ss pointer to pointer to string to be parsed * @param return_name value-result parameter for method name * * @note * If there is no whitespace after method name, the value in @a *return_name * may not be NUL-terminated. The calling function @b must NUL terminate * the value by setting the @a **ss to NUL after first examining its value. * * @return The method code if method * was identified, 0 (sip_method_unknown()) if method is not known, or @c -1 * (sip_method_invalid()) if an error occurred. * * If the value-result argument @a return_name is not @c NULL, * a pointer to the method name is stored to it. */sip_method_t sip_method_d(char **ss, char const **return_name){ char *s = *ss, c = *s; char const *name; int code = sip_method_unknown; size_t n = 0;#define MATCH(s, m) (strncmp(s, m, n = sizeof(m) - 1) == 0) switch (c) { case 'A': if (MATCH(s, "ACK")) code = sip_method_ack; break; case 'B': if (MATCH(s, "BYE")) code = sip_method_bye; break; case 'C': if (MATCH(s, "CANCEL")) code = sip_method_cancel; break; case 'I': if (MATCH(s, "INVITE")) code = sip_method_invite; else if (MATCH(s, "INFO")) code = sip_method_info; break; case 'M': if (MATCH(s, "MESSAGE")) code = sip_method_message; break; case 'N': if (MATCH(s, "NOTIFY")) code = sip_method_notify; break; case 'O': if (MATCH(s, "OPTIONS")) code = sip_method_options; break; case 'P': if (MATCH(s, "PRACK")) code = sip_method_prack; else if (MATCH(s, "PUBLISH")) code = sip_method_publish; break; case 'R': if (MATCH(s, "REGISTER")) code = sip_method_register; else if (MATCH(s, "REFER")) code = sip_method_refer; break; case 'S': if (MATCH(s, "SUBSCRIBE")) code = sip_method_subscribe; break; case 'U': if (MATCH(s, "UPDATE")) code = sip_method_update; break; }#undef MATCH if (IS_NON_WS(s[n])) /* Unknown method */ code = sip_method_unknown; if (code == sip_method_unknown) { name = s; for (n = 0; IS_UNRESERVED(s[n]); n++) ; if (s[n]) { if (!IS_LWS(s[n])) return sip_method_invalid; if (return_name) s[n++] = '\0'; } } else { name = sip_method_names[code]; } while (IS_LWS(s[n])) n++; *ss = (s + n); if (return_name) *return_name = name; return code;}/** Get method enum corresponding to method name */sip_method_t sip_method_code(char const *name){ /* Note that sip_method_d() does not change string if return_name is NULL */ return sip_method_d((char **)&name, NULL);}char const sip_transport_udp[] = "SIP/2.0/UDP";char const sip_transport_tcp[] = "SIP/2.0/TCP";char const sip_transport_sctp[] = "SIP/2.0/SCTP";char const sip_transport_tls[] = "SIP/2.0/TLS";/** Decode transport */issize_t sip_transport_d(char **ss, char const **ttransport){ char const *transport; char *pn, *pv, *pt; size_t pn_len, pv_len, pt_len; char *s = *ss;#define TRANSPORT_MATCH(t) \ (strncasecmp(s+7, t+7, sizeof(t)-8) == 0 && (IS_LWS(s[sizeof(t)])) \ && (transport = t, s += sizeof(t) - 1)) if (strncasecmp(s, "SIP/2.0", 7) != 0 || (!TRANSPORT_MATCH(sip_transport_udp) && !TRANSPORT_MATCH(sip_transport_tcp) && !TRANSPORT_MATCH(sip_transport_sctp) && !TRANSPORT_MATCH(sip_transport_tls))) { /* Protocol name */ transport = pn = s; skip_token(&s); pn_len = s - pn; skip_lws(&s); if (pn_len == 0 || *s++ != '/') return -1; skip_lws(&s); /* Protocol version */ pv = s; skip_token(&s); pv_len = s - pv; skip_lws(&s); if (pv_len == 0 || *s++ != '/') return -1; skip_lws(&s); /* Transport protocol */ pt = s; skip_token(&s); pt_len = s - pt; if (pt_len == 0) return -1; /* Remove whitespace between protocol name and version */ if (pn + pn_len + 1 != pv) { pn[pn_len] = '/'; pv = memmove(pn + pn_len + 1, pv, pv_len); } /* Remove whitespace between protocol version and transport */ if (pv + pv_len + 1 != pt) { pv[pv_len] = '/'; pt = memmove(pv + pv_len + 1, pt, pt_len); pt[pt_len] = '\0'; /* extra whitespace? */ if (!strcasecmp(transport, sip_transport_udp)) transport = sip_transport_udp; else if (!strcasecmp(transport, sip_transport_tcp)) transport = sip_transport_tcp; else if (!strcasecmp(transport, sip_transport_sctp)) transport = sip_transport_sctp; else if (!strcasecmp(transport, sip_transport_tls)) transport = sip_transport_tls; } } if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } *ss = s; *ttransport = transport; return 0;}/** Calculate extra space required by sip_transport_dup() */isize_t sip_transport_xtra(char const *transport){ if (transport == sip_transport_udp || transport == sip_transport_tcp || transport == sip_transport_sctp || transport == sip_transport_tls || strcasecmp(transport, sip_transport_udp) == 0 || strcasecmp(transport, sip_transport_tcp) == 0 || strcasecmp(transport, sip_transport_sctp) == 0 || strcasecmp(transport, sip_transport_tls) == 0) return 0; return MSG_STRING_SIZE(transport);}/** Duplicate a transport string */void sip_transport_dup(char **pp, char const **dd, char const *s){ if (s == sip_transport_udp) *dd = s; else if (s == sip_transport_tcp) *dd = s; else if (s == sip_transport_sctp) *dd = s; else if (s == sip_transport_tls) *dd = s; else if (strcasecmp(s, sip_transport_udp) == 0) *dd = sip_transport_udp; else if (strcasecmp(s, sip_transport_tcp) == 0) *dd = sip_transport_tcp; else if (strcasecmp(s, sip_transport_sctp) == 0) *dd = sip_transport_sctp; else if (strcasecmp(s, sip_transport_tls) == 0) *dd = sip_transport_tls; else MSG_STRING_DUP(*pp, *dd, s);}/** Parse SIP <word "@" word> construct used in @CallID. */char *sip_word_at_word_d(char **ss){ char *rv = *ss, *s0 = *ss; skip_word(ss); if (s0 == *ss) return NULL; if (**ss == '@') { (*ss)++; s0 = *ss; skip_word(ss); if (s0 == *ss) return NULL; } if (IS_LWS(**ss)) (*ss)++; skip_lws(ss); return rv;}/**Add message separator, then test if message is complete. * * Add sip_content_length and sip_separator if they are missing. * The test that all necessary message components ( @From, @To, * @CSeq, @CallID, @ContentLength and message separator are present. * * @retval 0 when successful * @retval -1 upon an error: headers are missing and they could not be added */int sip_complete_message(msg_t *msg){ sip_t *sip = sip_object(msg); su_home_t *home = msg_home(msg); size_t len = 0; ssize_t mplen; if (sip == NULL) return -1; if (!sip->sip_separator) sip->sip_separator = sip_separator_create(msg_home(msg)); if (sip->sip_multipart) { sip_content_type_t *c = sip->sip_content_type; msg_multipart_t *mp = sip->sip_multipart; sip_common_t *head; if (!c || msg_multipart_complete(msg_home(msg), c, mp) < 0) return -1; if (sip->sip_payload) head = sip->sip_payload->pl_common; else head = sip->sip_separator->sep_common; if (!head || !msg_multipart_serialize(&head->h_succ, mp)) return -1; mplen = msg_multipart_prepare(msg, mp, sip->sip_flags); if (mplen == -1) return -1; len = (size_t)mplen; } if (sip->sip_payload) len += sip->sip_payload->pl_len; if (len > UINT32_MAX) return -1; if (!sip->sip_content_length) { msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t*) sip_content_length_create(home, (uint32_t)len)); } else { if (sip->sip_content_length->l_length != len) { sip->sip_content_length->l_length = (uint32_t)len; sip_fragment_clear(sip->sip_content_length->l_common); } } if (!sip->sip_cseq || !sip->sip_call_id || !sip->sip_to || !sip->sip_from || !sip->sip_separator || !sip->sip_content_length) return -1; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -