/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ /**@SIP_PARSER * * @file test_sip_msg.c Simple SIP message parser/printer tester. * * @author Pekka Pessi . * * @date Created: Fri Feb 18 10:25:08 2000 ppessi */ #include "config.h" /* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */ #define MSG_PUB_T struct sip_s #define MSG_HDR_T union sip_header_u #include "sofia-sip/sip_parser.h" #include "sofia-sip/msg_mclass.h" #include "sofia-sip/msg_mclass_hash.h" #include #include #include #include #include #include #include #include int diff(const char *olds, const char *news, int *linep, int *pos) { const char *o, *n; *linep = 0; for (o = olds, n = news; *o && *n && *o == *n ; o++, n++) { if (*o == '\n') ++*linep; } *pos = o - olds; return *o != *n; } int test_msg_class(msg_mclass_t const *mc) { int i, j, N; N = mc->mc_hash_size; /* Check parser table sanity */ for (i = 0; i < N; i++) { /* Verify each header entry */ msg_hclass_t *hc = mc->mc_hash[i].hr_class; if (hc == NULL) continue; /* Short form */ if (hc->hc_short[0]) assert(mc->mc_short[hc->hc_short[0] - 'a'].hr_class == hc); /* Long form */ for (j = MC_HASH(hc->hc_name, N); j != i; j = (j + 1) % N) assert(mc->mc_hash[j].hr_class); } return 0; } char * url_print(url_t *url, char buf[1024]) { url_e(buf, 1024, url); return buf; } void print_contact(FILE *f, sip_contact_t *m) { char const * const *p; char buf[1024]; const char *sep = "\tContact: "; for (;m; m = m->m_next) { int quoted_url = 0; fputs(sep, f); sep = ", "; if (m->m_display) { quoted_url = 1; fprintf(f, "\"%s\" <", m->m_display); } url_print(m->m_url, buf); if (!quoted_url && strpbrk(buf, ",;?")) { fputs("<", f); } fputs(buf, f); if (quoted_url) fputs(">", f); if (m->m_params) for (p = m->m_params; *p; p++) fprintf(f, " ;%s", *p); if (m->m_comment) fprintf(f, " (%s)", m->m_comment); } fputs("\n", f); } void print_via(FILE *f, sip_via_t *v) { char const * const *p; char const * sep = "\tVia: "; for (;v; v = v->v_next) { fputs(sep, f); sep = ", "; fprintf(f, "%s %s", v->v_protocol, v->v_host); if (v->v_port) fprintf(f, ":%s", v->v_port); if (v->v_params) for (p = v->v_params; *p; p++) fprintf(f, " ;%s", *p); if (v->v_comment) fprintf(f, " (%s)", v->v_comment); } fputs("\n", f); } int main(int argc, char *argv[]) { char urlbuf[1024]; size_t n; int m, tcp; sip_t *sip; int exitcode = 0; msg_mclass_t const *sip_mclass = sip_default_mclass(); msg_t *msg = msg_create(sip_mclass, MSG_FLG_EXTRACT_COPY); msg_iovec_t iovec[1]; tcp = argv[1] && strcmp(argv[1], "-t") == 0; test_msg_class(sip_mclass); for (n = 0, m = 0;;) { if (msg_recv_iovec(msg, iovec, 1, 1, 0) < 0) { perror("msg_recv_iovec"); exit(1); } assert(iovec->mv_len >= 1); n = read(0, iovec->mv_base, 1); if (n < 0) { perror("test_sip_msg read"); exit(1); } msg_recv_commit(msg, n, n == 0); if (tcp) m = msg_extract(msg); if (n == 0 || m < 0) break; } if (!tcp) m = msg_extract(msg); sip = msg_object(msg); if (sip) fprintf(stdout, "sip flags = %x\n", sip->sip_flags); if (m < 0) { fprintf(stderr, "test_sip_msg: parsing error ("MOD_ZD")\n", n); exit(1); } if (sip->sip_flags & MSG_FLG_TRUNC) { fprintf(stderr, "test_sip_msg: message truncated\n"); exit(1); } if (msg_next(msg)) { fprintf(stderr, "test_sip_msg: stuff after message\n"); exit(1); } #if 0 fprintf(stderr, "test_sip_msg: %d headers (%d short ones), %d unknown\n", msg->mh_n_headers, msg->mh_n_short, msg->mh_n_unknown); if (msg->mh_payload) { fprintf(stderr, "\twith payload of %d bytes\n", msg->mh_payload->pl_len); } #endif if (MSG_HAS_ERROR(sip->sip_flags) || sip->sip_error) { fprintf(stderr, "test_sip_msg: parsing error\n"); exit(1); } else if (sip_sanity_check(sip) < 0) { fprintf(stderr, "test_sip_msg: message failed sanity check\n"); exit(1); } if (sip->sip_request) { fprintf(stdout, "\trequest %s (%d) %s %s\n", sip->sip_request->rq_method_name, sip->sip_request->rq_method, url_print(sip->sip_request->rq_url, urlbuf), sip->sip_request->rq_version); if (sip->sip_request->rq_url->url_type == url_unknown) { exitcode = 1; fprintf(stderr, "test_sip_msg: invalid request URI\n"); } } if (sip->sip_status) fprintf(stdout, "\tstatus %s %03d %s\n", sip->sip_status->st_version, sip->sip_status->st_status, sip->sip_status->st_phrase); if (sip->sip_cseq) fprintf(stdout, "\tCSeq: %u %s (%d)\n", sip->sip_cseq->cs_seq, sip->sip_cseq->cs_method_name, sip->sip_cseq->cs_method); if (sip->sip_call_id) fprintf(stdout, "\tCall-ID: %s (%x)\n", sip->sip_call_id->i_id, sip->sip_call_id->i_hash); if (sip->sip_from) fprintf(stdout, "\tFrom: %s@%s%s%s\n", sip->sip_from->a_user ? sip->sip_from->a_user : "[nobody]", sip->sip_from->a_host ? sip->sip_from->a_host : "[nowhere]", sip->sip_from->a_tag ? " ;tag=" : "", sip->sip_from->a_tag ? sip->sip_from->a_tag : ""); if (sip->sip_to) fprintf(stdout, "\tTo: %s@%s%s%s\n", sip->sip_to->a_user ? sip->sip_to->a_user : "[nobody]", sip->sip_to->a_host ? sip->sip_to->a_host : "[nowhere]", sip->sip_to->a_tag ? " ;tag=" : "", sip->sip_to->a_tag ? sip->sip_to->a_tag : ""); if (sip->sip_contact) print_contact(stdout, sip->sip_contact); if (sip->sip_via) print_via(stdout, sip->sip_via); if (sip->sip_content_length) { fprintf(stdout, "\tcontent length %u\n", sip->sip_content_length->l_length); } if (msg_next(msg)) { fprintf(stderr, "test_sip_msg: extra stuff after valid message\n"); exit(1); } return exitcode; }