17 #include <sipwitch-config.h>
19 #include <ucommon/secure.h>
30 #if !defined(_MSWINDOWS_)
34 using namespace sipwitch;
41 static char *getpass(
const char *prompt)
46 fputs(prompt, stderr);
48 for (i = 0; i <
sizeof(buf) - 1; i++) {
49 buf[i] = fgetc(stdin);
50 if (buf[i] ==
'\r' || buf[i] ==
'\n')
63 static void capture(
void)
68 snprintf(buffer,
sizeof(buffer),
"/tmp/.sipwitch.%ld", (
long)getpid());
69 fp = fopen(buffer,
"r");
71 while(fp && fgets(buffer,
sizeof(buffer), fp) != NULL)
72 fputs(buffer, stdout);
78 static void paddress(
struct sockaddr_internet *a1,
struct sockaddr_internet *a2)
84 unsigned p1 = 0, p2 = 0;
89 Socket::query((
struct sockaddr *)a1, buf,
sizeof(buf));
90 switch(a1->address.sa_family) {
92 p1 = (unsigned)ntohs(a1->ipv4.sin_port);
96 p1 = (unsigned)ntohs(a1->ipv6.sin6_port);
102 switch(a2->address.sa_family) {
104 p2 = (unsigned)ntohs(a2->ipv4.sin_port);
108 p2 = (unsigned)ntohs(a2->ipv6.sin6_port);
118 printf(
"%s:%u%c", buf, p1, sep);
120 printf(
"none%c", sep);
125 Socket::query((
struct sockaddr *)a2, buf,
sizeof(buf));
126 printf(
"%s:%u\n", buf, p2);
129 static void mapinit(
void)
132 struct passwd *pwd = getpwuid(getuid());
133 const char *userid = NULL;
135 fd_t fd = ::open(DEFAULT_VARPATH
"/run/sipwitch/control", O_WRONLY | O_NONBLOCK);
138 userid = pwd->pw_name;
140 shell::errexit(4,
"*** sipcontrol: maps: invalid login\n");
142 statmap = str(
STAT_MAP "-") + str(userid);
143 callmap = str(
CALL_MAP "-") + str(userid);
151 static void showrealm(
void)
156 fs.open(DEFAULT_CFGPATH
"/siprealm", fsys::RDONLY);
158 fs.open(DEFAULT_VARPATH
"/lib/sipwitch/uuid", fsys::RDONLY);
162 shell::errexit(1,
"*** sipcontrol: realm: no public realm known\n");
164 memset(buffer, 0,
sizeof(buffer));
165 fs.read(buffer,
sizeof(buffer) - 1);
168 char *cp = strchr(buffer,
'\n');
172 cp = strchr(buffer,
':');
179 printf(
"%s\n", buffer);
183 static void compute(
char **argv)
186 const char *user, *secret;
187 const char *mode =
"md5";
193 shell::errexit(3,
"*** sipcontrol: digest: userid missing\n");
195 secret = getpass(
"Enter new SIP secret: ");
196 if(!secret || !*secret) {
197 printf(
"no password supplied\n");
208 fs.open(DEFAULT_CFGPATH
"/siprealm", fsys::RDONLY);
210 fs.open(DEFAULT_VARPATH
"/lib/sipwitch/uuid", fsys::RDONLY);
213 shell::errexit(4,
"*** sipcontrol: digest: no public realm known\n");
215 memset(buffer, 0,
sizeof(buffer));
216 fs.read(buffer,
sizeof(buffer) - 1);
219 char *cp = strchr(buffer,
'\n');
223 cp = strchr(buffer,
':');
229 realm = strdup(buffer);
232 digest_t digest(mode);
233 if(digest.puts((string_t)user +
":" + (string_t)realm +
":" + (string_t)secret))
236 shell::errexit(6,
"** sipcontrol: digest: unsupported computation");
238 printf(
"%s\n", *digestbuf);
242 static void realm(
char **argv)
245 const char *mode = NULL;
253 const char *
control =
"\\\\.\\mailslot\\sipwitch_ctrl";
255 const char *control = DEFAULT_VARPATH
"/run/sipwitch/control";
265 fs.open(DEFAULT_CFGPATH
"/siprealm", fsys::RDONLY);
266 memset(buffer, 0,
sizeof(buffer));
268 fs.read(buffer,
sizeof(buffer) - 1);
270 cp = strchr(buffer,
':');
283 if(!mode && cp && *cp)
290 if(eq(buffer, realm) && eq(cp, mode))
295 String::set(replace,
sizeof(replace), realm);
297 snprintf(replace,
sizeof(replace),
"%s:%s", realm, mode);
299 ::remove(DEFAULT_CFGPATH
"/siprealm");
300 fs.open(DEFAULT_CFGPATH
"/siprealm", fsys::GROUP_PUBLIC, fsys::WRONLY);
302 fs.write(replace, strlen(replace));
306 shell::errexit(3,
"*** sipcontrol: realm: root permission required\n");
309 fp = fopen(control,
"w");
311 fprintf(fp,
"realm %s\n", realm);
316 printf(
"%s\n", realm);
320 static void status(
char **argv)
323 shell::errexit(1,
"*** sipcontrol: status: no arguments used\n");
327 mapped_view<MappedCall> calls(*callmap);
328 unsigned count = calls.count();
333 shell::errexit(10,
"*** sipcontrol: status: offline\n");
335 while(index < count) {
336 map = (
const volatile MappedCall *)(calls(index++));
338 fputc(map->
state[0], stdout);
347 static void calls(
char **argv)
350 shell::errexit(1,
"*** sipcontrol: calls: no arguments used\n");
354 mapped_view<MappedCall> calls(*callmap);
355 unsigned count = calls.count();
361 shell::errexit(10,
"*** sipcontrol: calls: offline\n");
364 while(index < count) {
365 map = (
const volatile MappedCall *)(calls(index++));
378 static void periodic(
char **argv)
383 shell::errexit(1,
"*** sipcontrol: pstats: no arguments used\n");
387 mapped_view<stats> sta(*statmap);
388 unsigned count = sta.count();
393 shell::errexit(10,
"*** sipcontrol: pstats: offline\n");
395 while(index < count) {
396 map = (
const volatile stats *)(sta(index++));
402 snprintf(text,
sizeof(text),
"%-12s %05hu", map->
id, map->
limit);
404 snprintf(text,
sizeof(text),
"%-12s - ", map->
id);
406 for(
unsigned entry = 0; entry < 2; ++entry) {
407 size_t len = strlen(text);
408 snprintf(text + len,
sizeof(text) - len,
" %07lu %05hu %05hu",
413 printf(
"%s\n", text);
418 static void showevents(
char **argv)
421 socket_t ipc = ::socket(AF_INET, SOCK_STREAM, 0);
422 struct sockaddr_in addr;
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;
430 static string_t contact =
"-";
431 static string_t publish =
"-";
434 shell::errexit(1,
"*** sipcontrol: events: no arguments used\n");
436 if(ipc == INVALID_SOCKET)
437 shell::errexit(9,
"*** sipcontrol: events: cannot create event socket\n");
439 memset(&addr, 0,
sizeof(addr));
446 DWORD size =
sizeof(keyname), vsize =
sizeof(keyvalue), vtype;
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))
458 vsize =
sizeof(keyvalue);
459 size =
sizeof(keyname);
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");
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) {
474 userid = pwd->pw_name;
476 shell::errexit(4,
"*** sipcontrol: events: invalid login\n");
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");
487 while(::recv(ipc, (
char *)&event,
sizeof(event), 0) ==
sizeof(event)) {
490 printf(
"failure: %s\n", event.
msg.
reason);
493 printf(
"warning: %s\n", event.
msg.
reason);
496 printf(
"notice: %s\n", event.
msg.
reason);
501 contact ^=
event.msg.contact;
507 publish ^=
event.msg.contact;
511 printf(
"server version %s %s\n",
515 printf(
"exiting: %s\n", event.
msg.
reason);
518 printf(
"connecting %s to %s on %s\n",
522 printf(
"disconnect %s from %s, reason=%s\n",
527 printf(
"releasing %s, extension %d\n",
530 printf(
"releasing %s\n", event.
msg.
user.id);
534 printf(
"activating %s, extension %d\n",
537 printf(
"activating %s\n", event.
msg.
user.id);
540 printf(
"changing state to %s\n", event.
msg.
server.state);
543 printf(
"changing realm to %s\n", event.
msg.
server.realm);
547 printf(
"housekeeping period %d\n", event.
msg.
period);
551 shell::errexit(11,
"*** sipcontrol: events: connection lost\n");
554 static void dumpstats(
char **argv)
560 shell::errexit(1,
"*** sipcontrol: stats: no arguments used\n");
564 mapped_view<stats> sta(*statmap);
565 unsigned count = sta.count();
571 shell::errexit(10,
"*** sipcontrol: stats: offline\n");
574 while(index < count) {
575 sta.copy(index++, map);
580 snprintf(text,
sizeof(text),
"%-12s %05hu", map.
id, map.
limit);
582 snprintf(text,
sizeof(text),
"%-12s - ", map.
id);
584 for(
unsigned entry = 0; entry < 2; ++entry) {
585 size_t len = strlen(text);
586 snprintf(text + len,
sizeof(text) - len,
" %09lu %05hu %05hu",
593 printf(
"%s 0s\n", text);
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');
601 printf(
"%s %ld%c\n", text, (
long)((now - map.
lastcall) / 60l),
'm');
603 printf(
"%s %ld%c\n", text, (
long)(now - map.
lastcall),
's');
612 mapped_view<MappedRegistry> reg(*regmap);
613 unsigned count = reg.count();
614 unsigned found = 0, index = 0;
617 char ext[8], exp[8], use[8];
621 shell::errexit(1,
"*** sipcontrol: registry: too many arguments\n");
624 shell::errexit(10,
"*** sipcontrol: registry: offline\n");
627 while(index < count) {
628 reg.copy(index++, buffer);
635 printf(
"%7s %-30s type %-30s use expires address\n",
"ext",
"user",
"profile");
638 snprintf(ext,
sizeof(ext),
"%7d", buffer.
ext);
641 snprintf(use,
sizeof(use),
"%u", buffer.
inuse);
643 snprintf(exp,
sizeof(exp),
"%ld", (
long)(buffer.
expires - now));
644 switch(buffer.
type) {
663 printf(
"%7s %-30s %-4s %-30s %4s %7s ", ext, buffer.
userid, type, buffer.
profile.
id, use, exp);
664 paddress(&buffer.
contact, NULL);
668 printf(
"found %d entries active of %d\n", found, count);
672 static void command(
char **argv,
unsigned timeout)
679 snprintf(buffer,
sizeof(buffer),
"\\\\.\\mailslot\\sipwitch_ctrl");
680 fd = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
684 struct passwd *pwd = getpwuid(getuid());
685 const char *userid = NULL;
688 sigaddset(&sigs, SIGUSR1);
689 sigaddset(&sigs, SIGUSR2);
690 sigaddset(&sigs, SIGALRM);
691 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
693 fd = ::open(DEFAULT_VARPATH
"/run/sipwitch/control", O_WRONLY | O_NONBLOCK);
696 userid = pwd->pw_name;
698 shell::errexit(4,
"*** sipcontrol: events: invalid login\n");
700 snprintf(buffer,
sizeof(buffer),
"/tmp/sipwitch-%s/control", userid);
701 fd = ::open(buffer, O_WRONLY | O_NONBLOCK);
705 if(fd == INVALID_HANDLE_VALUE)
706 shell::errexit(10,
"*** sipcontrol: command: offline\n");
710 snprintf(buffer,
sizeof(buffer),
"%ld", (
long)getpid());
716 len = strlen(buffer);
717 snprintf(buffer + len,
sizeof(buffer) - len - 1,
" %s", *(argv++));
721 if(!WriteFile(fd, buffer, (DWORD)strlen(buffer) + 1, NULL, NULL))
722 shell::errexit(11,
"*** sipcontrol: control failed\n");
724 len = strlen(buffer);
725 buffer[len++] =
'\n';
728 if(::write(fd, buffer, len) < (
int)len)
729 shell::errexit(11,
"*** sipcontrol: control failed\n");
736 sigwait(&sigs, &signo);
738 signo = sigwait(&sigs);
740 if(signo == SIGUSR1) {
745 shell::errexit(12,
"*** sipcontrol: command: timed out\n");
747 shell::errexit(20,
"*** sipcontrol: command: request failed\n");
751 static void version(
void)
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");
761 static void usage(
void)
763 printf(
"usage: sipcontrol command\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"
802 printf(
"Report bugs to sipwitch-devel@gnu.org\n");
806 static void single(
char **argv,
int timeout)
809 shell::errexit(1,
"*** sipcontrol: %s: too many arguments\n", *argv);
811 command(argv, timeout);
814 static void level(
char **argv,
int timeout)
817 shell::errexit(1,
"*** sipcontrol: %s: level missing\n", *argv);
820 shell::errexit(1,
"*** sipcontrol: %s: too many arguments\n", *argv);
822 command(argv, timeout);
825 static void period(
char **argv)
828 shell::errexit(1,
"*** sipcontrol: period: interval missing\n");
831 shell::errexit(1,
"*** sipcontrol: period: too many arguments\n");
836 static void address(
char **argv)
839 shell::errexit(1,
"*** sipcontrol: address: ipaddr missing\n");
842 shell::errexit(1,
"*** sipcontrol: address: too many arguments\n");
847 static void state(
char **argv)
850 shell::errexit(1,
"*** sipcontrol: state: value missing\n");
853 shell::errexit(1,
"*** sipcontrol: state: too many arguments\n");
858 static void iface(
char **argv)
861 shell::errexit(1,
"*** sipcontrol: %s: interface missing\n", *argv);
864 shell::errexit(1,
"*** sipcontrol: %s: too many arguments\n", *argv);
869 static void drop(
char **argv)
872 shell::errexit(1,
"*** sipcontrol: drop: user or callid missing\n");
875 shell::errexit(1,
"*** sipcontrol: drop: too many arguments\n");
880 static void release(
char **argv)
883 shell::errexit(1,
"*** sipcontrol: release: extension missing\n");
886 shell::errexit(1,
"*** sipcontrol: release: too many arguments\n");
891 static void activate(
char **argv)
894 shell::errexit(1,
"*** sipcontrol: activate: extension missing\n");
897 shell::errexit(1,
"*** sipcontrol: activate: ipaddr missing\n");
900 shell::errexit(1,
"*** sipcontrol: activate: too many arguments\n");
905 static void message(
char **argv)
910 shell::errexit(1,
"*** sipcontrol: message: extension missing\n");
913 shell::errexit(1,
"*** sipcontrol: message: \"text\" missing\n");
916 shell::errexit(1,
"*** sipcontrol: message: too many arguments\n");
918 if(argv[2][0] !=
'{') {
919 snprintf(buffer,
sizeof(buffer),
"{%s}", argv[2]);
926 static void grant(
char **argv)
930 fsys::fileinfo_t ino;
933 shell::errexit(1,
"*** sipcontrol: grant: no group specified\n");
935 shell::errexit(1,
"*** sipcontrol: grant: not more than one group\n");
937 grp = getgrnam(argv[1]);
940 else if(atol(argv[1]))
943 shell::errexit(2,
"*** sipcontrol: grant: %s: unknown group", argv[1]);
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]);
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]);
958 static void grant(
char **argv)
960 shell::errexit(9,
"*** sipcontrol: grant: unsupported platform");
966 static void enable(
char **argv)
968 shell::errexit(9,
"*** sipcontrol: enable: unsupported platform");
971 static void disable(
char **argv)
973 shell::errexit(9,
"*** sipcontrol: disable: unsupported platform");
978 static void enable(
char **argv)
980 char source[128], target[128];
983 shell::errexit(1,
"*** sipcontrol: enable: no configs specified\n");
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);
993 static void disable(
char **argv)
998 shell::errexit(1,
"*** sipcontrol: disable: no configs specified\n");
1001 snprintf(target,
sizeof(target),
"%s/lib/sipwitch/%s.xml", DEFAULT_VARPATH, *argv);
1002 fsys::erase(target);
1015 if(eq(*argv,
"version") || eq(*argv,
"-version") || eq(*argv,
"--version"))
1017 else if(eq(*argv,
"help") || eq(*argv,
"-help") || eq(*argv,
"--help"))
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"))
1021 else if(eq(*argv,
"history")) {
1027 else if(eq(*argv,
"down") || eq(*argv,
"restart") || eq(*argv,
"abort"))
1029 else if(eq(*argv,
"verbose") || eq(*argv,
"concurrency") || eq(*argv,
"trace"))
1031 else if(eq(*argv,
"message"))
1033 else if(eq(*argv,
"registry"))
1035 else if(eq(*argv,
"stats"))
1037 else if(eq(*argv,
"calls"))
1039 else if(eq(*argv,
"digest"))
1041 else if(eq(*argv,
"pstats"))
1043 else if(eq(*argv,
"address"))
1045 else if(eq(*argv,
"period"))
1047 else if(eq(*argv,
"activate"))
1049 else if(eq(*argv,
"release"))
1051 else if(eq(*argv,
"state"))
1053 else if(eq(*argv,
"status"))
1055 else if(eq(*argv,
"ifdown") || eq(*argv,
"ifup"))
1057 else if(eq(*argv,
"realm"))
1059 else if(eq(*argv,
"drop"))
1061 else if(eq(*argv,
"grant"))
1063 else if(eq(*argv,
"enable"))
1065 else if(eq(*argv,
"disable"))
1067 else if(eq(*argv,
"events"))
1071 shell::errexit(1,
"use: sipcontrol command [arguments...]\n");
1073 shell::errexit(1,
"*** sipcontrol: %s: unknown command or option\n", argv[0]);
A stat element of call traffic.
struct sipwitch::events::@1::@3 user
Event message and supporting methods for plugins.
Representation of a mapped active user record.
sockaddr_internet contact
struct sipwitch::events::@1::@4 server
Server control interfaces and functions.
Top level include directory for GNU Telephony SIP Witch Server.
Representation of an active call record.
type_t type
Type of event message.
struct sipwitch::events::@1::@2 call
struct sipwitch::stats::@9 data[2]
We have stats for both incoming and outgoing traffic of various kinds.
union sipwitch::events::@1 msg
Content of message, based on type.
enum sipwitch::MappedRegistry::@5 type