Skip to content
Snippets Groups Projects
chan_sip.c 49.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
    /*
     * Asterisk -- A telephony toolkit for Linux.
     *
     * Implementation of Session Initiation Protocol
     * 
     * Copyright (C) 1999, Mark Spencer
     *
     * Mark Spencer <markster@linux-support.net>
     *
     * This program is free software, distributed under the terms of
     * the GNU General Public License
     */
    
    #include <stdio.h>
    #include <pthread.h>
    #include <string.h>
    #include <asterisk/lock.h>
    #include <asterisk/channel.h>
    #include <asterisk/channel_pvt.h>
    #include <asterisk/config.h>
    #include <asterisk/logger.h>
    #include <asterisk/module.h>
    #include <asterisk/pbx.h>
    #include <asterisk/options.h>
    #include <asterisk/lock.h>
    #include <asterisk/sched.h>
    #include <asterisk/io.h>
    #include <asterisk/rtp.h>
    #include <asterisk/acl.h>
    #include <asterisk/callerid.h>
    #include <sys/socket.h>
    #include <errno.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <sys/signal.h>
    
    #define SIPDUMPER
    #define DEFAULT_EXPIREY 120
    #define MAX_EXPIREY     3600
    
    static char *desc = "Session Initiation Protocol (SIP)";
    static char *type = "sip";
    static char *tdesc = "Session Initiation Protocol (SIP)";
    static char *config = "sip.conf";
    
    #define DEFAULT_SIP_PORT	5060	/* From RFC 2543 */
    #define SIP_MAX_PACKET	1500		/* Also from RFC 2543, should sub headers tho */
    
    static char context[AST_MAX_EXTENSION] = "default";
    
    static char language[MAX_LANGUAGE] = "";
    
    static int usecnt =0;
    static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
    
    /* Protect the interface list (of sip_pvt's) */
    static pthread_mutex_t iflock = AST_MUTEX_INITIALIZER;
    
    /* Protect the monitoring thread, so only one process can kill or start it, and not
       when it's doing something critical. */
    static pthread_mutex_t netlock = AST_MUTEX_INITIALIZER;
    
    static pthread_mutex_t monlock = AST_MUTEX_INITIALIZER;
    
    /* This is the thread for the monitor which checks for input on the channels
       which are not currently in use.  */
    static pthread_t monitor_thread = 0;
    
    static int restart_monitor(void);
    
    /* Just about everybody seems to support ulaw, so make it a nice default */
    static int capability = AST_FORMAT_ULAW;
    
    static char ourhost[256];
    static struct in_addr ourip;
    static int ourport;
    
    /* Expire slowly */
    static int expirey = 900;
    
    static struct sched_context *sched;
    static struct io_context *io;
    /* The private structures of the  sip channels are linked for
       selecting outgoing channels */
       
    #define SIP_MAX_HEADERS		64
    #define SIP_MAX_LINES 		64
    
    struct sip_request {
    	int len;
    	int headers;					/* SIP Headers */
    	char *header[SIP_MAX_HEADERS];
    	int lines;						/* SDP Content */
    	char *line[SIP_MAX_LINES];
    	char data[SIP_MAX_PACKET];
    };
    
    static struct sip_pvt {
    	char callid[80];					/* Global CallID */
    	unsigned int cseq;							/* Current seqno */
    	int lastinvite;						/* Last Cseq of invite */
    	int alreadygone;					/* Whether or not we've already been destroyed by or peer */
    	int needdestroy;					/* if we need to be destroyed */
    	int capability;						/* Special capability */
    	int outgoing;						/* Outgoing or incoming call? */
    	int insecure;						/* Don't check source port/ip */
    	int expirey;						/* How long we take to expire */
    	struct sockaddr_in sa;				/* Our peer */
    	struct ast_channel *owner;			/* Who owns us */
    	char exten[AST_MAX_EXTENSION];		/* Extention where to start */
    	char context[AST_MAX_EXTENSION];
    	char language[MAX_LANGUAGE];
    	struct sip_request initreq;			/* Initial request */
    	struct ast_rtp *rtp;				/* RTP Session */
    	struct sip_pvt *next;
    } *iflist = NULL;
    
    static struct sip_pkt {
    	int retrans;
    	struct sip_pvt *owner;
    	int packetlen;
    	char data[SIP_MAX_PACKET];
    	struct sip_pkt *next;
    } *packets = NULL;	
    
    struct sip_user {
    	/* Users who can access various contexts */
    	char name[80];
    	char secret[80];
    	char context[80];
    	char callerid[80];
    	char methods[80];
    	char accountcode[80];
    	int hascallerid;
    	int amaflags;
    	int insecure;
    	struct ast_ha *ha;
    	struct sip_user *next;
    };
    
    struct sip_peer {
    	char name[80];
    	char secret[80];
    	char methods[80];
    	char username[80];
    	int dynamic;
    	int expire;
    	int expirey;
    	int capability;
    	int insecure;
    	struct sockaddr_in addr;
    	struct in_addr mask;
    	
    	struct sockaddr_in defaddr;
    	struct ast_ha *ha;
    	int delme;
    	struct sip_peer *next;
    };
    
    static struct ast_user_list {
    	struct sip_user *users;
    	pthread_mutex_t lock;
    } userl = { NULL, AST_MUTEX_INITIALIZER };
    
    static struct ast_peer_list {
    	struct sip_peer *peers;
    	pthread_mutex_t lock;
    } peerl = { NULL, AST_MUTEX_INITIALIZER };
    
    
    static int sipsock  = -1;
    
    static struct sockaddr_in bindaddr;
    
    #ifdef SIPDUMPER
    
    static void sip_dump_packet(char *data, int len)
    {
    	printf("SIP Packet Dump\n");
    	printf("================\n");
    	printf("Data: \n%s\n", data);
    	fflush(stdout);
    }
    
    #endif
    
    static struct ast_frame  *sip_read(struct ast_channel *ast);
    static int transmit_response(struct sip_pvt *p, char *msg);
    static int transmit_response_with_sdp(struct sip_pvt *p, char *msg);
    static int transmit_request(struct sip_pvt *p, char *msg, int inc);
    static int transmit_invite_with_sdp(struct sip_pvt *p, char *msg);
    
    static int __sip_xmit(struct sip_pvt *p, char *data, int len)
    {
    	int res;
        res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in));
    	if (res != len) {
    		ast_log(LOG_WARNING, "sip_xmit returned %d\n", res);
    	}
    	return res;
    }
    
    static int send_response(struct sip_pvt *p, struct sip_request *req)
    {
    	int res;
    	printf("Transmitting:\n%s\n", req->data);
    	res = __sip_xmit(p, req->data, req->len);
    	if (res > 0)
    		res = 0;
    	return res;
    }
    
    static int send_request(struct sip_pvt *p, struct sip_request *req)
    {
    	int res;
    	printf("XXX Need to handle Retransmitting XXX:\n%s\n", req->data);
    	res = __sip_xmit(p, req->data, req->len);
    	return res;
    }
    
    static char *ditch_braces(char *tmp)
    {
    	char *c = tmp;
    	char *n;
    	c = tmp;
    	if ((n = strchr(tmp, '<')) ) {
    		c = n + 1;
    		while(*c && *c != '>') c++;
    		if (*c != '>') {
    			ast_log(LOG_WARNING, "No closing brace in '%s'\n", tmp);
    		} else {
    			*c = '\0';
    		}
    		return n+1;
    	}
    	return c;
    }
    
    static int sip_digit(struct ast_channel *ast, char digit)
    {
    	printf("SIP digit! (%c)\n", digit);
    	return 0;
    }
    
    static int create_addr(struct sockaddr_in *sin, int *capability, char *peer, char *username, int *insecure)
    {
    	struct hostent *hp;
    	struct sip_peer *p;
    	int found=0;
    	sin->sin_family = AF_INET;
    	ast_pthread_mutex_lock(&peerl.lock);
    	p = peerl.peers;
    	while(p) {
    		if (!strcasecmp(p->name, peer)) {
    			found++;
    			if (capability)
    				*capability = p->capability;
    			if (username)
    				strncpy(username, p->username, 80);
    			if (insecure)
    				*insecure = p->insecure;
    			if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) {
    				if (p->addr.sin_addr.s_addr) {
    					sin->sin_addr = p->addr.sin_addr;
    					sin->sin_port = p->addr.sin_port;
    				} else {
    					sin->sin_addr = p->defaddr.sin_addr;
    					sin->sin_port = p->defaddr.sin_port;
    				}
    				break;
    			}
    		}
    		p = p->next;
    	}
    	ast_pthread_mutex_unlock(&peerl.lock);
    	if (!p && !found) {
    		hp = gethostbyname(peer);
    		if (hp) {
    			memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
    			sin->sin_port = htons(DEFAULT_SIP_PORT);
    			return 0;
    		} else {
    			ast_log(LOG_WARNING, "No such host: %s\n", peer);
    			return -1;
    		}
    	} else if (!p)
    		return -1;
    	else
    		return 0;
    }
    
    static int sip_call(struct ast_channel *ast, char *dest, int timeout)
    {
    	int res;
    	struct sip_pvt *p;
    	char *ext, *host;
    	char tmp[256];
    	char username[81];
    	strncpy(tmp, dest, sizeof(tmp) - 1);
    	
    	p = ast->pvt->pvt;
    	if ((ast->state != AST_STATE_DOWN) && (ast->state != AST_STATE_RESERVED)) {
    		ast_log(LOG_WARNING, "sip_call called on %s, neither down nor reserved\n", ast->name);
    		return -1;
    	}
    	host = strchr(tmp, '@');
    	if (host) {
    		*host = '\0';
    		host++;
    		ext = tmp;
    	} else {
    		host = tmp;
    		ext = NULL;
    	}
    	if (create_addr(&p->sa, &p->capability, host, username, &p->insecure)) {
    		return -1;
    	}
    	if (!ext && strlen(username))
    		ext = username;
    	res = 0;
    	p->outgoing = 1;
    	transmit_invite_with_sdp(p, username);
    	printf("Calling extension '%s' at '%s'\n", ext ? ext : "<none>", host);
    	return res;
    }
    
    static void __sip_destroy(struct sip_pvt *p)
    {
    	struct sip_pvt *cur, *prev = NULL;
    	if (p->rtp) {
    		ast_rtp_destroy(p->rtp);
    	}
    	cur = iflist;
    	while(cur) {
    		if (cur == p) {
    			if (prev)
    				prev->next = cur->next;
    			else
    				iflist = cur->next;
    			break;
    		}
    		prev = cur;
    		cur = cur->next;
    	}
    	if (!cur) {
    		ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur);
    	} else
    		free(p);
    }
    static void sip_destroy(struct sip_pvt *p)
    {
    	ast_pthread_mutex_lock(&iflock);
    	__sip_destroy(p);
    	ast_pthread_mutex_unlock(&iflock);
    }
    
    
    static int sip_hangup(struct ast_channel *ast)
    {
    	struct sip_pvt *p;
    	if (option_debug)
    		ast_log(LOG_DEBUG, "sip_hangup(%s)\n", ast->name);
    	if (!ast->pvt->pvt) {
    		ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
    		return 0;
    	}
    	p = ast->pvt->pvt;
    	if (!p->alreadygone && strlen(p->initreq.data)) {
    		if (!p->owner || p->owner->state != AST_STATE_UP)
    			transmit_request(p, "CANCEL", 0);
    		else
    			/* Send a hangup */
    			transmit_request(p, "BYE", 1);
    	}
    	p->needdestroy = 1;
    	p->owner = NULL;
    	p->outgoing = 0;
    	ast->pvt->pvt = NULL;
    	printf("SIP Hangup!\n");
    	return 0;
    }
    
    static int sip_answer(struct ast_channel *ast)
    {
    	int res = 0;
    	struct sip_pvt *p = ast->pvt->pvt;
    	if (ast->state != AST_STATE_UP) {
    		ast->state = AST_STATE_UP;
    		if (option_debug)
    			ast_log(LOG_DEBUG, "sip_answer(%s)\n", ast->name);
    		res = transmit_response_with_sdp(p, "200 OK");
    	}
    	return res;
    }
    
    static struct ast_frame  *sip_read(struct ast_channel *ast)
    {
    	ast_log(LOG_WARNING, "I should never get called but am on %s!\n", ast->name);
    	return NULL;
    }
    
    static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
    {
    	struct sip_pvt *p = ast->pvt->pvt;
    	if (p->rtp) {
    		return ast_rtp_write(p->rtp, frame);
    	}
    	return 0;
    }
    
    static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    {
    	struct sip_pvt *p = newchan->pvt->pvt;
    	if (p->owner != oldchan) {
    		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
    		return -1;
    	}
    	p->owner = newchan;
    	return 0;
    }
    
    static int sip_indicate(struct ast_channel *ast, int condition)
    {
    	struct sip_pvt *p = ast->pvt->pvt;
    	switch(condition) {
    	case AST_CONTROL_RINGING:
    		if (ast->state == AST_STATE_RING) {
    			transmit_response(p, "180 Ringing");
    		} else {
    			ast_log(LOG_WARNING, "XXX Need to send in-band ringtone XXX\n");
    		}
    		break;
    	case AST_CONTROL_BUSY:
    		if (ast->state != AST_STATE_UP) {
    			transmit_response(p, "600 Busy everywhere");
    		} else {
    			ast_log(LOG_WARNING, "XXX Need to send in-band busy tone XXX\n");
    		}
    		break;
    	case AST_CONTROL_CONGESTION:
    		if (ast->state != AST_STATE_UP) {
    			transmit_response(p, "486 Busy here");
    		} else {
    			ast_log(LOG_WARNING, "XXX Need to send in-band congestion tone XXX\n");
    		}
    		break;
    	default:
    		printf("Don't know how to indicate condition %d\n", condition);
    	}
    	return 0;
    }
    
    static struct ast_channel *sip_new(struct sip_pvt *i, int state)
    {
    	struct ast_channel *tmp;
    	int fmt;
    	tmp = ast_channel_alloc(1);
    	if (tmp) {
    		tmp->nativeformats = i->capability;
    		if (!tmp->nativeformats)
    			tmp->nativeformats = capability;
    		fmt = ast_best_codec(tmp->nativeformats);
    		snprintf(tmp->name, sizeof(tmp->name), "SIP/%s:%d", inet_ntoa(i->sa.sin_addr), ntohs(i->sa.sin_port));
    		tmp->type = type;
    		tmp->state = state;
    		if (state == AST_STATE_RING)
    			tmp->rings = 1;
    		tmp->writeformat = fmt;
    		tmp->pvt->rawwriteformat = fmt;
    		tmp->readformat = fmt;
    		tmp->pvt->rawreadformat = fmt;
    		tmp->pvt->pvt = i;
    		tmp->pvt->send_digit = sip_digit;
    		tmp->pvt->call = sip_call;
    		tmp->pvt->hangup = sip_hangup;
    		tmp->pvt->answer = sip_answer;
    		tmp->pvt->read = sip_read;
    		tmp->pvt->write = sip_write;
    		tmp->pvt->indicate = sip_indicate;
    		tmp->pvt->fixup = sip_fixup;
    		if (strlen(i->language))
    			strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
    		i->owner = tmp;
    		ast_pthread_mutex_lock(&usecnt_lock);
    		usecnt++;
    		ast_pthread_mutex_unlock(&usecnt_lock);
    		ast_update_use_count();
    		strncpy(tmp->context, i->context, sizeof(tmp->context)-1);
    		strncpy(tmp->exten, i->exten, sizeof(tmp->exten)-1);
    		tmp->priority = 1;
    		if (state != AST_STATE_DOWN) {
    			if (ast_pbx_start(tmp)) {
    				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
    				ast_hangup(tmp);
    				tmp = NULL;
    			}
    		}
    	} else
    		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
    	return tmp;
    }
    
    static struct cfalias {
    	char *fullname;
    	char *shortname;
    } aliases[] = {
    	{ "Content-Type", "c" },
    	{ "Content-Encoding", "e" },
    	{ "From", "f" },
    	{ "Call-ID", "i" },
    	{ "Contact", "m" },
    	{ "Content-Length", "l" },
    	{ "Subject", "s" },
    	{ "To", "t" },
    	{ "Via", "v" },
    };
    
    static char *get_sdp(struct sip_request *req, char *name)
    {
    	int x;
    	int len = strlen(name);
    	char *r;
    	for (x=0;x<req->lines;x++) {
    		if (!strncasecmp(req->line[x], name, len) && 
    				(req->line[x][len] == '=')) {
    					r = req->line[x] + len + 1;
    					while(*r && (*r < 33))
    							r++;
    					return r;
    		}
    	}
    	return "";
    }
    
    static char *get_header(struct sip_request *req, char *name)
    {
    	int x;
    	int len = strlen(name);
    	char *r;
    	for (x=0;x<req->headers;x++) {
    		if (!strncasecmp(req->header[x], name, len) && 
    				(req->header[x][len] == ':')) {
    					r = req->header[x] + len + 1;
    					while(*r && (*r < 33))
    							r++;
    					return r;
    		}
    	}
    	/* Try aliases */
    	for (x=0;x<sizeof(aliases) / sizeof(aliases[0]); x++) 
    		if (!strcasecmp(aliases[x].fullname, name)) 
    			return get_header(req, aliases[x].shortname);
    
    	/* Don't return NULL, so get_header is always a valid pointer */
    	return "";
    }
    
    static int rtpready(struct ast_rtp *rtp, struct ast_frame *f, void *data)
    {
    	/* Just deliver the audio directly */
    	struct sip_pvt *p = data;
    	if (p->owner)
    		ast_queue_frame(p->owner, f, 1);
    	return 0;
    }
    
    static void build_callid(char *callid, int len)
    {
    	int res;
    	int val;
    	int x;
    	for (x=0;x<4;x++) {
    		val = rand();
    		res = snprintf(callid, len, "%08x", val);
    		len -= res;
    		callid += res;
    	}
    	snprintf(callid, len, "@%s", inet_ntoa(ourip));
    }
    
    static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin)
    {
    	struct sip_pvt *p;
    	p = malloc(sizeof(struct sip_pvt));
    	if (!p)
    		return NULL;
    	/* Keep track of stuff */
    	memset(p, 0, sizeof(struct sip_pvt));
    	if (!callid)
    		build_callid(p->callid, sizeof(p->callid));
    	else
    		strncpy(p->callid, callid, sizeof(p->callid) - 1);
    	if (sin)
    		memcpy(&p->sa, sin, sizeof(p->sa));
    	p->rtp = ast_rtp_new(sched, io);
    	ast_rtp_set_data(p->rtp, p);
    	ast_rtp_set_callback(p->rtp, rtpready);
    	if (!p->rtp) {
    		ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
    		free(p);
    		return NULL;
    	}
    	
    	/* Add to list */
    	ast_pthread_mutex_lock(&iflock);
    	p->next = iflist;
    	iflist = p;
    	ast_pthread_mutex_unlock(&iflock);
    	return p;
    }
    
    static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin)
    {
    	struct sip_pvt *p;
    	char *callid;
    	callid = get_header(req, "Call-ID");
    	if (!strlen(callid)) {
    		ast_log(LOG_WARNING, "Call missing call ID from '%s'\n", inet_ntoa(sin->sin_addr));
    		return NULL;
    	}
    	ast_pthread_mutex_lock(&iflock);
    	p = iflist;
    	while(p) {
    		if (!strcmp(p->callid, callid)) {
    			/* Found the call */
    #if 0
    			if (!p->insecure && ((p->sa.sin_addr.s_addr != sin->sin_addr.s_addr) ||
    			    (p->sa.sin_port != sin->sin_port))) {
    					char orig[80];
    					char new[80];
    					snprintf(orig, sizeof(orig), "%s:%d", inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
    					snprintf(new, sizeof(new), "%s:%d", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
    					ast_log(LOG_WARNING, "Looks like %s is trying to steal call '%s' from %s?\n", new, p->callid, orig);
    					ast_pthread_mutex_unlock(&iflock);
    					return NULL;
    			}
    #endif
    			ast_pthread_mutex_unlock(&iflock);
    			return p;
    		}
    		p = p->next;
    	}
    	ast_pthread_mutex_unlock(&iflock);
    	return sip_alloc(callid, sin);
    }
    
    static void parse(struct sip_request *req)
    {
    	/* Divide fields by NULL's */
    	char *c;
    	int f = 0;
    	c = req->data;
    
    	/* First header starts immediately */
    	req->header[f] = c;
    	while(*c) {
    		if (*c == '\n') {
    			/* We've got a new header */
    			*c = 0;
    
    #if 0
    			printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
    #endif			
    			if (!strlen(req->header[f])) {
    				/* Line by itself means we're now in content */
    				c++;
    				break;
    			}
    			if (f >= SIP_MAX_HEADERS - 1) {
    				ast_log(LOG_WARNING, "Too many SIP headers...\n");
    			} else
    				f++;
    			req->header[f] = c + 1;
    		} else if (*c == '\r') {
    			/* Ignore but eliminate \r's */
    			*c = 0;
    		}
    		c++;
    	}
    	/* Check for last header */
    	if (strlen(req->header[f])) 
    		f++;
    	req->headers = f;
    	/* Now we process any mime content */
    	f = 0;
    	req->line[f] = c;
    	while(*c) {
    		if (*c == '\n') {
    			/* We've got a new line */
    			*c = 0;
    #if 0
    			printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
    #endif			
    			if (f >= SIP_MAX_LINES - 1) {
    				ast_log(LOG_WARNING, "Too many SDP lines...\n");
    			} else
    				f++;
    			req->line[f] = c + 1;
    		} else if (*c == '\r') {
    			/* Ignore and eliminate \r's */
    			*c = 0;
    		}
    		c++;
    	}
    	/* Check for last line */
    	if (strlen(req->line[f])) 
    		f++;
    	req->lines = f;
    	printf("%d headers, %d lines\n", req->headers, req->lines);
    	if (*c) 
    		ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
    }
    
    static int process_sdp(struct sip_pvt *p, struct sip_request *req)
    {
    	char *m;
    	char *c;
    	char host[258];
    	int len;
    	int portno;
    	int peercapability;
    	struct sockaddr_in sin;
    	char *codecs;
    	struct hostent *hp;
    	int codec;
    	/* Get codec and RTP info from SDP */
    	if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
    		ast_log(LOG_NOTICE, "Content is '%s', not 'application/sdp'\n", get_header(req, "Content-Type"));
    		return -1;
    	}
    	m = get_sdp(req, "m");
    	c = get_sdp(req, "c");
    	if (!strlen(m) || !strlen(c)) {
    		ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
    		return -1;
    	}
    	if (sscanf(c, "IN IP4 %256s", host) != 1) {
    		ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
    		return -1;
    	}
    	/* XXX This could block for a long time, and block the main thread! XXX */
    	hp = gethostbyname(host);
    	if (!hp) {
    		ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
    		return -1;
    	}
    	if (sscanf(m, "audio %d RTP/AVP %n", &portno, &len) != 1) {
    		ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m); 
    		return -1;
    	}
    	sin.sin_family = AF_INET;
    	memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
    	sin.sin_port = htons(portno);
    	ast_rtp_set_peer(p->rtp, &sin);
    #if 0
    	printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
    #endif	
    	peercapability = 0;
    	codecs = m + len;
    	while(strlen(codecs)) {
    		if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
    			ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
    			return -1;
    		}
    #if 0
    		printf("Codec: %d\n", codec);
    #endif		
    		codec = rtp2ast(codec);
    		if (codec  > -1)
    			peercapability |= codec;
    		codecs += len;
    	}
    	p->capability = capability & peercapability;
    	printf("Capabilities: us - %d, them - %d, combined - %d\n",
    		capability, peercapability, p->capability);
    	if (!p->capability) {
    		ast_log(LOG_WARNING, "No compatible codecs!\n");
    		return -1;
    	}
    	return 0;
    	
    }
    
    static int add_header(struct sip_request *req, char *var, char *value)
    {
    	if (req->lines) {
    		ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
    		return -1;
    	}
    	req->header[req->headers] = req->data + req->len;
    	req->len += snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
    	if (req->headers < SIP_MAX_HEADERS)
    		req->headers++;
    	else {
    		ast_log(LOG_WARNING, "Out of header space\n");
    		return -1;
    	}
    	return 0;	
    }
    
    static int add_blank_header(struct sip_request *req)
    {
    	if (req->lines) {
    		ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
    		return -1;
    	}
    	req->header[req->headers] = req->data + req->len;
    	req->len += snprintf(req->header[req->headers], sizeof(req->data) - req->len, "\r\n");
    	if (req->headers < SIP_MAX_HEADERS)
    		req->headers++;
    	else {
    		ast_log(LOG_WARNING, "Out of header space\n");
    		return -1;
    	}
    	return 0;	
    }
    
    static int add_line(struct sip_request *req, char *line)
    {
    	if (!req->lines) {
    		/* Add extra empty return */
    		req->len += snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
    	}
    	req->line[req->lines] = req->data + req->len;
    	req->len += snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
    	if (req->lines < SIP_MAX_LINES)
    		req->lines++;
    	else {
    		ast_log(LOG_WARNING, "Out of line space\n");
    		return -1;
    	}
    	return 0;	
    }
    
    static int copy_header(struct sip_request *req, struct sip_request *orig, char *field)
    {
    	char *tmp;
    	tmp = get_header(orig, field);
    	if (strlen(tmp)) {
    		/* Add what we're responding to */
    		return add_header(req, field, tmp);
    	}
    	ast_log(LOG_NOTICE, "No field '%s' present to copy\n", field);
    	return -1;
    }
    
    static int init_resp(struct sip_request *req, char *resp, struct sip_request *orig)
    {
    	/* Initialize a response */
    	if (req->headers || req->len) {
    		ast_log(LOG_WARNING, "Request already initialized?!?\n");
    		return -1;
    	}
    	req->header[req->headers] = req->data + req->len;
    	req->len += snprintf(req->header[req->headers], sizeof(req->data) - req->len, "SIP/2.0 %s\r\n", resp);
    	if (req->headers < SIP_MAX_HEADERS)
    		req->headers++;
    	else
    		ast_log(LOG_WARNING, "Out of header space\n");
    	return 0;
    }
    
    static int init_req(struct sip_request *req, char *resp, char *recip)
    {
    	/* Initialize a response */
    	if (req->headers || req->len) {
    		ast_log(LOG_WARNING, "Request already initialized?!?\n");
    		return -1;
    	}
    	req->header[req->headers] = req->data + req->len;
    	req->len += snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s SIP/2.0\r\n", resp, recip);
    	if (req->headers < SIP_MAX_HEADERS)
    		req->headers++;
    	else
    		ast_log(LOG_WARNING, "Out of header space\n");
    	return 0;
    }
    
    static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg)
    {
    	struct sip_request *req = &p->initreq;
    	memset(resp, 0, sizeof(*resp));
    	init_resp(resp, msg, req);
    	copy_header(resp, req, "Via");
    	copy_header(resp, req, "From");
    	copy_header(resp, req, "To");
    	copy_header(resp, req, "Call-ID");
    	copy_header(resp, req, "CSeq");
    	add_header(resp, "User-Agent", "Asterisk PBX");
    	if (p->expirey) {
    		/* For registration responses, we also need expirey and
    		   contact info */
    		char tmp[80];
    		char contact2[256], *c, contact[256];
    		snprintf(tmp, sizeof(tmp), "%d", p->expirey);
    #if 1
    		/* XXX This isn't exactly right and it's implemented
    		       very stupidly *sigh* XXX */
    		strncpy(contact2, get_header(req, "Contact"), sizeof(contact2)-1);
    		c = ditch_braces(contact2);
    		snprintf(contact, sizeof(contact), "<%s>", c);
    #endif
    		add_header(resp, "Expires", tmp);
    		add_header(resp, "Contact", contact);
    	}
    	return 0;
    }
    
    static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int inc)
    {
    	struct sip_request *orig = &p->initreq;
    	char stripped[80];
    	char tmp[80];
    	char *c, *n;
    	char *ot, *of;
    
    	memset(req, 0, sizeof(struct sip_request));
    	if (inc)
    		p->cseq++;
    
    	
    	if (p->outgoing)
    		strncpy(stripped, get_header(orig, "To"), sizeof(stripped) - 1);
    	else
    		strncpy(stripped, get_header(orig, "From"), sizeof(stripped) - 1);
    	
    	c = strchr(stripped, '<');
    	if (c) 
    		c++;
    	else
    		c = stripped;
    	n = strchr(c, '>');
    	if (n)
    		*n = '\0';
    	
    	init_req(req, msg, c);
    
    	snprintf(tmp, sizeof(tmp), "%d %s", p->cseq, msg);
    	add_header(req, "CSeq", tmp);
    
    	copy_header(req, orig, "Via");
    
    	ot = get_header(orig, "To");
    	of = get_header(orig, "From");
    	if (p->outgoing) {
    		add_header(req, "From", of);
    		add_header(req, "To", ot);
    	} else {
    		add_header(req, "From", ot);
    		add_header(req, "To", of);
    	}
    
    	copy_header(req, orig, "Call-ID");
    	add_header(req, "User-Agent", "Asterisk PBX");
    	return 0;
    }
    
    static int transmit_response(struct sip_pvt *p, char *msg)
    {
    	struct sip_request resp;
    	respprep(&resp, p, msg);
    	add_header(&resp, "Content-Length", "0");
    	add_blank_header(&resp);
    	return send_response(p, &resp);
    }
    
    static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
    {
    	int len;
    	int codec;
    	char costr[80];
    	struct sockaddr_in sin;
    	char v[256];
    	char s[256];
    	char o[256];
    	char c[256];
    	char t[256];
    	char m[256];
    	int x;
    	/* XXX We break with the "recommendation" and send our IP, in order that our
    	       peer doesn't have to gethostbyname() us XXX */
    	len = 0;
    	ast_rtp_get_us(p->rtp, &sin);
    	printf("We're at %s port %d\n", inet_ntoa(ourip), ntohs(sin.sin_port));	
    	snprintf(v, sizeof(v), "v=0\r\n");
    	snprintf(s, sizeof(s), "s=Asterisk Call from %s\r\n", ourhost);
    	snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", getpid(), getpid(), inet_ntoa(ourip));
    	snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", inet_ntoa(ourip));
    	snprintf(t, sizeof(t), "t=0 0\r\n");
    	snprintf(m, sizeof(m), "m=audio %d RTP/AVP 101", ntohs(sin.sin_port));
    	for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
    		if (p->capability & x) {
    			printf("Answering with capability %d\n", x);
    			if ((codec = ast2rtp(x)) > -1) {
    				snprintf(costr, sizeof(costr), " %d", codec);
    				strcat(m, costr);
    			}