294 lines
6.8 KiB
C
294 lines
6.8 KiB
C
/*
|
|
* This file is part of the Sofia-SIP package
|
|
*
|
|
* Copyright (C) 2005 Nokia Corporation.
|
|
*
|
|
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
|
*
|
|
* 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 <Pekka.Pessi@nokia.com>.
|
|
*
|
|
* @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 <sofia-sip/sip_header.h>
|
|
#include <sofia-sip/sip_util.h>
|
|
#include <sofia-sip/msg_addr.h>
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
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;
|
|
}
|