SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
messages.cpp
Go to the documentation of this file.
1 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #include "server.h"
18 
19 namespace sipwitch {
20 
21 static mutex_t msglock;
22 static unsigned keysize = 177;
23 static unsigned pending = 0;
24 static LinkedObject **msgs = NULL;
25 static LinkedObject *sending = NULL;
26 static LinkedObject *freelist = NULL;
27 static unsigned volatile allocated = 0;
28 static time_t volatile duration = 900;
29 
31 {
32  time(&expires);
33  expires += duration;
34 
35  from[0] = 0;
36  type[0] = 0;
37  body[0] = 0;
38  user[0] = 0;
39  msglen = 0;
40 }
41 
43 service::callback(2)
44 {
45 }
46 
47 bool messages::check(void)
48 {
49  shell::log(shell::INFO, "checking messages...");
50  msglock.lock();
51  msglock.release();
52  return true;
53 }
54 
56 {
57  linked_pointer<message> mp;
58  LinkedObject *msgnext;
59  unsigned msgcount = 0;
60  time_t now;
61 
62  if(!pending)
63  return;
64 
65  while(msgcount < keysize) {
66  msglock.lock();
67  time(&now);
68  mp = msgs[msgcount];
69  while(mp) {
70  msgnext = mp->getNext();
71  if(mp->expires < now) {
72  mp->delist(&msgs[msgcount]);
73  mp->enlist(&freelist);
74  }
75  mp = msgnext;
76  }
77  msglock.unlock();
78  ++msgcount;
79  }
80 }
81 
83 {
84  assert(cfg != NULL);
85 
86  const char *key = NULL, *value;
87  linked_pointer<service::keynode> sp = cfg->getList("messages");
88 
89  while(sp) {
90  key = sp->getId();
91  value = sp->getPointer();
92  if(key && value) {
93  if(!stricmp(key, "keysize") && !is_configured())
94  keysize = atoi(value);
95  else if(!stricmp(key, "expires"))
96  duration = atoi(value) * 60;
97  }
98  sp.next();
99  }
100 
101  if(is_configured())
102  return;
103 
104  msgs = new LinkedObject*[keysize];
105  memset(msgs, 0, sizeof(LinkedObject *) * keysize);
106 }
107 
108 void messages::snapshot(FILE *fp)
109 {
110  assert(fp != NULL);
111  fprintf(fp, "Messaging:\n");
112  fprintf(fp, " allocated messages: %d\n", allocated);
113  fprintf(fp, " pending messages: %d\n", pending);
114 }
115 
116 void messages::update(const char *uid)
117 {
118  assert(uid == NULL || *uid != 0);
119 
120  linked_pointer<message> mp;
121  LinkedObject *next;
122  unsigned path;
123  time_t now;
124  if(!uid || !pending)
125  return;
126 
127  path = NamedObject::keyindex(uid, keysize);
128  msglock.lock();
129  time(&now);
130  mp = msgs[path];
131  while(mp) {
132  next = mp->getNext();
133  if(!stricmp(mp->user, uid)) {
134  --pending;
135  mp->delist(&msgs[path]);
136  if(mp->expires < now)
137  mp->enlist(&freelist);
138  else
139  mp->enlist(&sending);
140  }
141  mp = next;
142  }
143  msglock.unlock();
144 }
145 
146 int messages::deliver(const char *to, const char *reply, const char *from, caddr_t text, size_t len, const char *msgtype, const char *digest)
147 {
148  message *msg;
149 
150  if(!msgtype)
151  msgtype = "text/plain";
152 
153  if(len > sizeof(msg->body))
154  return SIP_MESSAGE_TOO_LARGE;
155 
156  msglock.lock();
157  msg = static_cast<message *>(freelist);
158  if(msg)
159  freelist = msg->getNext();
160  msglock.unlock();
161  if(!msg) {
162  ++allocated;
163  msg = new message();
164  }
165  msg->create();
166  String::set(msg->reply, sizeof(msg->reply), reply);
167  String::set(msg->from, sizeof(msg->from), from);
168  String::set(msg->type, sizeof(msg->type), msgtype);
169  memset(msg->body, 0, sizeof(msg->body));
170  if(len)
171  memcpy(msg->body, text, len);
172  msg->msglen = len;
173 
174  if(!strchr(to, '@')) {
175  String::set(msg->user, sizeof(msg->user), to);
176  return deliver(msg);
177  }
178  return remote(to, msg, digest);
179 }
180 
181 int messages::system(const char *to, const char *text)
182 {
183  char from[MAX_URI_SIZE];
184  const char *scheme;
185  const char *sysid = stack::sip.system;
186  const char *host = stack::sip.published;
187  unsigned short port = sip_port;
188 
190  scheme = "sips";
191  else
192  scheme = "sip";
193 
194  if(!host) {
195  host = "127.0.0.1";
196 #ifdef AF_INET6
197  if(!host && stack::sip_family == AF_INET6)
198  host = "::1";
199 #endif
200  }
201 
202  if(strchr(host, ':'))
203  snprintf(from, sizeof(from), "<%s:%s@[%s]:%u>",
204  scheme, sysid, host, port);
205  else
206  snprintf(from, sizeof(from), "<%s:%s@%s:%u>",
207  scheme, sysid, host, port);
208 
209  return deliver(to, sysid, from, (caddr_t)text, strlen(text), "text/plain");
210 }
211 
212 int messages::remote(const char *to, message *msg, const char *digest)
213 {
214  shell::debug(3, "instant message delivered to %s from %s", to, msg->reply);
215 
216  voip::msg_t im = NULL;
217  int error = SIP_BAD_REQUEST;
218  char route[MAX_URI_SIZE];
219  srv resolv;
220  voip::context_t ctx = resolv.route(to, route, sizeof(route));
221  char rewrite[MAX_URI_SIZE];
222  const char *schema = NULL;
223 
224  if(!ctx)
225  return error;
226 
227  if(eq(to, "tcp:", 4)) {
228  schema = "sip";
229  to += 4;
230  }
231  else if(eq(to, "udp:", 4)) {
232  schema = "sip";
233  to += 4;
234  }
235 
236  if(schema) {
237  snprintf(rewrite, sizeof(rewrite), "%s:%s", schema, to);
238  to = rewrite;
239  }
240 
241  if(voip::make_request_message(ctx, "MESSAGE", to, msg->from, &im, route)) {
242  char *authbuf = new char[1024];
243  stringbuf<64> response;
244  stringbuf<64> once;
245  char nounce[64];
246  char *req = NULL;
247  osip_uri_to_str(im->req_uri, &req);
248  snprintf(authbuf, 1024, "%s:%s", im->sip_method, req);
249  Random::uuid(nounce);
250 
251  digest_t auth("md5");
252  auth.puts(nounce);
253  once = *auth;
254  auth = registry::getDigest();
255  auth.puts(authbuf);
256  response = *auth;
257  snprintf(authbuf, 1024, "%s:%s:%s", digest, *once, *response);
258  auth.reset();
259  auth.puts(authbuf);
260  response = *auth;
261  snprintf(authbuf, 1024,
262  "Digest username=\"%s\""
263  ",realm=\"%s\""
264  ",uri=\"%s\""
265  ",response=\"%s\""
266  ",nonce=\"%s\""
267  ",algorithm=%s"
268  ,msg->reply, registry::getRealm(), req, *response, *once, registry::getDigest());
269  voip::header(im, AUTHORIZATION, authbuf);
270  delete[] authbuf;
271  osip_free(req);
272  }
273  if(im) {
274  voip::attach(im, msg->type, msg->body, msg->msglen);
275  stack::siplog(im);
277  error = SIP_OK;
278  }
279  return error;
280 }
281 
283 {
284  assert(msg != NULL);
285 
286  linked_pointer<registry::target> tp;
288  voip::msg_t im;
289  time_t now;
290  unsigned msgcount = 0;
291  char to[MAX_URI_SIZE];
292  int error = SIP_GONE;
293 
294  time(&now);
295  if(!rr)
296  error = SIP_NOT_FOUND;
297 
298  if(!rr || (rr->expires && rr->expires < now)) {
299  shell::debug(3, "instant message failed for %s from %s; error=%d", msg->user, msg->reply, error);
300  goto final;
301  }
302 
303  shell::debug(3, "instant message delivered to %s from %s", msg->user, msg->reply);
304  tp = rr->source.internal.targets;
305  while(tp) {
306  if(!rr->expires || tp->expires > now) {
307  stack::sipAddress(&tp->address, to + 1, msg->user, sizeof(to) - 6);
308  to[0] = '<';
309  String::add(to, sizeof(to), ";lr>");
310  im = NULL;
311 
312  if(voip::make_request_message(tp->context, "MESSAGE", tp->contact, msg->from, &im, to)) {
313  stack::sipAddress(&tp->address, to + 1, msg->user, sizeof(to) - 2);
314  to[0] = '<';
315  String::add(to, sizeof(to), ">");
316  if(im->to) {
317  osip_to_free(im->to);
318  im->to = NULL;
319  }
320  osip_message_set_to(im, to);
321  voip::attach(im, msg->type, msg->body, msg->msglen);
322  voip::send_request_message(tp->context, im);
323  ++msgcount;
324  }
325  }
326  tp.next();
327  }
328 
329  // as long as we sent to one extension, we are ok...
330  if(msgcount)
331  error = SIP_OK;
332 
333 final:
334  registry::detach(rr);
335  msglock.lock();
336  msg->enlist(&freelist);
337  msglock.release();
338  return error;
339 }
340 
342 {
343  message *msg = NULL;
344  time_t now;
345 
346  for(;;) {
347  msglock.lock();
348  if(sending)
349  time(&now);
350  while(sending) {
351  msg = (message *)sending;
352  sending = msg->getNext();
353  if(msg->expires > now)
354  break;
355  msg->enlist(&freelist);
356  msg = NULL;
357  }
358  msglock.release();
359  if(!msg || deliver(msg))
360  return;
361  }
362 }
363 
364 } // end namespace
Structure for SIP Message (REQUEST and RESPONSE).
Definition: osip_message.h:55
int osip_uri_to_str(const osip_uri_t *url, char **dest)
Get a string representation of a url element.
void reload(service *cfg)
Definition: messages.cpp:82
static void automatic(void)
Definition: messages.cpp:341
static void update(const char *userid)
Definition: messages.cpp:116
const char *volatile published
Definition: server.h:384
void osip_to_free(osip_to_t *header)
Free a To element.
char reply[MAX_USERID_SIZE]
Definition: server.h:546
keynode * getList(const char *path)
Definition: service.cpp:376
void cleanup(void)
Definition: messages.cpp:55
volatile time_t expires
Definition: mapped.h:113
static bool make_request_message(context_t ctx, const char *method, const char *to, const char *from, msg_t *msg, const char *route=NULL)
Definition: voip.cpp:504
union sipwitch::MappedRegistry::@6 source
static int deliver(message *msg)
Definition: messages.cpp:282
int osip_message_set_to(osip_message_t *sip, const char *hvalue)
Set the To header.
#define SIP_OK
Definition: osip_const.h:97
#define SIP_MESSAGE_TOO_LARGE
Definition: osip_const.h:139
static const char * getRealm(void)
Definition: server.h:178
String system
Definition: server.h:388
char from[MAX_URI_SIZE]
Definition: server.h:544
osip_uri_t * req_uri
Request-Uri (SIP request only)
Definition: osip_message.h:57
static stack sip
Definition: server.h:398
#define osip_free(P)
Definition: osip_port.h:105
#define SIP_GONE
Definition: osip_const.h:113
struct sipwitch::MappedRegistry::@6::@8 internal
#define SIP_NOT_FOUND
Definition: osip_const.h:108
static bool is_configured(void)
Definition: service.h:217
static void siplog(voip::msg_t msg)
Definition: stack.cpp:331
static void attach(msg_t msg, const char *type, const char *body)
Definition: voip.cpp:941
static void detach(mapped *m)
Definition: registry.cpp:1100
char user[MAX_USERID_SIZE]
Definition: server.h:542
char * value[96]
Definition: cgiserver.cpp:90
static const char * getDigest(void)
Definition: server.h:181
static int system(const char *to, const char *message)
Definition: messages.cpp:181
voip::context_t route(const char *uri, char *buf, size_t size)
Definition: srv.cpp:375
void * context_t
Definition: voip.h:53
#define AUTHORIZATION
Definition: osip_const.h:40
static char * sipAddress(struct sockaddr_internet *addr, char *buf, const char *user=NULL, size_t size=MAX_URI_SIZE)
Definition: stack.cpp:1079
static void send_request_message(context_t ctx, msg_t msg)
Definition: voip.cpp:609
bool check(void)
Definition: messages.cpp:47
static mapped * access(const char *id)
Definition: registry.cpp:1081
static int remote(const char *to, message *msg, const char *digest=NULL)
Definition: messages.cpp:212
System configuration instance and service functions.
Definition: service.h:78
static unsigned short sip_port
Definition: service.h:188
char * sip_method
METHOD (SIP request only)
Definition: osip_message.h:58
osip_to_t * to
To header.
Definition: osip_message.h:93
static void header(msg_t msg, const char *key, const char *value)
Definition: voip.cpp:928
#define SIP_BAD_REQUEST
Definition: osip_const.h:104
void snapshot(FILE *fp)
Definition: messages.cpp:108
#define MAX_URI_SIZE
Definition: mapped.h:71