shithub: catphone

ref: 2e99eaaea1aa6776eda10f5ec8bd90adcfe8424a
dir: /sip.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include "dat.h"
#include "fns.h"

static char sipversion[] = "SIP/2.0";
static char *methodstrtab[] = {
 [REGISTER]	"REGISTER",
 [INVITE]	"INVITE",
 [ACK]		"ACK",
 [BYE]		"BYE",
 [CANCEL]	"CANCEL",
 [OPTIONS]	"OPTIONS",
 [NOTIFY]	"NOTIFY",
 [SUBSCRIBE]	"SUBSCRIBE",
 [INFO]		"INFO",
 [MESSAGE]	"MESSAGE",
 [UPDATE]	"UPDATE",
 [REFER]	"REFER",
};

static char registerhdr0[] = "REGISTER sip:%s %s\r\n"
	"Via: %s/UDP %s:%s;branch=z9hG4bK703d971c0c737b8e;rport\r\n"
	"Contact: <sip:%s-0x82a66a010@%s:%s>;expires=3849\r\n"
	"Max-Forwards: 70\r\n"
	"To: <sip:%s@%s>\r\n"
	"From: <sip:%s@%s>;tag=4a5a693256d38cbc\r\n"
	"Call-ID: 2cee372fc4be4e45\r\n"
	"CSeq: 16021 REGISTER\r\n"
	"User-Agent: catphone (plan9front)\r\n"
	"Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,NOTIFY,SUBSCRIBE,INFO,MESSAGE,UPDATE,REFER\r\n"
	"Content-Length: 0\r\n"
	"\r\n";
static char registerhdr[] = "REGISTER sip:10.0.0.104 SIP/2.0\r\n"
	"Via: SIP/2.0/UDP 10.0.1.9:54022;branch=z9hG4bKdf800c31b9a88ffb;rport\r\n"
	"Contact: <sip:[email protected]:54022>;expires=3849\r\n"
	"Max-Forwards: 70\r\n"
	"Authorization: Digest username=\"sam\", realm=\"asterisk\", nonce=\"0d39ab10\", uri=\"sip:10.0.0.104\", response=\"a12e05b52604b5226763ce577d5c240b\", algorithm=MD5\r\n"
	"To: <sip:[email protected]>\r\n"
	"From: <sip:[email protected]>;tag=4a5a693256d38cbc\r\n"
	"Call-ID: 2cee372fc4be4e45\r\n"
	"CSeq: 16022 REGISTER\r\n"
	"User-Agent: catphone (plan9front)\r\n"
	"Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,NOTIFY,SUBSCRIBE,INFO,MESSAGE,UPDATE,REFER\r\n"
	"Content-Length: 0\r\n"
	"\r\n";

static char *
getmethodstr(SipMethod m)
{
	return methodstrtab[m];
}

static uint
hash(char *s)
{
	uint h;

	h = 0x811c9dc5;
	while(*s != 0)
		h = (h^(uchar)*s++) * 0x1000193;
	return h % 13;
}

void
addheader(Hdrtab *ht, char *name, char *value)
{
	Hdr *h, *newh;
	uint key;

	key = hash(name);
	newh = emalloc(sizeof(Hdr));
	newh->name = strdup(name);
	newh->value = strdup(value);
	newh->next = nil;

	h = ht->headers[key];
	if(h == nil){
		ht->headers[key] = newh;
		return;
	}
	while(h->next != nil)
		h = h->next;
	h->next = newh;
}

Hdr *
getheader(Hdrtab *ht, char *name)
{
	Hdr *h;
	uint key;

	key = hash(name);
	for(h = ht->headers[key]; h != nil; h = h->next)
		if(cistrcmp(h->name, name) == 0)
			return h;
	return nil;
}

void
delheader(Hdrtab *ht, char *name)
{
	Hdr **h, *nh;
	uint key;

	key = hash(name);
	h = &ht->headers[key];
	while(*h != nil){
		nh = (*h)->next;
		if(cistrcmp((*h)->name, name) == 0){
			free((*h)->name);
			free((*h)->value);
			free(*h);
		}
		*h = nh;
	}
}

void
delheaders(Hdrtab *ht)
{
	Hdr *h, *nh;
	int i;

	for(i = 0; i < nelem(ht->headers); i++)
		for(h = ht->headers[i]; h != nil; h = nh){
			nh = h->next;
			free(h->name);
			free(h->value);
			free(h);
		}
}

/* rfc3261 § 10 - Registrations */
static int
sip_register(Sip *s, char *user, char *pass)
{
	Biobuf *bin, *bout;
	char *line, *p, *kv[2];
	int n;

	if((bin = Bfdopen(s->fd, OREAD)) == nil)
		sysfatal("Bfdopen: %r");
	if((bout = Bfdopen(s->fd, OWRITE)) == nil)
		sysfatal("Bfdopen: %r");

	/* present yourself */
	Bprint(bout, registerhdr0, s->nci->rsys, sipversion,
		sipversion, s->nci->lsys, s->nci->lserv,
		user, s->nci->lsys, s->nci->lserv,
		user, s->nci->rsys,
		user, s->nci->rsys);
	Bflush(bout);

	/* wait for the challenge */
	while((line = Brdline(bin, '\n')) != nil){
		if(strncmp(line, "\r\n", 2) == 0)
			break;

		p = strchr(line, '\r');
		*p++ = 0, *p = 0;
		if(debug)
			fprint(2, "%s\n", line);

		if(strstr(line, ":") == nil)
			continue;

		gettokens(line, kv, nelem(kv), ": ");
		if(debug)
			fprint(2, "got key=%s value=%s\n", kv[0], kv[1]);
	}

	/* respond to the challenge */

	/* get the OK */

	Bterm(bin);
	Bterm(bout);

	return 0;
}

Sip *
mksip(int fd)
{
	Sip *s;

	s = emalloc(sizeof(Sip));
	memset(s, 0, sizeof *s);
	s->version = 2;
	s->nci = getnetconninfo(nil, fd);
	if(s->nci == nil){
		werrstr("couldn't getnetconninfo");
		free(s);
		return nil;
	}
	s->fd = fd;
	s->reg = sip_register;

	return s;
}

void
rmsip(Sip *s)
{
	close(s->fd);
	freenetconninfo(s->nci);
	free(s);
}