⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uac_unixsock.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
字号:
/* * $Id: uac_unixsock.c,v 1.8 2004/11/09 15:15:12 andrei Exp $ * * Copyright (C) 2001-2004 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: *    info@iptel.org * * ser 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 General Public License for more details. * * You should have received a copy of the GNU General Public License  * along with this program; if not, write to the Free Software  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <string.h>#include "../../mem/mem.h"#include "../../mem/shm_mem.h"#include "../../parser/hf.h"#include "../../dprint.h"#include "../../parser/parse_uri.h"#include "../../unixsock_server.h"#include "../../parser/msg_parser.h"#include "../../parser/parse_to.h"#include "../../parser/parse_cseq.h"#include "../../parser/parse_from.h"#include "../../ut.h"#include "uac_unixsock.h"#include "config.h"#include "ut.h"#include "t_hooks.h"#include "callid.h"#include "uac.h"#include "dlg.h"struct str_list {	str s;	struct str_list *next;};#define skip_hf(_hf) (             \    ((_hf)->type == HDR_FROM)   || \    ((_hf)->type == HDR_TO)     || \    ((_hf)->type == HDR_CALLID) || \    ((_hf)->type == HDR_CSEQ)      \)/* * Read the method from the request */static int get_method(str* method, str* msg){	if (unixsock_read_line(method, msg) != 0) {		unixsock_reply_asciiz("400 Method expected");		unixsock_reply_send();		return -1;	}	DBG("get_method: method: '%.*s'\n", method->len, ZSW(method->s));	return 0;}/* * Read the Request-URI and parse it */static int get_ruri(str* ruri, struct sip_uri* puri, str* msg){	if (unixsock_read_line(ruri, msg) != 0) {		unixsock_reply_asciiz("400 Request-URI expected");		unixsock_reply_send();		return -1;	}		if (parse_uri(ruri->s, ruri->len, puri) < 0 ) {		unixsock_reply_asciiz("400 Request-URI is invalid\n");		unixsock_reply_send();		return -1;	}	DBG("get_ruri: '%.*s'\n", ruri->len, ZSW(ruri->s));	return 0;}/* * Read and parse the next hop */static int get_nexthop(str* nexthop, struct sip_uri* pnexthop, str* msg){	if (unixsock_read_line(nexthop, msg) != 0) {		unixsock_reply_asciiz("400 Next-hop URI expected\n");		unixsock_reply_send();		return -1;	}	if (nexthop->len == 1 && nexthop->s[0] == '.' ) {		DBG("get_nexthop: next hop empty\n");		nexthop->s = 0; 		nexthop->len = 0;	} else if (parse_uri(nexthop->s, nexthop->len, pnexthop) < 0 ) {		unixsock_reply_asciiz("400 Next-hop URI is invalid\n");		unixsock_reply_send();		return -1;	} else {		DBG("get_nexthop: '%.*s'\n", nexthop->len, ZSW(nexthop->s));	}	return 0;}/* * Read header into a static buffer (it is necessary because * the unixsock_read_lineset performs CRLF recovery and thus * the result may be longer than the original */static int get_headers(str* headers, str* msg){	static char headers_buf[MAX_HEADER];	headers->s = headers_buf;	headers->len = MAX_HEADER;	     /* now read and parse header fields */	if (unixsock_read_lineset(headers, msg) < 0) {		unixsock_reply_asciiz("400 Header fields expected\n");		unixsock_reply_send();		return -1;	}	DBG("get_headers: %.*s\n", headers->len, ZSW(headers->s));	return 0;}/* * Read the message body */static int get_body_lines(str* body, str* msg){	if (unixsock_read_body(body, msg) < 0) {		unixsock_reply_asciiz("400 Body expected\n");		unixsock_reply_send();		return -1;	}	DBG("get_body_lines: %.*s\n", body->len,  ZSW(body->s));	return 0;}/* * Make sure that the FIFO user created the message * correctly */static int check_msg(struct sip_msg* msg, str* method, str* body, 		     int* fromtag, int *cseq_is, int* cseq, str* callid){	struct to_body* parsed_from;	struct cseq_body *parsed_cseq;	int i;	char c;	if (body->len && !msg->content_type) {		unixsock_reply_asciiz("400 Content-Type missing");		goto err;	}	if (body->len && msg->content_length) {		unixsock_reply_asciiz("400 Content-Length disallowed");		goto err;	}	if (!msg->to) {		unixsock_reply_asciiz("400 To missing");		goto err;	}	if (!msg->from) {		unixsock_reply_asciiz("400 From missing");		goto err;	}	     /* we also need to know if there is from-tag and add it otherwise */	if (parse_from_header(msg) < 0) {		unixsock_reply_asciiz("400 Error in From");		goto err;	}	parsed_from = (struct to_body*)msg->from->parsed;	*fromtag = parsed_from->tag_value.s && parsed_from->tag_value.len;	*cseq = 0;	if (msg->cseq && (parsed_cseq = get_cseq(msg))) {		*cseq_is = 1;		for (i = 0; i < parsed_cseq->number.len; i++) {			c = parsed_cseq->number.s[i];			if (c >= '0' && c <= '9' ) {				*cseq = (*cseq) * 10 + c - '0';			} else {			        DBG("check_msg: Found non-numerical in CSeq: <%i>='%c'\n", (unsigned int)c, c);				unixsock_reply_asciiz("400 Non-numerical CSeq");				goto err;			}		}				if (parsed_cseq->method.len != method->len 		    || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {			unixsock_reply_asciiz("400 CSeq method mismatch");			goto err;		}	} else {		*cseq_is = 0;	}	if (msg->callid) {		callid->s = msg->callid->body.s;		callid->len = msg->callid->body.len;	} else {		callid->s = 0;		callid->len = 0;	}	return 0; err:	unixsock_reply_send();	return -1;}static inline struct str_list *new_str(char *s, int len, struct str_list **last, int *total){	struct str_list *new;	new = pkg_malloc(sizeof(struct str_list));	if (!new) {		LOG(L_ERR, "new_str: Not enough mem\n");		return 0;	}	new->s.s = s;	new->s.len = len;	new->next = 0;	(*last)->next = new;	*last = new;	*total += len;	return new;}static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto) {	struct str_list sl, *last, *i, *foo;	int p, frag_len, total_len;	char *begin, *needle, *dst, *ret, *d;	str *sock_name, *portname;	union sockaddr_union to_su;	struct socket_info* send_sock;	ret = 0; /* pessimist: assume failure */	total_len = 0;	last = &sl;	last->next = 0;	portname = sock_name = 0;	for (; hf; hf = hf->next) {		if (skip_hf(hf)) continue;		begin = needle = hf->name.s; 		p = hf->len;		     /* substitution loop */		while(p) {			d = q_memchr(needle, SUBST_CHAR, p);			if (!d || d + 1 >= needle + p) { /* nothing to substitute */				if (!new_str(begin, p, &last, &total_len)) goto error;				break;			} else {				frag_len = d - begin;				d++; /* d not at the second substitution char */				switch(*d) {				case SUBST_CHAR: /* double SUBST_CHAR: IP */					     /* string before substitute */					if (!new_str(begin, frag_len, &last, &total_len)) goto error;					     /* substitute */					if (!sock_name) {						send_sock = uri2sock(0, uri, &to_su, proto);						if (!send_sock) {							LOG(L_ERR, "ERROR: get_hfblock: send_sock failed\n");							goto error;						}						sock_name = &send_sock->address_str;						portname = &send_sock->port_no_str;					}					if (!new_str(sock_name->s, sock_name->len, &last, &total_len)) goto error;					     /* inefficient - FIXME --andrei*/					if (!new_str(":", 1, &last, &total_len)) goto error;					if (!new_str(portname->s, portname->len, &last, &total_len)) goto error;					     /* keep going ... */					begin = needle = d + 1;					p -= frag_len + 2;					continue;				default:					     /* no valid substitution char -- keep going */					p -= frag_len + 1;					needle = d;				}			} /* possible substitute */		} /* substitution loop */		DBG("get_hfblock: one more hf processed\n");	} /* header loop */		     /* construct a single header block now */	ret = pkg_malloc(total_len);	if (!ret) {		LOG(L_ERR, "get_hfblock: no pkg mem for hf block\n");		goto error;	}	i = sl.next;	dst = ret;	while(i) {		foo = i;		i = i->next;		memcpy(dst, foo->s.s, foo->s.len);		dst += foo->s.len;		pkg_free(foo);	}	*l = total_len;	return ret;	 error:	i = sl.next;	while(i) {		foo = i;		i = i->next;		pkg_free(foo);	}	*l = 0;	return 0;}#define FIFO_ROUTE_PREFIX "Route: "#define FIFO_ROUTE_SEPARATOR ", "static void print_routes(dlg_t* _d){	rr_t* ptr;	ptr = _d->hooks.first_route;	if (ptr) {		unixsock_reply_asciiz(FIFO_ROUTE_PREFIX);	} else {		unixsock_reply_asciiz(".\n");		return;	}	while(ptr) {		unixsock_reply_printf("%.*s", ptr->len, ptr->nameaddr.name.s);		ptr = ptr->next;		if (ptr) {			unixsock_reply_asciiz(FIFO_ROUTE_SEPARATOR);		}	} 	if (_d->hooks.last_route) {		unixsock_reply_asciiz(FIFO_ROUTE_SEPARATOR "<");		unixsock_reply_printf("%.*s", _d->hooks.last_route->len, _d->hooks.last_route->s);		unixsock_reply_asciiz(">");	}	if (_d->hooks.first_route) {		unixsock_reply_asciiz(CRLF);	}}static int print_uris(struct sip_msg* reply){	dlg_t* dlg;		dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));	if (!dlg) {		LOG(L_ERR, "print_uris: No memory left\n");		return -1;	}	memset(dlg, 0, sizeof(dlg_t));	if (dlg_response_uac(dlg, reply) < 0) {		LOG(L_ERR, "print_uris: Error while creating dialog structure\n");		free_dlg(dlg);		return -2;	}	if (dlg->state != DLG_CONFIRMED) {		unixsock_reply_asciiz(".\n.\n.\n");		free_dlg(dlg);		return 0;	}	if (dlg->hooks.request_uri->s) {			unixsock_reply_printf("%.*s\n", dlg->hooks.request_uri->len, dlg->hooks.request_uri->s);	} else {		unixsock_reply_asciiz(".\n");	}	if (dlg->hooks.next_hop->s) {		unixsock_reply_printf("%.*s\n", dlg->hooks.next_hop->len, dlg->hooks.next_hop->s);	} else {		unixsock_reply_asciiz(".\n");	}	print_routes(dlg);	free_dlg(dlg);	return 0;}static void callback(struct cell *t, int type, struct tmcb_params *ps){	struct sockaddr_un* to;	str text;	if (!*ps->param) {		LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", ps->code);		return;	}		to = (struct sockaddr_un*)(*ps->param);	unixsock_reply_reset();	if (ps->rpl == FAKED_REPLY) {		get_reply_status(&text, ps->rpl, ps->code);		if (text.s == 0) {			LOG(L_ERR, "callback: get_reply_status failed\n");			unixsock_reply_asciiz("500 callback: get_reply_status failed\n");			goto done;		}		unixsock_reply_printf("%.*s\n", text.len, text.s);		pkg_free(text.s);	} else {		text.s = ps->rpl->first_line.u.reply.reason.s;		text.len = ps->rpl->first_line.u.reply.reason.len;		     /* FIXME: check for return values here */		unixsock_reply_printf("%d %.*s\n", ps->rpl->first_line.u.reply.statuscode, text.len, text.s);		print_uris(ps->rpl);		unixsock_reply_printf("%s\n", ps->rpl->headers->name.s);	}done:	unixsock_reply_sendto(to);	shm_free(to);	*ps->param=0; /* 0 it so the callback won't do anything if called					 for a retransmission */}/* * Create shm_copy of filename */static int duplicate_addr(struct sockaddr_un** dest, struct sockaddr_un* addr){	if (addr) {		*dest = shm_malloc(sizeof(*addr));		if (!*dest) {			unixsock_reply_asciiz("500 No shared memory");			return -1;		}		memcpy(*dest, addr, sizeof(*addr));	} else {		*dest = 0;	}	return 0;}int unixsock_uac(str* msg){	str method, ruri, nexthop, headers, body, hfb, callid;	struct sip_uri puri, pnexthop;	struct sip_msg faked_msg;	int ret, sip_error, err_ret, fromtag, cseq_is, cseq;	char err_buf[MAX_REASON_LEN];	struct sockaddr_un* shm_sockaddr;	dlg_t dlg;	if (get_method(&method, msg) < 0) return -1;	if (get_ruri(&ruri, &puri, msg) < 0) return -1;	if (get_nexthop(&nexthop, &pnexthop, msg) < 0) return -1;	if (get_headers(&headers, msg) < 0) return -1;	     /* use SIP parser to look at what is in the FIFO request */	memset(&faked_msg, 0, sizeof(struct sip_msg));	faked_msg.len = headers.len; 	faked_msg.buf = faked_msg.unparsed = headers.s;	if (parse_headers(&faked_msg, HDR_EOH, 0) == -1 ) {		unixsock_reply_asciiz("400 HFs unparsable\n");		unixsock_reply_send();		goto error;	}	if (get_body_lines(&body, msg) < 0) goto error;		     /* at this moment, we collected all the things we got, let's	      * verify user has not forgotten something */	if (check_msg(&faked_msg, &method, &body, &fromtag, 		      &cseq_is, &cseq, &callid) < 0) goto error;	hfb.s = get_hfblock(nexthop.len ? &nexthop : &ruri, 			    faked_msg.headers, &hfb.len, PROTO_UDP);	if (!hfb.s) {		unixsock_reply_asciiz("500 No memory for HF block");		unixsock_reply_send();		goto error;	}	memset(&dlg, 0, sizeof(dlg_t));	     /* Fill in Call-ID, use given Call-ID if	      * present and generate it if not present	      */	if (callid.s && callid.len) dlg.id.call_id = callid;	else generate_callid(&dlg.id.call_id);		     /* We will not fill in dlg->id.rem_tag because	      * if present it will be printed within To HF	      */		     /* Generate fromtag if not present */	if (!fromtag) {		generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);	}		     /* Fill in CSeq */	if (cseq_is) dlg.loc_seq.value = cseq;	else dlg.loc_seq.value = DEFAULT_CSEQ;	dlg.loc_seq.is_set = 1;	dlg.loc_uri = faked_msg.from->body;	dlg.rem_uri = faked_msg.to->body;	dlg.hooks.request_uri = &ruri;	dlg.hooks.next_hop = (nexthop.len ? &nexthop : &ruri);		     /* we got it all, initiate transaction now! */	if (duplicate_addr(&shm_sockaddr, unixsock_sender_addr()) < 0) goto error01;	ret = t_uac(&method, &hfb, &body, &dlg, callback, shm_sockaddr);	if (ret <= 0) {		err_ret = err2reason_phrase(ret, &sip_error, err_buf, sizeof(err_buf), "FIFO/UAC");		if (err_ret > 0) {			unixsock_reply_printf("%d %s", sip_error, err_buf);		} else {			unixsock_reply_asciiz("500 UNIXSOCK/UAC error");		}		unixsock_reply_send();		shm_free(shm_sockaddr);		goto error01;	}	     /* Do not free shm_sockaddr here, it will be used	      * by the callback	      */	pkg_free(hfb.s);	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);	return 0;	 error01:	pkg_free(hfb.s); error:	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);	return -1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -