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>
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
46 {
47 public:
49
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
62 static string_t saved_state(
"up"),
saved_realm(
"unknown");
63 static time_t started;
64
66 {
67 private:
68 void run(void);
69
70 public:
71 event_thread();
72
73 } _thread_;
74
76 {
77 }
78
80 {
81 enlist(&root);
83 }
84
86 {
88 delist(&root);
89 }
90
92 {
94
95 private_locking.acquire();
96 if(freelist) {
97 node = freelist;
98 freelist = (
dispatch *)node->getNext();
99 }
100 else
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;
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
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
182 shell::log(
DEBUG3,
"connecting client events for %ld", (
long)client);
183
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
195 ::send(client, (const char *)&evt, sizeof(evt), 0);
196
198 }
199
200 shell::log(
DEBUG1,
"stopping event dispatcher");
201 }
202
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
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 {
271 }
272
274 {
281
282 }
283
285 {
287
292 }
293
295 {
297
302 }
303
305 {
307
308 private_locking.acquire();
310 private_locking.release();
314 }
315
317 {
318 events evt;
319
320 private_locking.acquire();
321 saved_state = str;
322 private_locking.release();
324 String::set(evt.msg.server.state, sizeof(evt.msg.server.state), str);
326 }
327
329 {
334 }
335
337 {
339
343 }
344
346 {
348
352 }
353
355 {
357
361 }
362
364 {
366
370
373 if(addr) {
374 string_t
uri = str(
"sip:") + (
const char *)addr;
377 }
378 }
379
381 {
383
385 string_t
uri = str(
"sip:") + addr;
388 }
389
391 {
393
394 if(shutdown_flag || ipc_socket == INVALID_SOCKET)
395 return;
396
397 shutdown_flag = true;
400
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
413 //ipc_socket = INVALID_SOCKET;
414 }
415
416 } // end namespace
static void activate(MappedRegistry *user)
Send event for first instance of user registration.
Some convenience methods for manipulating SIP uri's.
static void failure(const char *reason)
Send error to user.
static volatile char * sip_publish
struct sipwitch::events::@1::@3 user
Event message and supporting methods for plugins.
Representation of a mapped active user record.
time_t starting
Time the call was received.
static void publish(const char *address)
Update publish address...
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.
static void terminate(const char *reason)
Notify server termination.
static void notice(const char *reason)
Send notice to user.
static string_t saved_realm("unknown")
Stream events to local clients.
static void reload(void)
Refresh clients with any config events...
static bool start(void)
Start server event system by binding event session listener.
static void send(events *message)
type_t type
Type of event message.
static void warning(const char *reason)
Send warning to user.
char dialed[MAX_IDENT_SIZE]
Destination requested on our switch.
static string_t getContact(void)
char display[MAX_DISPLAY_SIZE]
Display name of calling party.
Service configuration and component callbacks.
char ident[MAX_IDENT_SIZE]
Ident of calling parting.
struct sipwitch::events::@1::@2 call
static void release(MappedRegistry *user)
Send event for last instance of user expired or de-registering.
static void add(socket_t so)
Manage control interface.
static void sync(unsigned period=0l)
Test connection and housekeeping notification.
Interface class for call detail records.
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.
static const char * env(const char *id)
Return the value of a server environment variable.
static void stop(events *message)
static void connect(cdr *rec)
Send call connection to clients from cdr start record.
char network[MAX_NETWORK_SIZE *2]
Subnet interface the caller appeared on.