SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sipcontrol.cpp
Go to the documentation of this file.
1 // Copyright (C) 2008-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 <sipwitch/sipwitch.h>
19 #include <ucommon/secure.h>
20 #ifdef _MSWINDOWS_
21 #include <windows.h>
22 #include <io.h>
23 #else
24 #include <signal.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <fcntl.h>
28 #endif
29 
30 #if !defined(_MSWINDOWS_)
31 #include <sys/un.h>
32 #endif
33 
34 using namespace sipwitch;
35 
36 static string_t statmap = STAT_MAP;
37 static string_t callmap = CALL_MAP;
38 static string_t regmap = REGISTRY_MAP;
39 
40 #ifdef _MSWINDOWS_
41 static char *getpass(const char *prompt)
42 {
43  static char buf[128];
44  size_t i;
45 
46  fputs(prompt, stderr);
47  fflush(stderr);
48  for (i = 0; i < sizeof(buf) - 1; i++) {
49  buf[i] = fgetc(stdin);
50  if (buf[i] == '\r' || buf[i] == '\n')
51  break;
52  fputs("*", stderr);
53  fflush(stderr);
54  }
55  buf[i] = 0;
56  fputs("\n", stderr);
57  fflush(stderr);
58  return buf;
59 }
60 #endif
61 
62 #ifndef _MSWINDOWS_
63 static void capture(void)
64 {
65  char buffer[512];
66  FILE *fp;
67 
68  snprintf(buffer, sizeof(buffer), "/tmp/.sipwitch.%ld", (long)getpid());
69  fp = fopen(buffer, "r");
70  fsys::erase(buffer);
71  while(fp && fgets(buffer, sizeof(buffer), fp) != NULL)
72  fputs(buffer, stdout);
73  if(fp)
74  fclose(fp);
75 }
76 #endif
77 
78 static void paddress(struct sockaddr_internet *a1, struct sockaddr_internet *a2)
79 {
80  assert(a1 != NULL);
81 
82  char sep = '\n';
83  char buf[64];
84  unsigned p1 = 0, p2 = 0;
85 
86  if(!a1)
87  return;
88 
89  Socket::query((struct sockaddr *)a1, buf, sizeof(buf));
90  switch(a1->address.sa_family) {
91  case AF_INET:
92  p1 = (unsigned)ntohs(a1->ipv4.sin_port);
93  break;
94 #ifdef AF_INET6
95  case AF_INET6:
96  p1 = (unsigned)ntohs(a1->ipv6.sin6_port);
97  break;
98 #endif
99  }
100 
101  if(a2) {
102  switch(a2->address.sa_family) {
103  case AF_INET:
104  p2 = (unsigned)ntohs(a2->ipv4.sin_port);
105  break;
106 #ifdef AF_INET6
107  case AF_INET6:
108  p2 = (unsigned)ntohs(a2->ipv6.sin6_port);
109  break;
110 #endif
111  }
112  }
113 
114  if(a2 && p2)
115  sep = ',';
116 
117  if(p1)
118  printf("%s:%u%c", buf, p1, sep);
119  else
120  printf("none%c", sep);
121 
122  if(!a2 || !p2)
123  return;
124 
125  Socket::query((struct sockaddr *)a2, buf, sizeof(buf));
126  printf("%s:%u\n", buf, p2);
127 }
128 
129 static void mapinit(void)
130 {
131 #ifndef _MSWINDOWS_
132  struct passwd *pwd = getpwuid(getuid());
133  const char *userid = NULL;
134 
135  fd_t fd = ::open(DEFAULT_VARPATH "/run/sipwitch/control", O_WRONLY | O_NONBLOCK);
136  if(fd < 0) {
137  if(pwd)
138  userid = pwd->pw_name;
139  if(!pwd || !userid)
140  shell::errexit(4, "*** sipcontrol: maps: invalid login\n");
141 
142  statmap = str(STAT_MAP "-") + str(userid);
143  callmap = str(CALL_MAP "-") + str(userid);
144  regmap = str(REGISTRY_MAP "-") + str(userid);
145  }
146  else
147  ::close(fd);
148 #endif
149 }
150 
151 static void showrealm(void)
152 {
153  fsys_t fs;
154  char buffer[256];
155 
156  fs.open(DEFAULT_CFGPATH "/siprealm", fsys::RDONLY);
157  if(!is(fs))
158  fs.open(DEFAULT_VARPATH "/lib/sipwitch/uuid", fsys::RDONLY);
159 
160  if(!is(fs))
161 error:
162  shell::errexit(1, "*** sipcontrol: realm: no public realm known\n");
163 
164  memset(buffer, 0, sizeof(buffer));
165  fs.read(buffer, sizeof(buffer) - 1);
166  fs.close();
167 
168  char *cp = strchr(buffer, '\n');
169  if(cp)
170  *cp = 0;
171 
172  cp = strchr(buffer, ':');
173  if(cp)
174  *cp = 0;
175 
176  if(!buffer[0])
177  goto error;
178 
179  printf("%s\n", buffer);
180  exit(0);
181 }
182 
183 static void compute(char **argv)
184 {
185  char *realm = NULL;
186  const char *user, *secret;
187  const char *mode = "md5";
188  char buffer[128];
189  string_t digestbuf;
190 
191  user = argv[1];
192  if(!user)
193  shell::errexit(3, "*** sipcontrol: digest: userid missing\n");
194 
195  secret = getpass("Enter new SIP secret: ");
196  if(!secret || !*secret) {
197  printf("no password supplied\n");
198  exit(0);
199  }
200 
201  realm = argv[2];
202  if(realm) {
203  if(argv[3])
204  mode = argv[3];
205  }
206  else {
207  fsys_t fs;
208  fs.open(DEFAULT_CFGPATH "/siprealm", fsys::RDONLY);
209  if(!is(fs))
210  fs.open(DEFAULT_VARPATH "/lib/sipwitch/uuid", fsys::RDONLY);
211 
212  if(!is(fs))
213  shell::errexit(4, "*** sipcontrol: digest: no public realm known\n");
214 
215  memset(buffer, 0, sizeof(buffer));
216  fs.read(buffer, sizeof(buffer) - 1);
217  fs.close();
218 
219  char *cp = strchr(buffer, '\n');
220  if(cp)
221  *cp = 0;
222 
223  cp = strchr(buffer, ':');
224  if(cp)
225  *(cp++) = 0;
226 
227  if(cp && *cp)
228  mode = cp;
229  realm = strdup(buffer);
230  }
231 
232  digest_t digest(mode);
233  if(digest.puts((string_t)user + ":" + (string_t)realm + ":" + (string_t)secret))
234  digestbuf = *digest;
235  else
236  shell::errexit(6, "** sipcontrol: digest: unsupported computation");
237 
238  printf("%s\n", *digestbuf);
239  exit(0);
240 }
241 
242 static void realm(char **argv)
243 {
244  char *realm = NULL;
245  const char *mode = NULL;
246  fsys_t fs;
247  char buffer[256];
248  char replace[256];
249  char *cp = NULL;
250  FILE *fp;
251 
252 #ifdef _MSWINDOWS_
253  const char *control = "\\\\.\\mailslot\\sipwitch_ctrl";
254 #else
255  const char *control = DEFAULT_VARPATH "/run/sipwitch/control";
256 #endif
257 
258  if(!argv[1])
259  showrealm();
260 
261  mode = argv[2];
262  if(!mode)
263  mode = "md5";
264 
265  fs.open(DEFAULT_CFGPATH "/siprealm", fsys::RDONLY);
266  memset(buffer, 0, sizeof(buffer));
267  if(is(fs)) {
268  fs.read(buffer, sizeof(buffer) - 1);
269  fs.close();
270  cp = strchr(buffer, ':');
271  if(cp)
272  *(cp++) = 0;
273  }
274 
275  realm = argv[1];
276  if(!realm)
277  realm = buffer;
278 
279  if(!cp || !*cp)
280  cp = (char *)"md5";
281 
282  // make sure we have a valid mode, default is md5...
283  if(!mode && cp && *cp)
284  mode = cp;
285 
286  if(!mode)
287  mode = "md5";
288 
289  // if unchanged, we leave alone...
290  if(eq(buffer, realm) && eq(cp, mode))
291  goto exit;
292 
293  // create replacement realm string...
294  if(eq(mode, "md5"))
295  String::set(replace, sizeof(replace), realm);
296  else
297  snprintf(replace, sizeof(replace), "%s:%s", realm, mode);
298 
299  ::remove(DEFAULT_CFGPATH "/siprealm");
300  fs.open(DEFAULT_CFGPATH "/siprealm", fsys::GROUP_PUBLIC, fsys::WRONLY);
301  if(is(fs)) {
302  fs.write(replace, strlen(replace));
303  fs.close();
304  }
305  else
306  shell::errexit(3, "*** sipcontrol: realm: root permission required\n");
307 
308  // if server is up, also sync server with realm change...
309  fp = fopen(control, "w");
310  if(fp) {
311  fprintf(fp, "realm %s\n", realm);
312  fclose(fp);
313  }
314 
315 exit:
316  printf("%s\n", realm);
317  exit(0);
318 }
319 
320 static void status(char **argv)
321 {
322  if(argv[1])
323  shell::errexit(1, "*** sipcontrol: status: no arguments used\n");
324 
325  mapinit();
326 
327  mapped_view<MappedCall> calls(*callmap);
328  unsigned count = calls.count();
329  unsigned index = 0;
330  const volatile MappedCall *map;
331 
332  if(!count)
333  shell::errexit(10, "*** sipcontrol: status: offline\n");
334 
335  while(index < count) {
336  map = (const volatile MappedCall *)(calls(index++));
337  if(map->state[0])
338  fputc(map->state[0], stdout);
339  else
340  fputc(' ', stdout);
341  }
342  fputc('\n', stdout);
343  fflush(stdout);
344  exit(0);
345 }
346 
347 static void calls(char **argv)
348 {
349  if(argv[1])
350  shell::errexit(1, "*** sipcontrol: calls: no arguments used\n");
351 
352  mapinit();
353 
354  mapped_view<MappedCall> calls(*callmap);
355  unsigned count = calls.count();
356  unsigned index = 0;
357  const volatile MappedCall *map;
358  time_t now;
359 
360  if(!count)
361  shell::errexit(10, "*** sipcontrol: calls: offline\n");
362 
363  time(&now);
364  while(index < count) {
365  map = (const volatile MappedCall *)(calls(index++));
366 
367  if(!map->created || !map->source[0])
368  continue;
369 
370  if(map->active)
371  printf("%08x:%d %s %s \"%s\" -> %s; %ld sec(s)\n", map->sequence, map->cid, map->state + 1, map->source, map->display, map->target, (long)(now - map->active));
372  else
373  printf("%08x:%d %s %s \"%s\" -> none; %ld secs\n", map->sequence, map->cid, map->state + 1, map->source, map->display, (long)(now - map->created));
374  }
375  exit(0);
376 }
377 
378 static void periodic(char **argv)
379 {
380  char text[80];
381 
382  if(argv[1])
383  shell::errexit(1, "*** sipcontrol: pstats: no arguments used\n");
384 
385  mapinit();
386 
387  mapped_view<stats> sta(*statmap);
388  unsigned count = sta.count();
389  unsigned index = 0;
390  const volatile stats *map;
391 
392  if(!count)
393  shell::errexit(10, "*** sipcontrol: pstats: offline\n");
394 
395  while(index < count) {
396  map = (const volatile stats *)(sta(index++));
397 
398  if(!map->id[0])
399  continue;
400 
401  if(map->limit)
402  snprintf(text, sizeof(text), "%-12s %05hu", map->id, map->limit);
403  else
404  snprintf(text, sizeof(text), "%-12s - ", map->id);
405 
406  for(unsigned entry = 0; entry < 2; ++entry) {
407  size_t len = strlen(text);
408  snprintf(text + len, sizeof(text) - len, " %07lu %05hu %05hu",
409  map->data[entry].pperiod,
410  map->data[entry].pmin,
411  map->data[entry].pmax);
412  }
413  printf("%s\n", text);
414  }
415  exit(0);
416 }
417 
418 static void showevents(char **argv)
419 {
420 #ifdef _MSWINDOWS_
421  socket_t ipc = ::socket(AF_INET, SOCK_STREAM, 0);
422  struct sockaddr_in addr;
423 #else
424  socket_t ipc = ::socket(AF_UNIX, SOCK_STREAM, 0);
425  struct sockaddr_un addr;
426  struct passwd *pwd = getpwuid(getuid());
427  const char *userid = NULL;
428 #endif
429 
430  static string_t contact = "-";
431  static string_t publish = "-";
432 
433  if(argv[1])
434  shell::errexit(1, "*** sipcontrol: events: no arguments used\n");
435 
436  if(ipc == INVALID_SOCKET)
437  shell::errexit(9, "*** sipcontrol: events: cannot create event socket\n");
438 
439  memset(&addr, 0, sizeof(addr));
440 
441 #ifdef _MSWINDOWS_
442  DWORD port = 0;
443  DWORD index = 0;
444  TCHAR keyname[128];
445  TCHAR keyvalue[128];
446  DWORD size = sizeof(keyname), vsize = sizeof(keyvalue), vtype;
447  DWORD *dp;
448 
449  HKEY keys = HKEY_LOCAL_MACHINE, subkey;
450  if(RegOpenKeyEx(keys, "SOFTWARE\\sipwitch", 0, KEY_READ, &subkey) != ERROR_SUCCESS)
451  shell::errexit(10, "*** sipcontrol: events: no service found\n");
452  while((RegEnumValue(subkey, index++, keyname, &size, NULL, &vtype, (BYTE *)keyvalue, &vsize) == ERROR_SUCCESS) && (vtype == REG_DWORD) && (keyname[0] != 0)) {
453  dp = (DWORD *)&keyvalue;
454  if(eq("port", keyname))
455  port = *dp;
456 // else if(eq("pid", keyname))
457 // pid = *dp;
458  vsize = sizeof(keyvalue);
459  size = sizeof(keyname);
460  }
461  RegCloseKey(subkey);
462  if(!port)
463  shell::errexit(10, "*** sipcontrol: events: server missing\n");
464  addr.sin_family = AF_INET;
465  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
466  addr.sin_port = htons((unsigned short)port);
467  if(::connect(ipc, (struct sockaddr *)&addr, sizeof(addr)) < 0)
468  shell::errexit(10, "*** sipcontrol: events: server offline\n");
469 #else
470  addr.sun_family = AF_UNIX;
471  String::set(addr.sun_path, sizeof(addr.sun_path), DEFAULT_VARPATH "/run/sipwitch/events");
472  if(::connect(ipc, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0) {
473  if(pwd)
474  userid = pwd->pw_name;
475  if(!pwd || !userid)
476  shell::errexit(4, "*** sipcontrol: events: invalid login\n");
477 
478  memset(&addr, 0, sizeof(addr));
479  addr.sun_family = AF_UNIX;
480  snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/sipwitch-%s/events", userid);
481  if(::connect(ipc, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0)
482  shell::errexit(10, "*** sipcontrol: events: server offline\n");
483  }
484 #endif
485 
486  event_t event;
487  while(::recv(ipc, (char *)&event, sizeof(event), 0) == sizeof(event)) {
488  switch(event.type) {
489  case events::FAILURE:
490  printf("failure: %s\n", event.msg.reason);
491  break;
492  case events::WARNING:
493  printf("warning: %s\n", event.msg.reason);
494  break;
495  case events::NOTICE:
496  printf("notice: %s\n", event.msg.reason);
497  break;
498  case events::CONTACT:
499  if(!eq(contact, event.msg.contact)) {
500  printf("contact: %s\n", event.msg.contact);
501  contact ^= event.msg.contact;
502  }
503  break;
504  case events::PUBLISH:
505  if(!eq(publish, event.msg.contact)) {
506  printf("publish: %s\n", event.msg.contact);
507  publish ^= event.msg.contact;
508  }
509  break;
510  case events::WELCOME:
511  printf("server version %s %s\n",
512  event.msg.server.version, event.msg.server.state);
513  break;
514  case events::TERMINATE:
515  printf("exiting: %s\n", event.msg.reason);
516  exit(0);
517  case events::CALL:
518  printf("connecting %s to %s on %s\n",
519  event.msg.call.caller, event.msg.call.dialed, event.msg.call.network);
520  break;
521  case events::DROP:
522  printf("disconnect %s from %s, reason=%s\n",
523  event.msg.call.caller, event.msg.call.dialed, event.msg.call.reason);
524  break;
525  case events::RELEASE:
526  if(event.msg.user.extension)
527  printf("releasing %s, extension %d\n",
528  event.msg.user.id, event.msg.user.extension);
529  else
530  printf("releasing %s\n", event.msg.user.id);
531  break;
532  case events::ACTIVATE:
533  if(event.msg.user.extension)
534  printf("activating %s, extension %d\n",
535  event.msg.user.id, event.msg.user.extension);
536  else
537  printf("activating %s\n", event.msg.user.id);
538  break;
539  case events::STATE:
540  printf("changing state to %s\n", event.msg.server.state);
541  break;
542  case events::REALM:
543  printf("changing realm to %s\n", event.msg.server.realm);
544  break;
545  case events::SYNC:
546  if(event.msg.period)
547  printf("housekeeping period %d\n", event.msg.period);
548  break;
549  }
550  }
551  shell::errexit(11, "*** sipcontrol: events: connection lost\n");
552 }
553 
554 static void dumpstats(char **argv)
555 {
556  char text[80];
557  time_t now;
558 
559  if(argv[1])
560  shell::errexit(1, "*** sipcontrol: stats: no arguments used\n");
561 
562  mapinit();
563 
564  mapped_view<stats> sta(*statmap);
565  unsigned count = sta.count();
566  unsigned index = 0;
567  stats map;
568  unsigned current;
569 
570  if(!count)
571  shell::errexit(10, "*** sipcontrol: stats: offline\n");
572 
573  time(&now);
574  while(index < count) {
575  sta.copy(index++, map);
576  if(!map.id[0])
577  continue;
578 
579  if(map.limit)
580  snprintf(text, sizeof(text), "%-12s %05hu", map.id, map.limit);
581  else
582  snprintf(text, sizeof(text), "%-12s - ", map.id);
583 
584  for(unsigned entry = 0; entry < 2; ++entry) {
585  size_t len = strlen(text);
586  snprintf(text + len, sizeof(text) - len, " %09lu %05hu %05hu",
587  map.data[entry].total,
588  map.data[entry].current,
589  map.data[entry].peak);
590  }
591  current = map.data[0].current + map.data[1].current;
592  if(current)
593  printf("%s 0s\n", text);
594  else if(!map.lastcall)
595  printf("%s -\n", text);
596  else if(now - map.lastcall > (3600l * 99l))
597  printf("%s %ld%c\n", text, (long)((now - map.lastcall) / (3600l * 24l)), 'd');
598  else if(now - map.lastcall > (60l * 120l))
599  printf("%s %ld%c\n", text, (long)((now - map.lastcall) / 3600l), 'h');
600  else if(now - map.lastcall > 120l)
601  printf("%s %ld%c\n", text, (long)((now - map.lastcall) / 60l), 'm');
602  else
603  printf("%s %ld%c\n", text, (long)(now - map.lastcall), 's');
604  }
605  exit(0);
606 }
607 
608 static void registry(char **argv)
609 {
610  mapinit();
611 
612  mapped_view<MappedRegistry> reg(*regmap);
613  unsigned count = reg.count();
614  unsigned found = 0, index = 0;
615  MappedRegistry buffer;
616  time_t now;
617  char ext[8], exp[8], use[8];
618  const char *type;
619 
620  if(argv[1])
621  shell::errexit(1, "*** sipcontrol: registry: too many arguments\n");
622 
623  if(!count)
624  shell::errexit(10, "*** sipcontrol: registry: offline\n");
625 
626  time(&now);
627  while(index < count) {
628  reg.copy(index++, buffer);
629  if(buffer.type == MappedRegistry::EXPIRED)
630  continue;
631  else if(buffer.type == MappedRegistry::TEMPORARY && !buffer.inuse)
632  continue;
633 
634  if(!found++)
635  printf("%7s %-30s type %-30s use expires address\n", "ext", "user", "profile");
636  ext[0] = 0;
637  if(buffer.ext)
638  snprintf(ext, sizeof(ext), "%7d", buffer.ext);
639  exp[0] = '-';
640  exp[1] = 0;
641  snprintf(use, sizeof(use), "%u", buffer.inuse);
642  if(buffer.expires && buffer.type != MappedRegistry::TEMPORARY)
643  snprintf(exp, sizeof(exp), "%ld", (long)(buffer.expires - now));
644  switch(buffer.type) {
646  type = "rej";
647  break;
649  type = "ref";
650  break;
652  type = "gw";
653  break;
655  type = "svc";
656  break;
658  type = "temp";
659  break;
660  default:
661  type = "user";
662  };
663  printf("%7s %-30s %-4s %-30s %4s %7s ", ext, buffer.userid, type, buffer.profile.id, use, exp);
664  paddress(&buffer.contact, NULL);
665  fflush(stdout);
666  }
667 
668  printf("found %d entries active of %d\n", found, count);
669  exit(0);
670 }
671 
672 static void command(char **argv, unsigned timeout)
673 {
674  char buffer[512];
675  size_t len;
676  fd_t fd;
677 
678 #ifdef _MSWINDOWS_
679  snprintf(buffer, sizeof(buffer), "\\\\.\\mailslot\\sipwitch_ctrl");
680  fd = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
681 #else
682  sigset_t sigs;
683  int signo;
684  struct passwd *pwd = getpwuid(getuid());
685  const char *userid = NULL;
686 
687  sigemptyset(&sigs);
688  sigaddset(&sigs, SIGUSR1);
689  sigaddset(&sigs, SIGUSR2);
690  sigaddset(&sigs, SIGALRM);
691  pthread_sigmask(SIG_BLOCK, &sigs, NULL);
692 
693  fd = ::open(DEFAULT_VARPATH "/run/sipwitch/control", O_WRONLY | O_NONBLOCK);
694  if(fd < 0) {
695  if(pwd)
696  userid = pwd->pw_name;
697  if(!pwd || !userid)
698  shell::errexit(4, "*** sipcontrol: events: invalid login\n");
699 
700  snprintf(buffer, sizeof(buffer), "/tmp/sipwitch-%s/control", userid);
701  fd = ::open(buffer, O_WRONLY | O_NONBLOCK);
702  }
703 #endif
704 
705  if(fd == INVALID_HANDLE_VALUE)
706  shell::errexit(10, "*** sipcontrol: command: offline\n");
707 
708 #ifndef _MSWINDOWS_
709  if(timeout)
710  snprintf(buffer, sizeof(buffer), "%ld", (long)getpid());
711  else
712 #endif
713  buffer[0] = 0;
714 
715  while(*argv) {
716  len = strlen(buffer);
717  snprintf(buffer + len, sizeof(buffer) - len - 1, " %s", *(argv++));
718  }
719 
720 #ifdef _MSWINDOWS_
721  if(!WriteFile(fd, buffer, (DWORD)strlen(buffer) + 1, NULL, NULL))
722  shell::errexit(11, "*** sipcontrol: control failed\n");
723 #else
724  len = strlen(buffer);
725  buffer[len++] = '\n';
726  buffer[len] = 0;
727 
728  if(::write(fd, buffer, len) < (int)len)
729  shell::errexit(11, "*** sipcontrol: control failed\n");
730 
731  if(!timeout)
732  exit(0);
733 
734  alarm(timeout);
735 #ifdef HAVE_SIGWAIT2
736  sigwait(&sigs, &signo);
737 #else
738  signo = sigwait(&sigs);
739 #endif
740  if(signo == SIGUSR1) {
741  capture();
742  exit(0);
743  }
744  if(signo == SIGALRM)
745  shell::errexit(12, "*** sipcontrol: command: timed out\n");
746 
747  shell::errexit(20, "*** sipcontrol: command: request failed\n");
748 #endif
749 }
750 
751 static void version(void)
752 {
753  printf("SIP Witch " VERSION "\n"
754  "Copyright (C) 2007,2008,2009 David Sugar, Tycho Softworks\n"
755  "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
756  "This is free software: you are free to change and redistribute it.\n"
757  "There is NO WARRANTY, to the extent permitted by law.\n");
758  exit(0);
759 }
760 
761 static void usage(void)
762 {
763  printf("usage: sipcontrol command\n"
764  "Commands:\n"
765  " abort Force daemon abort\n"
766  " activate <ext> <ipaddr> Assign registration\n"
767  " address <ipaddr> Set public ip address\n"
768  " calls List active calls on server\n"
769  " check Server deadlock check\n"
770  " concurrency <level> Server concurrency level\n"
771  " contact Server contact config address\n"
772  " digest id [realm [type]] Compute a digest\n"
773  " disable conf-id... Disable configurations\n"
774  " down Shut down server\n"
775  " drop <user|callid> Drop an active call\n"
776  " dump Dump server configuration\n"
777  " enable conf-id... Enable configurations\n"
778  " events Display server events\n"
779  " grant <group> Grant dir access to system group\n"
780  " history [bufsize] Set buffer or dump error log\n"
781  " ifup <iface> Notify interface came up\n"
782  " ifdown <iface> Notify interface went down\n"
783  " message <ext> <text> Send text message to extension\n"
784  " peering Print peering (published) address\n"
785  " period <interval> Collect periodic statistics\n"
786  " pstats Dump periodic statistics\n"
787  " realm [text [digest]] Show or set new server realm\n"
788  " registry Dump registry\n"
789  " release <ext> Release registration\n"
790  " reload Reload configuration\n"
791  " restart Server restart\n"
792  " siplog Dump sip log when tracing\n"
793  " snapshot Server snapshot\n"
794  " stats Dump server statistics\n"
795  " state <selection> Change server state\n"
796  " status Dump status string\n"
797  " trace <on|off|clear> Set sip message tracing\n"
798  " usercache Dump user cache\n"
799  " verbose <level> Server verbose logging level\n"
800  );
801 
802  printf("Report bugs to sipwitch-devel@gnu.org\n");
803  exit(0);
804 }
805 
806 static void single(char **argv, int timeout)
807 {
808  if(argv[1])
809  shell::errexit(1, "*** sipcontrol: %s: too many arguments\n", *argv);
810 
811  command(argv, timeout);
812 }
813 
814 static void level(char **argv, int timeout)
815 {
816  if(!argv[1])
817  shell::errexit(1, "*** sipcontrol: %s: level missing\n", *argv);
818 
819  if(argv[2])
820  shell::errexit(1, "*** sipcontrol: %s: too many arguments\n", *argv);
821 
822  command(argv, timeout);
823 }
824 
825 static void period(char **argv)
826 {
827  if(!argv[1])
828  shell::errexit(1, "*** sipcontrol: period: interval missing\n");
829 
830  if(argv[2])
831  shell::errexit(1, "*** sipcontrol: period: too many arguments\n");
832 
833  command(argv, 10);
834 }
835 
836 static void address(char **argv)
837 {
838  if(!argv[1])
839  shell::errexit(1, "*** sipcontrol: address: ipaddr missing\n");
840 
841  if(argv[2])
842  shell::errexit(1, "*** sipcontrol: address: too many arguments\n");
843 
844  command(argv, 10);
845 }
846 
847 static void state(char **argv)
848 {
849  if(!argv[1])
850  shell::errexit(1, "*** sipcontrol: state: value missing\n");
851 
852  if(argv[2])
853  shell::errexit(1, "*** sipcontrol: state: too many arguments\n");
854 
855  command(argv, 10);
856 }
857 
858 static void iface(char **argv)
859 {
860  if(!argv[1])
861  shell::errexit(1, "*** sipcontrol: %s: interface missing\n", *argv);
862 
863  if(argv[2])
864  shell::errexit(1, "*** sipcontrol: %s: too many arguments\n", *argv);
865 
866  command(argv, 20);
867 }
868 
869 static void drop(char **argv)
870 {
871  if(!argv[1])
872  shell::errexit(1, "*** sipcontrol: drop: user or callid missing\n");
873 
874  if(argv[2])
875  shell::errexit(1, "*** sipcontrol: drop: too many arguments\n");
876 
877  command(argv, 10);
878 }
879 
880 static void release(char **argv)
881 {
882  if(!argv[1])
883  shell::errexit(1, "*** sipcontrol: release: extension missing\n");
884 
885  if(argv[2])
886  shell::errexit(1, "*** sipcontrol: release: too many arguments\n");
887 
888  command(argv, 10);
889 }
890 
891 static void activate(char **argv)
892 {
893  if(!argv[1])
894  shell::errexit(1, "*** sipcontrol: activate: extension missing\n");
895 
896  if(!argv[2])
897  shell::errexit(1, "*** sipcontrol: activate: ipaddr missing\n");
898 
899  if(argv[3])
900  shell::errexit(1, "*** sipcontrol: activate: too many arguments\n");
901 
902  command(argv, 10);
903 }
904 
905 static void message(char **argv)
906 {
907  char buffer[500];
908 
909  if(!argv[1])
910  shell::errexit(1, "*** sipcontrol: message: extension missing\n");
911 
912  if(!argv[2])
913  shell::errexit(1, "*** sipcontrol: message: \"text\" missing\n");
914 
915  if(argv[3])
916  shell::errexit(1, "*** sipcontrol: message: too many arguments\n");
917 
918  if(argv[2][0] != '{') {
919  snprintf(buffer, sizeof(buffer), "{%s}", argv[2]);
920  argv[2] = buffer;
921  }
922  command(argv, 10);
923 }
924 
925 #ifdef HAVE_PWD_H
926 static void grant(char **argv)
927 {
928  gid_t gid = -1;
929  struct group *grp;
930  fsys::fileinfo_t ino;
931 
932  if(!argv[1])
933  shell::errexit(1, "*** sipcontrol: grant: no group specified\n");
934  if(argv[2])
935  shell::errexit(1, "*** sipcontrol: grant: not more than one group\n");
936 
937  grp = getgrnam(argv[1]);
938  if(grp)
939  gid = grp->gr_gid;
940  else if(atol(argv[1]))
941  gid = atol(argv[1]);
942  else
943  shell::errexit(2, "*** sipcontrol: grant: %s: unknown group", argv[1]);
944 
945  fsys::info(DEFAULT_VARPATH "/lib/sipwitch", &ino);
946  chmod(DEFAULT_VARPATH "/lib/sipwitch", ino.st_mode | 070);
947  if(chown(DEFAULT_VARPATH "/lib/sipwitch", ino.st_uid, gid))
948  shell::errexit(2, "*** sipcontrol: grant: %s: cannot change owner", argv[1]);
949 
950  fsys::info(DEFAULT_VARPATH "/cache/sipwitch", &ino);
951  chmod(DEFAULT_VARPATH "/cache/sipwitch", ino.st_mode | 070);
952  if(chown(DEFAULT_VARPATH "/cache/sipwitch", ino.st_uid, gid))
953  shell::errexit(2, "*** sipcontrol: grant: %s: cannot change owner", argv[1]);
954 
955  exit(0);
956 }
957 #else
958 static void grant(char **argv)
959 {
960  shell::errexit(9, "*** sipcontrol: grant: unsupported platform");
961 }
962 #endif
963 
964 #ifdef _MSWINDOWS_
965 
966 static void enable(char **argv)
967 {
968  shell::errexit(9, "*** sipcontrol: enable: unsupported platform");
969 }
970 
971 static void disable(char **argv)
972 {
973  shell::errexit(9, "*** sipcontrol: disable: unsupported platform");
974 }
975 
976 #else
977 
978 static void enable(char **argv)
979 {
980  char source[128], target[128];
981 
982  if(!argv[1])
983  shell::errexit(1, "*** sipcontrol: enable: no configs specified\n");
984 
985  while(*(++argv)) {
986  snprintf(source, sizeof(source), "%s/sipwitch.d/%s.xml", DEFAULT_CFGPATH, *argv);
987  snprintf(target, sizeof(target), "%s/lib/sipwitch/%s.xml", DEFAULT_VARPATH, *argv);
988  fsys::link(source, target);
989  }
990  exit(0);
991 }
992 
993 static void disable(char **argv)
994 {
995  char target[128];
996 
997  if(!argv[1])
998  shell::errexit(1, "*** sipcontrol: disable: no configs specified\n");
999 
1000  while(*(++argv)) {
1001  snprintf(target, sizeof(target), "%s/lib/sipwitch/%s.xml", DEFAULT_VARPATH, *argv);
1002  fsys::erase(target);
1003  }
1004  exit(0);
1005 }
1006 
1007 #endif
1008 
1010 {
1011  if(argc < 2)
1012  usage();
1013 
1014  ++argv;
1015  if(eq(*argv, "version") || eq(*argv, "-version") || eq(*argv, "--version"))
1016  version();
1017  else if(eq(*argv, "help") || eq(*argv, "-help") || eq(*argv, "--help"))
1018  usage();
1019  else if(eq(*argv, "reload") || eq(*argv, "check") || eq(*argv, "snapshot") || eq(*argv, "dump") || eq(*argv, "siplog") || eq(*argv, "usercache") || eq(*argv, "policy") || eq(*argv, "contact"))
1020  single(argv, 30);
1021  else if(eq(*argv, "history")) {
1022  if(argc == 2)
1023  single(argv, 30);
1024  else
1025  level(argv, 10);
1026  }
1027  else if(eq(*argv, "down") || eq(*argv, "restart") || eq(*argv, "abort"))
1028  single(argv, 0);
1029  else if(eq(*argv, "verbose") || eq(*argv, "concurrency") || eq(*argv, "trace"))
1030  level(argv, 10);
1031  else if(eq(*argv, "message"))
1032  message(argv);
1033  else if(eq(*argv, "registry"))
1034  registry(argv);
1035  else if(eq(*argv, "stats"))
1036  dumpstats(argv);
1037  else if(eq(*argv, "calls"))
1038  calls(argv);
1039  else if(eq(*argv, "digest"))
1040  compute(argv);
1041  else if(eq(*argv, "pstats"))
1042  periodic(argv);
1043  else if(eq(*argv, "address"))
1044  address(argv);
1045  else if(eq(*argv, "period"))
1046  period(argv);
1047  else if(eq(*argv, "activate"))
1048  activate(argv);
1049  else if(eq(*argv, "release"))
1050  release(argv);
1051  else if(eq(*argv, "state"))
1052  state(argv);
1053  else if(eq(*argv, "status"))
1054  status(argv);
1055  else if(eq(*argv, "ifdown") || eq(*argv, "ifup"))
1056  iface(argv);
1057  else if(eq(*argv, "realm"))
1058  realm(argv);
1059  else if(eq(*argv, "drop"))
1060  drop(argv);
1061  else if(eq(*argv, "grant"))
1062  grant(argv);
1063  else if(eq(*argv, "enable"))
1064  enable(argv);
1065  else if(eq(*argv, "disable"))
1066  disable(argv);
1067  else if(eq(*argv, "events"))
1068  showevents(argv);
1069 
1070  if(!argv[1])
1071  shell::errexit(1, "use: sipcontrol command [arguments...]\n");
1072  else
1073  shell::errexit(1, "*** sipcontrol: %s: unknown command or option\n", argv[0]);
1074  PROGRAM_EXIT(1);
1075 }
1076 
unsigned long total
Definition: stats.h:69
A stat element of call traffic.
Definition: stats.h:57
char display[64]
Definition: mapped.h:155
unsigned count
Definition: cgiserver.cpp:92
unsigned period
Definition: events.h:108
struct sipwitch::events::@1::@3 user
Event message and supporting methods for plugins.
Definition: events.h:66
unsigned short current
Definition: stats.h:70
char reason[16]
Definition: events.h:90
Representation of a mapped active user record.
Definition: mapped.h:95
sockaddr_internet contact
Definition: mapped.h:111
uint32_t sequence
Definition: mapped.h:156
unsigned short limit
Definition: stats.h:74
char id[12]
Definition: stats.h:60
volatile time_t expires
Definition: mapped.h:113
char id[48]
Definition: mapped.h:84
unsigned short peak
Definition: stats.h:70
char state[16]
Definition: mapped.h:152
struct sipwitch::events::@1::@4 server
char target[(48+50)]
Definition: mapped.h:154
Server control interfaces and functions.
Definition: control.h:58
unsigned short pmin
Definition: stats.h:70
PROGRAM_MAIN(argc, argv)
#define REGISTRY_MAP
Definition: mapped.h:77
time_t lastcall
Definition: stats.h:73
unsigned short pmax
Definition: stats.h:70
Top level include directory for GNU Telephony SIP Witch Server.
char contact[160]
Definition: events.h:106
Representation of an active call record.
Definition: mapped.h:147
type_t type
Type of event message.
Definition: events.h:82
struct sipwitch::events::@1::@2 call
short argc
Definition: cgiserver.cpp:93
struct sipwitch::stats::@9 data[2]
We have stats for both incoming and outgoing traffic of various kinds.
char source[(48+50)]
Definition: mapped.h:154
union sipwitch::events::@1 msg
Content of message, based on type.
char * map[96]
Definition: cgiserver.cpp:89
#define STAT_MAP
Definition: stats.h:45
unsigned long pperiod
Definition: stats.h:69
volatile unsigned inuse
Definition: mapped.h:110
#define CALL_MAP
Definition: mapped.h:76
enum sipwitch::MappedRegistry::@5 type