SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
events.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 <sipwitch-config.h>
18 #include <ucommon/ucommon.h>
19 #include <ucommon/export.h>
20 #include <sipwitch/events.h>
21 #include <sipwitch/control.h>
22 #include <sipwitch/mapped.h>
23 #include <sipwitch/service.h>
24 
25 #if !defined(_MSWINDOWS_)
26 #include <sys/un.h>
27 #endif
28 
29 #ifndef _MSWINDOWS_
30 #include <pwd.h>
31 #include <fcntl.h>
32 #endif
33 
34 namespace sipwitch {
35 
36 static mutex_t private_locking;
37 static bool shutdown_flag = false;
38 #ifdef _MSWINDOWS_
39 static struct sockaddr_in ipc_addr;
40 #else
41 static struct sockaddr_un ipc_addr;
42 #endif
43 static socket_t ipc_socket = INVALID_SOCKET;
44 
45 class __LOCAL dispatch : public LinkedObject
46 {
47 public:
48  socket_t session;
49 
50  dispatch();
51 
52  void assign(socket_t so);
53  void release(void);
54 
55  static void add(socket_t so);
56  static void stop(events *message);
57  static void send(events *message);
58 };
59 
60 static LinkedObject *root = NULL;
61 static dispatch *freelist = NULL;
62 static string_t saved_state("up"), saved_realm("unknown");
63 static time_t started;
64 
65 static class __LOCAL event_thread : public JoinableThread
66 {
67 private:
68  void run(void);
69 
70 public:
71  event_thread();
72 
73 } _thread_;
74 
76 {
77 }
78 
79 void dispatch::assign(socket_t so)
80 {
81  enlist(&root);
82  session = so;
83 }
84 
86 {
87  ::close(session);
88  delist(&root);
89 }
90 
91 void dispatch::add(socket_t so)
92 {
93  dispatch *node;
94 
95  private_locking.acquire();
96  if(freelist) {
97  node = freelist;
98  freelist = (dispatch *)node->getNext();
99  }
100  else
101  node = new dispatch;
102  node->assign(so);
103  private_locking.release();
104 }
105 
107 {
108  private_locking.acquire();
109  linked_pointer<dispatch> dp = root;
110 
111  while(is(dp)) {
112  if(msg)
113  ::send(dp->session, (const char *)msg, sizeof(events), 0);
114  ::close(dp->session);
115  dp.next();
116  }
117  freelist = NULL;
118  root = NULL;
119  private_locking.release();
120 }
121 
123 {
124  fd_set detect;
125  struct timeval timeout;
126  if(ipc_socket == INVALID_SOCKET)
127  return;
128 
129  private_locking.acquire();
130  linked_pointer<dispatch> dp = root;
131  LinkedObject *next;
132  while(is(dp)) {
133  next = dp->Next;
134  if(::send(dp->session, (const char *)msg, sizeof(events), 0) < (ssize_t)sizeof(events)) {
135 disconnect:
136  shell::log(DEBUG3, "releasing client events for %ld", (long)dp->session);
137  dp->release();
138  dp->Next = freelist;
139  freelist = *dp;
140  }
141  // disconnect detection...
142  memset(&timeout, 0, sizeof(timeout));
143  memset(&detect, 0, sizeof(detect));
144  FD_SET(dp->session, &detect);
145  if(select(dp->session + 1, &detect, NULL, &detect, &timeout) > 0)
146  goto disconnect;
147  dp = next;
148  }
149  private_locking.release();
150 }
151 
152 event_thread::event_thread() : JoinableThread()
153 {
154 }
155 
156 void event_thread::run(void)
157 {
158  socket_t client;
159  events evt;
160 
161  time(&started);
162 
163  shell::log(DEBUG1, "starting event dispatcher");
164  shutdown_flag = false;
165 
166  for(;;) {
167  // when shutdown closes ipc, we exit the thread...
168  client = ::accept(ipc_socket, NULL, NULL);
169  if(shutdown_flag) {
170  if(ipc_socket != INVALID_SOCKET) {
171  Socket::release(ipc_socket);
172  ipc_socket = INVALID_SOCKET;
173  }
174  break;
175  }
176  if(client < 0) {
177  shell::log(shell::ERR, "event accept failed; error=%ld", (long)client);
178  continue;
179  }
180 
181  events::sync();
182  shell::log(DEBUG3, "connecting client events for %ld", (long)client);
183 
184  evt.type = events::WELCOME;
185  evt.msg.server.started = started;
186  String::set(evt.msg.server.version, sizeof(evt.msg.server.version), VERSION);
187  private_locking.acquire();
188  String::set(evt.msg.server.state, sizeof(evt.msg.server.state), *saved_state);
189  String::set(evt.msg.server.realm, sizeof(evt.msg.server.realm), *saved_realm);
190  private_locking.release();
191  ::send(client, (const char *)&evt, sizeof(evt), 0);
192 
193  String::set(evt.msg.contact, sizeof(evt.msg.contact), *service::getContact());
194  evt.type = events::CONTACT;
195  ::send(client, (const char *)&evt, sizeof(evt), 0);
196 
197  dispatch::add(client);
198  }
199 
200  shell::log(DEBUG1, "stopping event dispatcher");
201 }
202 
203 bool events::start(void)
204 {
205  if(ipc_socket != INVALID_SOCKET)
206  return false;
207 
208 #ifdef _MSWINDOWS_
209  ipc_socket = ::socket(AF_INET, SOCK_STREAM, 0);
210 #else
211  ipc_socket = ::socket(AF_UNIX, SOCK_STREAM, 0);
212 #endif
213 
214  if(ipc_socket == INVALID_SOCKET)
215  return false;
216 
217  memset(&ipc_addr, 0, sizeof(ipc_addr));
218 #ifdef _MSWINDOWS_
219  DWORD port;
220  HKEY keys, subkey;
221  socklen_t alen;
222 
223  ipc_addr.sin_family = AF_INET;
224  ipc_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
225  ipc_addr.sin_port = 0;
226  if(::bind(ipc_socket, (struct sockaddr *)&ipc_addr, sizeof(ipc_addr)) < 0)
227  goto failed;
228 
229  alen = sizeof(ipc_addr);
230  ::getsockname(ipc_socket, (struct sockaddr *)&ipc_addr, &alen);
231  port = ntohs(ipc_addr.sin_port);
232  keys = HKEY_LOCAL_MACHINE;
233  if(RegCreateKeyEx(keys, "SOFTWARE\\sipwitch", 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &subkey, NULL) == ERROR_SUCCESS) {
234  RegSetValueEx(subkey, "port", 0L, REG_DWORD, (const BYTE *)&port, sizeof(port));
235  port = GetCurrentProcessId();
236  RegSetValueEx(subkey, "pid", 0L, REG_DWORD, (const BYTE *)&port, sizeof(port));
237  RegCloseKey(subkey);
238  }
239 #else
240  ipc_addr.sun_family = AF_UNIX;
241  String::set(ipc_addr.sun_path, sizeof(ipc_addr.sun_path), control::env("events"));
242 
243  ::remove(control::env("events"));
244  if(::bind(ipc_socket, (struct sockaddr *)&ipc_addr, SUN_LEN(&ipc_addr)) < 0)
245  goto failed;
246 #endif
247 
248  if(::listen(ipc_socket, 10) < 0)
249  goto failed;
250 
251  _thread_.start();
252  return true;
253 
254 failed:
255  Socket::release(ipc_socket);
256  ipc_socket = INVALID_SOCKET;
257  return false;
258 }
259 
261 {
262  events evt;
263  evt.type = CALL;
264  evt.msg.call.started = rec->starting;
265  String::set(evt.msg.call.reason, sizeof(evt.msg.call.reason), rec->reason);
266  String::set(evt.msg.call.network, sizeof(evt.msg.call.network), rec->network);
267  String::set(evt.msg.call.caller, sizeof(evt.msg.call.caller), rec->ident);
268  String::set(evt.msg.call.dialed, sizeof(evt.msg.call.dialed), rec->dialed);
269  String::set(evt.msg.call.display, sizeof(evt.msg.call.display), rec->display);
270  dispatch::send(&evt);
271 }
272 
273 void events::drop(cdr *rec)
274 {
275  events evt;
276  evt.type = DROP;
277  String::set(evt.msg.call.caller, sizeof(evt.msg.call.caller), rec->ident);
278  String::set(evt.msg.call.dialed, sizeof(evt.msg.call.dialed), rec->dialed);
279  String::set(evt.msg.call.display, sizeof(evt.msg.call.display), rec->display);
280  dispatch::send(&evt);
281 
282 }
283 
285 {
286  events evt;
287 
288  evt.type = ACTIVATE;
289  String::set(evt.msg.user.id, sizeof(evt.msg.user.id), rr->userid);
290  evt.msg.user.extension = rr->ext;
291  dispatch::send(&evt);
292 }
293 
295 {
296  events evt;
297 
298  evt.type = RELEASE;
299  String::set(evt.msg.user.id, sizeof(evt.msg.user.id), rr->userid);
300  evt.msg.user.extension = rr->ext;
301  dispatch::send(&evt);
302 }
303 
304 void events::realm(const char *str)
305 {
306  events evt;
307 
308  private_locking.acquire();
309  saved_realm = str;
310  private_locking.release();
311  evt.type = REALM;
312  String::set(evt.msg.server.realm, sizeof(evt.msg.server.realm), str);
313  dispatch::send(&evt);
314 }
315 
316 void events::state(const char *str)
317 {
318  events evt;
319 
320  private_locking.acquire();
321  saved_state = str;
322  private_locking.release();
323  evt.type = STATE;
324  String::set(evt.msg.server.state, sizeof(evt.msg.server.state), str);
325  dispatch::send(&evt);
326 }
327 
328 void events::sync(unsigned sync_period)
329 {
330  events evt;
331  evt.type = SYNC;
332  evt.msg.period = sync_period;
333  dispatch::send(&evt);
334 }
335 
336 void events::notice(const char *reason)
337 {
338  events evt;
339 
340  evt.type = NOTICE;
341  String::set(evt.msg.reason, sizeof(evt.msg.reason), reason);
342  dispatch::send(&evt);
343 }
344 
345 void events::warning(const char *reason)
346 {
347  events evt;
348 
349  evt.type = WARNING;
350  String::set(evt.msg.reason, sizeof(evt.msg.reason), reason);
351  dispatch::send(&evt);
352 }
353 
354 void events::failure(const char *reason)
355 {
356  events evt;
357 
358  evt.type = FAILURE;
359  String::set(evt.msg.reason, sizeof(evt.msg.reason), reason);
360  dispatch::send(&evt);
361 }
362 
363 void events::reload(void)
364 {
365  events evt;
366 
367  evt.type = CONTACT;
368  String::set(evt.msg.contact, sizeof(evt.msg.contact), *service::getContact());
369  dispatch::send(&evt);
370 
371  evt.type = PUBLISH;
372  volatile char *addr = service::callback::sip_publish;
373  if(addr) {
374  string_t uri = str("sip:") + (const char *)addr;
375  String::set(evt.msg.contact, sizeof(evt.msg.contact), *uri);
376  dispatch::send(&evt);
377  }
378 }
379 
380 void events::publish(const char *addr)
381 {
382  events evt;
383 
384  evt.type = PUBLISH;
385  string_t uri = str("sip:") + addr;
386  String::set(evt.msg.contact, sizeof(evt.msg.contact), *uri);
387  dispatch::send(&evt);
388 }
389 
390 void events::terminate(const char *reason)
391 {
392  events evt;
393 
394  if(shutdown_flag || ipc_socket == INVALID_SOCKET)
395  return;
396 
397  shutdown_flag = true;
398  evt.type = TERMINATE;
399  String::set(evt.msg.reason, sizeof(evt.msg.reason), reason);
400 
401  dispatch::stop(&evt);
402  socket_t tmp;
403 #ifdef _MSWINDOWS_
404  tmp = ::socket(AF_INET, SOCK_STREAM, 0);
405  ::connect(tmp, (struct sockaddr *)&ipc_addr, sizeof(ipc_addr));
406 #else
407  tmp = ::socket(AF_UNIX, SOCK_STREAM, 0);
408  ::connect(tmp, (struct sockaddr *)&ipc_addr, SUN_LEN(&ipc_addr));
409 #endif
410  Socket::release(tmp);
411 
412  ::remove(control::env("events"));
413  //ipc_socket = INVALID_SOCKET;
414 }
415 
416 } // end namespace
static void activate(MappedRegistry *user)
Send event for first instance of user registration.
Definition: events.cpp:284
Some convenience methods for manipulating SIP uri's.
Definition: uri.h:55
static void failure(const char *reason)
Send error to user.
Definition: events.cpp:354
static volatile char * sip_publish
Definition: service.h:191
unsigned period
Definition: events.h:108
struct sipwitch::events::@1::@3 user
Event message and supporting methods for plugins.
Definition: events.h:66
char reason[16]
Definition: events.h:90
Representation of a mapped active user record.
Definition: mapped.h:95
#define DEBUG3
Definition: control.h:51
time_t starting
Time the call was received.
Definition: cdr.h:107
void release(void)
Definition: events.cpp:85
static void publish(const char *address)
Update publish address...
Definition: events.cpp:380
struct sipwitch::events::@1::@4 server
Definitions for memory mapped objects that may be shared between processes.
char reason[16]
Reason the call was terminated.
Definition: cdr.h:97
socket_t session
Definition: events.cpp:48
static void terminate(const char *reason)
Notify server termination.
Definition: events.cpp:390
char contact[160]
Definition: events.h:106
static void notice(const char *reason)
Send notice to user.
Definition: events.cpp:336
char state[32]
Definition: events.h:103
char realm[64]
Definition: events.h:104
static string_t saved_realm("unknown")
Stream events to local clients.
static void reload(void)
Refresh clients with any config events...
Definition: events.cpp:363
static bool start(void)
Start server event system by binding event session listener.
Definition: events.cpp:203
static void send(events *message)
Definition: events.cpp:122
type_t type
Type of event message.
Definition: events.h:82
static void warning(const char *reason)
Send warning to user.
Definition: events.cpp:345
char dialed[MAX_IDENT_SIZE]
Destination requested on our switch.
Definition: cdr.h:77
static string_t getContact(void)
Definition: service.cpp:792
void assign(socket_t so)
Definition: events.cpp:79
char display[MAX_DISPLAY_SIZE]
Display name of calling party.
Definition: cdr.h:87
Service configuration and component callbacks.
char ident[MAX_IDENT_SIZE]
Ident of calling parting.
Definition: cdr.h:72
struct sipwitch::events::@1::@2 call
static void release(MappedRegistry *user)
Send event for last instance of user expired or de-registering.
Definition: events.cpp:294
static void add(socket_t so)
Definition: events.cpp:91
Manage control interface.
static void sync(unsigned period=0l)
Test connection and housekeeping notification.
Definition: events.cpp:328
Interface class for call detail records.
Definition: cdr.h:56
union sipwitch::events::@1 msg
Content of message, based on type.
static void drop(cdr *rec)
Send call disconnected event to clients from cdr stop record.
Definition: events.cpp:273
static const char * env(const char *id)
Return the value of a server environment variable.
Definition: control.h:131
static void stop(events *message)
Definition: events.cpp:106
#define DEBUG1
Definition: control.h:49
static void connect(cdr *rec)
Send call connection to clients from cdr start record.
Definition: events.cpp:260
char network[MAX_NETWORK_SIZE *2]
Subnet interface the caller appeared on.
Definition: cdr.h:92