📄 register.c
字号:
/* Copyright (C) 2002-2005 Thomas Ries <tries@gmx.net> This file is part of Siproxd. Siproxd 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. Siproxd 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 Siproxd; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "config.h"#include <stdio.h>#include <time.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <osipparser2/osip_parser.h>#include "siproxd.h"#include "log.h"static char const ident[]="$Id: register.c,v 1.60 2006/10/13 17:40:09 hb9xar Exp $";/* configuration storage */extern struct siproxd_config configuration;/* URL mapping table */struct urlmap_s urlmap[URLMAP_SIZE];/* time of last save */static time_t last_save=0;extern int errno;/* * initialize the URL mapping table */void register_init(void) { FILE *stream; int sts, i; size_t len; char buff[128]; memset(urlmap, 0, sizeof(urlmap)); if (configuration.registrationfile) { stream = fopen(configuration.registrationfile, "r"); if (!stream) { /* * the file does not exist, or the size was incorrect, * delete it and start from scratch */ unlink(configuration.registrationfile); WARN("registration file not found, starting with empty table"); } else { /* read the url table from file */ for (i=0;i < URLMAP_SIZE; i++) { fgets(buff, sizeof(buff), stream); sts=sscanf(buff, "***:%i:%i", &urlmap[i].active, &urlmap[i].expires); if (sts == 0) break; /* format error */ if (urlmap[i].active) { osip_uri_init(&urlmap[i].true_url); osip_uri_init(&urlmap[i].masq_url); osip_uri_init(&urlmap[i].reg_url); #define R(X) {\ fgets(buff, sizeof(buff), stream);\ buff[sizeof(buff)-1]='\0';\ if (strchr(buff, 10)) *strchr(buff, 10)='\0';\ if (strchr(buff, 13)) *strchr(buff, 13)='\0';\ if (strlen(buff) > 0) {\ len = strlen(buff);\ X =(char*)malloc(len+1);\ sts=sscanf(buff,"%s",X);\ if (sts == 0) break;\ } else {\ X = NULL;\ }\ } R(urlmap[i].true_url->scheme); R(urlmap[i].true_url->username); R(urlmap[i].true_url->host); R(urlmap[i].true_url->port); R(urlmap[i].masq_url->scheme); R(urlmap[i].masq_url->username); R(urlmap[i].masq_url->host); R(urlmap[i].masq_url->port); R(urlmap[i].reg_url->scheme); R(urlmap[i].reg_url->username); R(urlmap[i].reg_url->host); R(urlmap[i].reg_url->port); } } fclose(stream); /* check for premature abort of reading the registration file */ if (i < URLMAP_SIZE) { /* clean up and delete it */ WARN("registration file corrupt, starting with empty table"); memset(urlmap, 0, sizeof(urlmap)); unlink(configuration.registrationfile); } } } /* initialize save-timer */ time(&last_save); return;}/* * shut down the URL mapping table */void register_save(void) { int i; FILE *stream; if (configuration.registrationfile) { /* write urlmap back to file */ stream = fopen(configuration.registrationfile, "w+"); if (!stream) { /* try to unlink it and open again */ unlink(configuration.registrationfile); stream = fopen(configuration.registrationfile, "w+"); /* open file for write failed, complain */ if (!stream) { ERROR("unable to write registration file"); return; } } for (i=0;i < URLMAP_SIZE; i++) { fprintf(stream, "***:%i:%i\n", urlmap[i].active, urlmap[i].expires); if (urlmap[i].active) { #define W(X) fprintf(stream, "%s\n", (X)? X:""); W(urlmap[i].true_url->scheme); W(urlmap[i].true_url->username); W(urlmap[i].true_url->host); W(urlmap[i].true_url->port); W(urlmap[i].masq_url->scheme); W(urlmap[i].masq_url->username); W(urlmap[i].masq_url->host); W(urlmap[i].masq_url->port); W(urlmap[i].reg_url->scheme); W(urlmap[i].reg_url->username); W(urlmap[i].reg_url->host); W(urlmap[i].reg_url->port); } } fclose(stream); } return;}/* * handles register requests and updates the URL mapping table * * RETURNS: * STS_SUCCESS : successfully registered * STS_FAILURE : registration failed * STS_NEED_AUTH : authentication needed */int register_client(sip_ticket_t *ticket, int force_lcl_masq) { int i, j, n, sts; int expires; time_t time_now; osip_contact_t *contact; osip_uri_t *url1_to, *url1_contact=NULL; osip_uri_t *url2_to; osip_header_t *expires_hdr; osip_uri_param_t *expires_param=NULL; /* * Authorization - do only if I'm not just acting as outbound proxy * but am ment to be the registrar */ if (force_lcl_masq == 0) { /* * RFC 3261, Section 16.3 step 6 * Proxy Behavior - Request Validation - Proxy-Authorization */ sts = authenticate_proxy(ticket->sipmsg); if (sts == STS_FAILURE) { /* failed */ WARN("proxy authentication failed for %s@%s", (ticket->sipmsg->to->url->username)? ticket->sipmsg->to->url->username : "*NULL*", ticket->sipmsg->to->url->host); return STS_FAILURE; } else if (sts == STS_NEED_AUTH) { /* needed */ DEBUGC(DBCLASS_REG,"proxy authentication needed for %s@%s", ticket->sipmsg->to->url->username, ticket->sipmsg->to->url->host); return STS_NEED_AUTH; } }/* fetch 1st Via entry and remember this address. Incoming requests for the registered address have to be passed on to that host. To: -> address to be registered Contact: -> host is reachable there Note: in case of un-REGISTER, the contact header may contain '*' only - which means "all registrations made by this UA" => Mapping is To: <1--n> Contact */ time(&time_now); DEBUGC(DBCLASS_BABBLE,"sip_register:"); /* * First make sure, we have a proper Contact header: * - url * - url -> hostname * * Libosip parses an: * "Contact: *" * the following way (Note: Display name!! and URL is NULL) * (gdb) p *((osip_contact_t*)(sip->contacts->node->element)) * $5 = {displayname = 0x8af8848 "*", url = 0x0, gen_params = 0x8af8838} */ osip_message_get_contact(ticket->sipmsg, 0, &contact); if ((contact == NULL) || (contact->url == NULL) || (contact->url->host == NULL)) { /* Don't have required Contact fields. This may be a Registration query or unregistering all registered records for this UA. We should simply forward this request to its destination. However, if this is an unregistration from a client that is not registered (Grandstream "unregister at startup" option) -> How do I handle this one? Right now we do a direction lookup and if this fails we generate an OK message by ourself (fake) */ DEBUGC(DBCLASS_REG, "empty Contact header - " "seems to be a registration query"); sts = sip_find_direction(ticket, NULL); if (sts != STS_SUCCESS) { /* answer the request myself. Most likely this is an UNREGISTER * request when the client just booted */ sts = register_response(ticket, STS_SUCCESS); return STS_SIP_SENT; } return STS_SUCCESS; } url1_contact=contact->url; /* evaluate Expires Header field */ osip_message_get_expires(ticket->sipmsg, 0, &expires_hdr); /* * look for an Contact expires parameter - in case of REGISTER * these two are equal. The Contact expires has higher priority! */ if (ticket->sipmsg->contacts && ticket->sipmsg->contacts->node && ticket->sipmsg->contacts->node->element) { osip_contact_param_get_byname( (osip_contact_t*) ticket->sipmsg->contacts->node->element, EXPIRES, &expires_param); } if (expires_param && expires_param->gvalue) { /* get expires from contact Header */ expires=atoi(expires_param->gvalue); if ((expires < 0) || (expires >= LONG_MAX)) expires=configuration.default_expires; } else if (expires_hdr && expires_hdr->hvalue) { /* get expires from expires Header */ expires=atoi(expires_hdr->hvalue); if ((expires < 0) || (expires >= LONG_MAX)) expires=configuration.default_expires; } else { char tmp[16]; /* it seems, the expires field is not present everywhere... */ DEBUGC(DBCLASS_REG,"no 'expires' header found - set time to %i sec", configuration.default_expires); expires=configuration.default_expires; sprintf(tmp,"%i",expires); osip_message_set_expires(ticket->sipmsg, tmp); } url1_to=ticket->sipmsg->to->url; /* * REGISTER */ if (expires > 0) { DEBUGC(DBCLASS_REG,"register: %s@%s expires=%i seconds", (url1_contact->username) ? url1_contact->username : "*NULL*", (url1_contact->host) ? url1_contact->host : "*NULL*", expires); /* * Update registration. There are two possibilities: * - already registered, then update the existing record * - not registered, then create a new record */ j=-1; for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) { if (j < 0) j=i; /* remember first hole */ continue; } url2_to=urlmap[i].reg_url; /* check address-of-record ("public address" of user) */ if (compare_url(url1_to, url2_to)==STS_SUCCESS) { DEBUGC(DBCLASS_REG, "found entry for %s@%s <-> %s@%s at " "slot=%i, exp=%li", (url1_contact->username) ? url1_contact->username : "*NULL*", (url1_contact->host) ? url1_contact->host : "*NULL*", (url2_to->username) ? url2_to->username : "*NULL*", (url2_to->host) ? url2_to->host : "*NULL*", i, (long)urlmap[i].expires-time_now); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -