21 static volatile bool warning_registry =
false;
22 static bool shutdown_flag =
false;
23 static unsigned shutdown_count = 0;
24 static unsigned startup_count = 0;
25 static unsigned active_count = 0;
27 static char *remove_quotes(
char *c)
61 case EXOSIP_REGISTRATION_REFRESHED:
70 case EXOSIP_CALL_TIMEOUT:
98 case EXOSIP_REGISTRATION_TERMINATED:
144 const char *tmp = NULL;
146 bool presence =
false;
149 const char *content = msgtype;
150 const char *expires = NULL;
151 const char *
event = NULL;
170 if(msgheader && msgheader->
hvalue)
171 expires = msgheader->
hvalue;
175 if(msgheader && msgheader->
hvalue)
176 event = msgheader->
hvalue;
179 snprintf(msgtype,
sizeof(msgtype),
"%s/%s", ct->
type, ct->
subtype);
180 else if(ct && ct->
type)
181 String::set(msgtype,
sizeof(msgtype), ct->
type);
189 if(event && stricmp(event,
"presence")) {
196 if(!strnicmp(tmp,
"<presence", 9))
198 else if(!strnicmp(tmp,
"</basic", 7))
200 else if(!strnicmp(tmp,
"</status>", 9))
202 else if(!strnicmp(tmp,
"<basic>open", 11) && basic) {
206 else if(!strnicmp(tmp,
"<show>dnd", 9) && presence) {
210 else if(!strnicmp(tmp,
"<basic>closed", 13) && basic) {
214 else if(!strnicmp(tmp,
"available", 9) && presence) {
218 else if(!strnicmp(tmp,
"unavailable", 11) && presence) {
222 else if(!strnicmp(tmp,
"on-the-phone", 12) && presence) {
226 else if(!strnicmp(tmp,
"online", 6) && presence) {
230 else if(!strnicmp(tmp,
"busy", 4) && presence) {
234 else if(!strnicmp(tmp,
"dnd", 3) && presence) {
238 else if(!strnicmp(tmp,
"vacation", 8) && presence)
243 else if(!strnicmp(tmp,
"away", 4) && presence)
268 const char *
id = NULL;
269 const char *digest = NULL;
270 const char *hash = NULL;
281 String::set(target,
sizeof(target),
id);
284 String::set(target,
sizeof(target),
requesting);
299 String::set(target,
sizeof(target),
requesting);
308 if(!body || !ct || !ct->
type) {
315 snprintf(msgtype,
sizeof(msgtype),
"%s/%s",
318 snprintf(msgtype,
sizeof(msgtype),
"%s",
322 snprintf(sysid,
sizeof(sysid),
"%u",
extension);
324 String::set(sysid,
sizeof(sysid),
identity);
328 snprintf(fromhdr,
sizeof(fromhdr),
329 "\"%u\" <%s;user=phone>",
extension, address);
331 snprintf(fromhdr,
sizeof(fromhdr),
332 "\"%s\" <%s>",
display, address);
334 snprintf(fromhdr,
sizeof(fromhdr),
337 shell::debug(3,
"sending message from %s to %s\n", sysid, target);
368 if(String::equal(
network,
"decline")) {
374 if(String::equal(
network,
"reject")) {
386 snprintf(fromext,
sizeof(fromext),
"%u",
extension);
390 if(msgheader && msgheader->
hvalue && msgheader->
hvalue[0]) {
397 if(msgheader && msgheader->
hvalue && msgheader->
hvalue[0])
400 String::set(call->
subject,
sizeof(call->
subject),
"inviting call");
404 if(msgheader && msgheader->
hvalue && atol(msgheader->
hvalue))
410 if(body && body->
body)
416 toext = atoi(target);
454 snprintf(call->
dialed,
sizeof(call->
dialed),
"%u", toext);
457 String::set(call->
dialed,
sizeof(call->
dialed), target);
460 shell::debug(1,
"calling self %08x:%u, id=%s\n",
463 String::set(call->
subject,
sizeof(call->
subject),
"calling self");
481 shell::debug(1,
"local call %08x:%u for %s from %s\n",
485 String::set(call->
dialed,
sizeof(call->
dialed), target);
499 shell::debug(1,
"incoming call %08x:%u for %s from %s\n",
544 shell::debug(1,
"outgoing call %08x:%u from %s to %s",
586 shell::debug(1,
"dialed call %08x:%u for %s from %s, dialing=%s\n",
590 String::set(cdrnode->
ident,
sizeof(cdrnode->
ident),
"unknown");
695 shell::debug(2,
"%s",
"challenge request required");
703 const char *scheme =
"sip";
708 const char *target = NULL;
713 const char *sep1 =
"", *sep2 =
"";
714 const char *refer = NULL;
715 const char *uri_host;
716 struct sockaddr_internet iface;
720 bool allowed =
false;
729 uri_host =
uri->host;
732 if(msgheader && msgheader->hvalue)
733 if(!stricmp(msgheader->hvalue,
"no") || !strnicmp(msgheader->hvalue,
"anon", 4))
757 if(strchr(uri_host,
':') != NULL && uri_host[0] !=
'[') {
762 if(
uri->username &&
uri->username[0]) {
763 if(
uri->port &&
uri->port[0])
765 uri->scheme,
uri->username, sep1, uri_host, sep2,
uri->port);
768 uri->scheme,
uri->username, sep1, uri_host, sep2);
771 if(
uri->port &&
uri->port[0])
773 uri->scheme, sep1, uri_host, sep2,
uri->port);
776 uri->scheme, sep1, uri_host, sep2);
779 if(
uri->port &&
uri->port[0])
780 local_port = atoi(
uri->port);
803 memset(&iface, 0,
sizeof(iface));
808 if(eq(
"localdomain", uri_host))
811 if(String::ifind(
stack::sip.localnames, uri_host,
" ,;:\t\n"))
823 shell::log(shell::ERR,
"unresolvable request: %s", uri_host);
839 shell::debug(2,
"authorizing local; target=%s\n",
uri->username);
840 target =
uri->username;
845 shell::debug(3,
"rewrite process; target=%s, dialing=%s\n", target,
dialing);
863 shell::debug(4,
"rewrite process; registry=%p, dialed=%p\n", (
void *)
reginfo, (
void *)
dialed.
keys);
898 shell::log(shell::NOTIFY,
"unregistered destination %s", target);
901 shell::log(shell::ERR,
"invalid destination %s, type=%s\n", target,
dialed.
keys->getId());
1007 goto static_routing;
1011 if(pp->
prefix[0] ==
'-') {
1012 if(!strnicmp(target, pp->
prefix + 1, strlen(pp->
prefix) - 1))
1013 target += strlen(pp->
prefix) - 1;
1014 }
else if(pp->
prefix[0]) {
1019 if(pp->
suffix[0] ==
'-') {
1049 if(!stricmp(
routed->getId(),
"refuse")) {
1056 if(!stricmp(
routed->getId(),
"redirect") || !stricmp(
routed->getId(),
"refer")) {
1060 if(cp && !strchr(cp,
'@')) {
1061 if(String::equal(cp,
"sip:", 4) || String::equal(cp,
"sips:", 5))
1064 snprintf(
buffer,
sizeof(
buffer),
"sip:%s@%s", target, cp);
1070 if(String::equal(cp,
"sip:", 4) || String::equal(cp,
"sips:"))
1086 if(cp && *cp ==
'-') {
1088 if(!strnicmp(target, cp, strlen(cp)))
1089 target += strlen(cp);
1091 if(strnicmp(target, cp, strlen(cp)))
1096 if(cp && *cp ==
'-') {
1103 if(!stricmp(
routed->getId(),
"rewrite")) {
1105 if(String::equal(
dialing,
"sips:", 5) || String::equal(
"sip:",
dialing, 4))
1106 snprintf(dbuf,
sizeof(dbuf),
"%s",
dialing);
1108 snprintf(dbuf,
sizeof(dbuf),
"sip:%s",
dialing);
1112 String::set(dbuf,
sizeof(dbuf),
dialing);
1166 shell::debug(1,
"rejecting invite from %s; error=%d\n",
getIdent(), error);
1170 shell::debug(1,
"rejecting unknown invite; error=%d\n", error);
1183 assert(error >= 100);
1218 const char *userid = NULL, *secret = NULL;
1267 stringbuf<64> digest;
1270 const char *hash = NULL;
1284 remove_quotes(auth->
uri);
1285 remove_quotes(auth->
nonce);
1293 shell::log(shell::NOTIFY,
"restricted %s from <%s> for %s:%u",
1298 shell::log(shell::NOTIFY,
"rejecting restricted %s", auth->
username);
1307 shell::log(shell::NOTIFY,
"rejecting unknown %s", auth->
username);
1316 if(!stricmp(node->getId(),
"reject")) {
1317 shell::log(shell::NOTIFY,
"rejecting user %s", auth->
username);
1325 leaf = node->leaf(
"extension");
1326 if(leaf && leaf->getPointer())
1329 leaf = node->leaf(
"display");
1330 if(leaf && leaf->getPointer())
1335 leaf = node->leaf(
"digest");
1336 if(!hash && (!leaf || !leaf->getPointer())) {
1337 shell::log(shell::NOTIFY,
"rejecting unsupported %s", auth->
username);
1352 snprintf(
buffer,
sizeof(
buffer),
"%s:%s:%s", leaf->getPointer(), auth->
nonce, *digest);
1360 if(stricmp(*digest, auth->
response)) {
1361 shell::log(shell::NOTIFY,
"rejecting unauthorized %s", auth->
username);
1381 snprintf(nonce,
sizeof(nonce),
"%08lx", (
long)now);
1383 "Digest realm=\"%s\", nonce=\"%s\", algorithm=%s",
1435 if(param != NULL && param->
gvalue != NULL)
1439 if(param != NULL && param->
gvalue != NULL)
1463 stringbuf<64> digest;
1469 const char *hash = NULL;
1478 remove_quotes(auth->
uri);
1479 remove_quotes(auth->
nonce);
1493 if(!stricmp(node->getId(),
"reject")) {
1503 leaf = node->leaf(
"digest");
1504 if(!hash && (!leaf || !leaf->getPointer())) {
1518 snprintf(
buffer,
sizeof(
buffer),
"%s:%s:%s", leaf->getPointer(), auth->
nonce, *digest);
1526 if(!stricmp(*digest, auth->
response))
1533 shell::debug(2,
"rejecting %s; error=%d", auth->
username, error);
1561 struct sockaddr_internet iface;
1565 if(contact && contact->
url) {
1567 if(param && param->
gvalue)
1586 shell::log(shell::ERR,
"cannot determine origin for registration");
1590 reguri = contact->
url;
1591 port = reguri->
port;
1592 if(!port || !port[0])
1593 port = (
char *)
"5060";
1623 port = reguri->
port;
1624 if(!port || !port[0])
1625 port = (
char *)
"5060";
1642 shell::debug(3,
"querying %s", reguri->
username);
1644 shell::debug(3,
"query rejected for %s; error=%d", reguri->
username, error);
1664 if(!interval || !contact) {
1673 assert(contact != NULL && *contact != 0);
1674 assert(interval > 0);
1686 shell::debug(2,
"rejecting %s, not in local dialing plan",
getIdent());
1694 if(!warning_registry) {
1695 warning_registry =
true;
1696 shell::log(shell::ERR,
"registry capacity reached");
1702 warning_registry =
false;
1709 expire += interval + 3;
1726 shell::log(shell::ERR,
"cannot register %s from %s",
getIdent(),
buffer);
1738 shell::log(shell::INFO,
"registering service %s:%s@%s:%s",
1781 linked_pointer<service::keynode> device =
server::list(
"devices");
1784 linked_pointer<service::keynode> node = device->getFirst();
1785 const char *id, *
value;
1788 value = node->getPointer();
1789 if(
id && value && !stricmp(
id,
"match")) {
1813 shutdown_flag =
true;
1816 while(shutdown_count < startup_count)
1821 while(startup_count < count)
1836 if(msgheader && msgheader->
hvalue)
1850 time_t current, prior = 0;
1885 if(current != prior) {
1894 shell::debug(2,
"sip: event %s(%d); cid=%d, did=%d, instance=%s",
1916 case EXOSIP_REGISTRATION_TERMINATED:
1923 case EXOSIP_REGISTRATION_REFRESHED:
1985 if(body && body->
body) {
1994 case EXOSIP_CALL_TIMEOUT:
2220 shell::log(shell::WARN,
"unknown message");
bool unauthenticated(void)
void update(Socket::address &addr, int changed)
Structure for SIP Message (REQUEST and RESPONSE).
char * subtype
Sub-Type of attachement.
Some convenience methods for manipulating SIP uri's.
voip::proxyauth_t proxy_auth
static void automatic_action(context_t ctx)
static void close(session *s)
user is successfully registred.
char network[MAX_NETWORK_SIZE]
static void getInterface(struct sockaddr *iface, const struct sockaddr *dest)
static void add_authentication(context_t ctx, const char *user, const char *secret, const char *realm, bool automatic=false)
osip_list_t contacts
Contacts headers.
static volatile char * sip_publish
static bool forward(stack::call *cr)
static void release(context_t ctx)
#define osip_proxy_authenticate_get_realm(header)
Get value of the realm parameter from a Proxy-Authenticate element.
void reregister(const char *contact, time_t interval)
static void identity(const struct sockaddr *address, char *buffer, const char *user, size_t size)
char display[MAX_DISPLAY_SIZE]
int osip_content_length_to_str(const osip_content_length_t *header, char **dest)
Get a string representation of a Content-Length element.
ACK received for 200ok to INVITE.
announce a server failure
static unsigned getRoutes(void)
registry::mapped * reginfo
static cdr * get(void)
Get a free cdr node to fill from the cdr memory pool.
static volatile char * sip_contact
static const char * getDomain(void)
announce a server failure
Pointer to a provisioned user xml subtree.
User profiles are used to map features and toll restriction level together under a common identifier...
bool expire(Socket::address &addr)
char identity[MAX_URI_SIZE]
#define SIP_NOT_ACCEPTABLE_HERE
int osip_atoi(const char *number)
void * osip_list_get(const osip_list_t *li, int pos)
Get an element from a list.
static bool make_answer_response(context_t ctx, tid_t tid, int status, msg_t *msg)
announce new NOTIFY request
char * port
Port where to send answers.
static session * create(voip::context_t context, voip::call_t cid, voip::did_t did, voip::tid_t tid)
static void update(const char *userid)
char prefix[MAX_USERID_SIZE]
#define SIP_MOVED_PERMANENTLY
struct sockaddr_storage peering
int did
unique id for SIP dialogs
static stack::subnet * getPolicy(const struct sockaddr *addr)
#define SIP_ADDRESS_INCOMPLETE
announce a global failure
#define USER_PROFILE_OUTGOING
service::keynode * routed
osip_content_length_t * content_length
Content-Length header.
osip_contact_t * contact_t
#define SIP_SERVER_TIME_OUT
static session * access(voip::call_t cid)
unsigned cid
Internal call sequence identifiers.
announce processing by a remote app
announce a 1xx for request.
Structure for holding Body.
announce a request failure
#define MSG_IS_REFER(msg)
Test if the message is a REFER REQUEST.
static int getDialog(session *session)
#define SIP_UNDECIPHERABLE
static unsigned getRange(void)
char sysident[MAX_IDENT_SIZE]
void failed(thread *thread, session *s)
enum sipwitch::cdr::@0 type
Start or end of call?
osip_from_t * from
From header.
announce new incoming request.
time_t starting
Time the call was received.
service::usernode authorized
#define MSG_IS_INFO(msg)
Test if the message is an INFO REQUEST.
static void post(cdr *cdr)
Post cdr record to callbacks through the cdr thread queue.
char * type
Type of attachement.
#define osip_message_get_expires(sip, pos, dest)
Find a Expires header.
char from[MAX_URI_SIZE+MAX_DISPLAY_SIZE]
announce a global failure
announce a 1xx for request.
static void serviceid(const char *sipuri, char *buffer, size_t size)
int osip_message_header_get_byname(const osip_message_t *sip, const char *hname, int pos, osip_header_t **dest)
Find an "unknown" header.
osip_content_type_t * content_type
Content-Type header.
char buftemp[MAX_URI_SIZE]
static UserCache * find(const char *id)
Find user record.
enum sipwitch::thread::@13 authorizing
#define osip_via_param_get_byname(header, name, dest)
Find a header parameter in a Via element.
static bool authenticate(voip::reg_t id, const char *realm)
union sipwitch::MappedRegistry::@6 source
static int deliver(message *msg)
void ring(thread *thread, session *s=NULL)
announce new incoming request.
int cid
unique id for SIP calls (but multiple dialogs!)
static void release_event(event_t ev)
Definition of the Content-Type header.
unsigned addTarget(Socket::address &via, time_t expires, const char *contact, const char *policy, struct sockaddr *peer, voip::context_t context)
#define osip_message_get_subject(sip, pos, dest)
Find a Subject header.
#define USER_PROFILE_INCOMING
#define SIP_BUSY_EVRYWHERE
const char * getIdent(void)
bool has_feature(unsigned short X) const
static const char * getScheme(void)
MappedRegistry * accepted
#define MSG_IS_REGISTER(msg)
Test if the message is a REGISTER REQUEST.
static void shutdown(void)
osip_proxy_authenticate_t * proxyauth_t
char forward[MAX_USERID_SIZE]
static void clear(session *s)
const char *volatile restricted
char * displayname
Display Name.
static keynode * getRouting(const char *id)
#define SIP_TEMPORARILY_UNAVAILABLE
Socket::address request_address
static void server_requires(voip::msg_t msg, const char *txt)
struct sockaddr_storage iface
static bool make_options_response(context_t ctx, tid_t tid, int status, msg_t *msg)
static void detach(session *s)
char requesting[MAX_URI_SIZE]
static const char * getRealm(void)
enum sipwitch::stack::session::@10 state
static void send_options_response(context_t ctx, tid_t tid, int status, msg_t msg=NULL)
announce a request failure
char * gvalue
uri parameter value
osip_uri_t * req_uri
Request-Uri (SIP request only)
char subject[MAX_URI_SIZE]
static void published(struct sockaddr_storage *peer)
void busy(thread *thread, session *s=NULL)
static const char * referLocal(MappedRegistry *rr, const char *target, char *buffer, size_t size)
int osip_list_eol(const osip_list_t *li, int pos)
Check if the end of list is detected .
void trying(thread *thread)
#define SIP_REQUEST_TIME_OUT
announce new incoming SUBSCRIBE.
#define MSG_IS_BYE(msg)
Test if the message is a BYE REQUEST.
char identbuf[MAX_USERID_SIZE+12]
struct sipwitch::MappedRegistry::@6::@8 internal
static void release(stack::subnet *access)
Definition of the From header.
#define MSG_IS_PUBLISH(msg)
Test if the message is an UPDATE REQUEST.
osip_message_t * request
request within current transaction
char dialed[MAX_IDENT_SIZE]
Destination requested on our switch.
static void registration(voip::reg_t id, modules::regmode_t mode)
static void siplog(voip::msg_t msg)
static void refer(session *session, voip::event_t sevent)
#define SIP_MOVED_TEMPORARILY
static mapped * address(const struct sockaddr *addr)
static const char * referRemote(MappedRegistry *rr, const char *target, char *buffer, size_t size)
void message_reply(thread *thread, session *s)
static void incUse(mapped *rr, stats::stat_t stat)
#define MSG_IS_MESSAGE(msg)
Test if the message is a MESSAGE REQUEST.
void send_reply(int error)
announce a server failure
char buffer[MAX_URI_SIZE]
char dialed[MAX_IDENT_SIZE]
destination_t destination
char binding[MAX_URI_SIZE]
osip_list_t www_authenticates
WWW-Authenticate headers.
static bool isExtension(const char *id)
static keynode * list(const char *p)
static void detach(mapped *m)
static void send_response_message(context_t ctx, tid_t tid, int status, msg_t msg=NULL)
static void wait(unsigned count)
#define SIP_UNSUPPORTED_URI_SCHEME
static void send_answer_response(context_t ctx, tid_t tid, int status, msg_t msg=NULL)
#define osip_message_set_expires(sip, value)
Allocate and Add a new Expires header.
static void infomsg(session *session, voip::event_t sevent)
#define SIP_PROXY_AUTHENTICATION_REQUIRED
static time_t getExpires(void)
void bye(thread *thread, session *s)
Socket::address via_address
void confirm(thread *thread, session *s)
static pattern * getRouting(unsigned trs, const char *id)
char display[MAX_DISPLAY_SIZE]
Display name of calling party.
static bool exists(const char *id)
static const char * getDigest(void)
static void getProvision(const char *id, usernode &user)
announce a new INVITE within call
Socket::address contact_address
announce that call has been cancelled
announce no answer within the timeout
char ident[MAX_IDENT_SIZE]
Ident of calling parting.
osip_list_t vias
Vias headers.
eXosip_event_type
Structure for event type description.
void answer(thread *thread, session *s)
static char * sipAddress(struct sockaddr_internet *addr, char *buf, const char *user=NULL, size_t size=MAX_URI_SIZE)
void getDevice(registry::mapped *rr)
int osip_message_set_contact(osip_message_t *sip, const char *hvalue)
Set the Contact header.
thread(voip::context_t ctx, const char *tag)
char * host
Host where to send answers.
bool refresh(Socket::address &addr, time_t expires, const char *target_contact)
#define MSG_IS_OPTIONS(msg)
Test if the message is an OPTIONS REQUEST.
char * osip_www_authenticate_get_realm(osip_www_authenticate_t *header)
Get value of the realm parameter from a Www-Authenticate element.
unsigned setTarget(Socket::address &via, time_t expires, const char *contact, const char *policy, struct sockaddr *peer, voip::context_t context)
osip_list_t proxy_authenticates
Proxy-Authenticate headers.
int status_code
Status Code (SIP answer only)
static mapped * access(const char *id)
char * body
buffer containing data
char * scheme
Uri Scheme (sip or sips)
a BYE was received for this call
Definition of the Authorization header.
announce a global failure
static unsigned short sip_port
osip_message_t * ack
ack within current transaction
static const char * eid(eXosip_event_type ev)
static void publish(const char *uri, char *buffer, const char *user, size_t size)
static const char * get(const char *id)
static void server_accepts(voip::msg_t msg)
static unsigned getPrefix(void)
static void activate(MappedRegistry *rr)
char identity[MAX_USERID_SIZE]
static void getDialing(const char *id, usernode &user)
char display[MAX_DISPLAY_SIZE]
static bool make_response_message(context_t ctx, tid_t tid, int status, msg_t *msg)
void relay(thread *thread, session *s)
const char * contact_host
Interface class for call detail records.
void addContact(const char *id)
char suffix[MAX_USERID_SIZE]
int tid
unique id for transactions (to be used for answers)
Structure for referencing url parameters.
int osip_message_get_body(const osip_message_t *sip, int pos, osip_body_t **dest)
Get one body header.
char * sip_method
METHOD (SIP request only)
int rid
unique id for registration
osip_message_t * response
last response within current transaction
eXosip_event_type_t type
type of the event
Structure for referencing SIP urls.
#define SIP_SERVICE_UNAVAILABLE
static void release(const char *hash)
#define SIP_REQUEST_TERMINATED
static void setDialog(session *session, voip::did_t did)
static int inviteRemote(stack::session *session, const char *uri, const char *digest=NULL)
char request[MAX_URI_SIZE]
static int inviteLocal(stack::session *session, registry::mapped *rr, destination_t dest)
static const char * getValue(keynode *base, const char *id)
static mapped * dialing(const char *id)
voip::proxyauth_t www_auth
static mapped * allocate(const char *id)
static void server_allows(voip::msg_t msg)
void reinvite(thread *thread, session *s)
announce a request failure
struct sockaddr_internet address
char dialing[MAX_USERID_SIZE]
User caches may be used to contact nearby users in multicast registries.
int osip_message_get_authorization(const osip_message_t *sip, int pos, osip_authorization_t **dest)
Get one Authorization header.
char uuid[48]
A unique identifier for each and every call.
static profile_t * getProfile(const char *id)
char network[MAX_NETWORK_SIZE]
static void header(msg_t msg, const char *key, const char *value)
treemap< char * > keynode
Definition of a xml node.
static bool announce(MappedRegistry *rr, const char *msgtype, const char *event, const char *expires, const char *body)
enum sipwitch::MappedRegistry::@5 type
struct sockaddr_storage peering
static event_t get_event(context_t ctx, timeout_t timeout)
char network[MAX_NETWORK_SIZE *2]
Subnet interface the caller appeared on.
static mapped * invite(const char *id, stats::stat_t stat)