2 * $Id: unixsock_server.c,v 1.17 2004/12/03 19:09:31 andrei Exp $
4 * UNIX Domain Socket Server
6 * Copyright (C) 2001-2004 FhG Fokus
8 * This file is part of ser, a free SIP server.
10 * ser is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version
15 * For a license to use the ser software under conditions
16 * other than those described here, or to purchase support for this
17 * software, please contact iptel.org by e-mail at the following addresses:
20 * ser is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 * 2004-03-03 added tcp init code (andrei)
32 * 2004-04-29 added chmod(sock_perm) & chown(sock_user,sock_group) (andrei)
38 #include <sys/types.h>
39 #include <sys/socket.h>
50 #include "sr_module.h"
52 #include "fifo_server.h" /* CMD_SEPARATOR */
53 #include "unixsock_server.h"
57 /* AF_LOCAL is not defined on solaris */
58 #if !defined(AF_LOCAL)
59 #define AF_LOCAL AF_UNIX
61 #if !defined(PF_LOCAL)
62 #define PF_LOCAL PF_UNIX
66 /* solaris doesn't have SUN_LEN */
68 #define SUN_LEN(sa) ( strlen((sa)->sun_path) + \
69 (size_t)(((struct sockaddr_un*)0)->sun_path) )
73 #define UNIXSOCK_BUF_SIZE BUF_SIZE
75 char* unixsock_name = 0;
76 int unixsock_children = 1;
77 int unixsock_tx_timeout = 2000; /* Timeout for sending replies in milliseconds */
80 static int rx_sock, tx_sock;
81 static struct unixsock_cmd* cmd_list = 0;
82 static char reply_buf[UNIXSOCK_BUF_SIZE];
84 static struct sockaddr_un reply_addr;
85 static unsigned int reply_addr_len;
87 static time_t up_since;
88 static char up_since_ctime[MAX_CTIME_LEN];
91 #define PRINT_CMD "print" /* Diagnostic command */
92 #define VERSION_CMD "version" /* Print the version of the server */
93 #define UPTIME_CMD "uptime" /* Print server's uptime */
94 #define WHICH_CMD "which" /* Print available FIFO commands */
95 #define PS_CMD "ps" /* Print server's process table */
96 #define ARG_CMD "arg" /* Print server's command line arguments */
97 #define PWD_CMD "pwd" /* Get the current working directory */
98 #define KILL_CMD "kill" /* Kill the server */
102 * Diagnostic and hello-world command
104 static int print_cmd(str* msg)
111 if (unixsock_read_line(&line, msg) < 0) {
112 unixsock_reply_asciiz("500 Error while reading text\n");
117 if (unixsock_reply_printf("200 OK\n%.*s\n", line.len, ZSW(line.s)) < 0) {
118 unixsock_reply_reset();
119 unixsock_reply_asciiz("500 Error while sending reply\n");
124 if (unixsock_reply_send() < 0) ret = -1;
130 * Print the version of the server
132 static int version_cmd(str* msg)
137 if (unixsock_reply_asciiz("200 OK\n" SERVER_HDR CRLF) < 0) ret = -1;
138 if (unixsock_reply_send() < 0) ret = -1;
143 static int uptime_cmd(str* msg)
151 if (unixsock_reply_printf("200 OK\nNow: %sUp Since: %sUp time: %.0f [sec]\n",
152 ctime(&now), up_since_ctime, difftime(now, up_since)) < 0) {
153 unixsock_reply_reset();
154 unixsock_reply_asciiz("500 Error while printing reply\n");
158 if (unixsock_reply_send() < 0) {
166 static int which_cmd(str* msg)
168 struct unixsock_cmd* c;
172 unixsock_reply_asciiz("200 OK\n");
174 for(c = cmd_list; c; c = c->next) {
175 if (unixsock_reply_printf("%s\n", c->name) < 0) {
176 unixsock_reply_reset();
177 unixsock_reply_asciiz("500 Error while creating reply\n");
183 if (unixsock_reply_send() < 0) {
190 static int ps_cmd(str* msg)
195 unixsock_reply_asciiz("200 OK\n");
196 for (p = 0; p < process_count(); p++) {
197 if (unixsock_reply_printf("%d\t%d\t%s\n", p, pt[p].pid, pt[p].desc) < 0) {
198 unixsock_reply_reset();
199 unixsock_reply_asciiz("500 Error while printing reply\n");
205 if (unixsock_reply_send() < 0) {
212 static int pwd_cmd(str* msg)
218 cwd_buf = pkg_malloc(max_len);
221 LOG(L_ERR, "pwd_cmd: No memory left\n");
222 unixsock_reply_asciiz("500 No Memory Left\n");
226 if (getcwd(cwd_buf, max_len)) {
227 if (unixsock_reply_printf("200 OK\n%s\n", cwd_buf) < 0) {
228 unixsock_reply_reset();
229 unixsock_reply_asciiz("500 Error while sending reply\n");
233 unixsock_reply_asciiz("500 getcwd Failed\n");
238 if (unixsock_reply_send() < 0) {
245 static int arg_cmd(str* msg)
250 unixsock_reply_asciiz("200 OK\n");
251 for (p = 0; p < my_argc; p++) {
252 if (unixsock_reply_printf("%s\n", my_argv[p]) < 0) {
253 unixsock_reply_reset();
254 unixsock_reply_asciiz("500 Could not create reply\n");
260 if (unixsock_reply_send() < 0) {
267 static int kill_cmd(str* msg)
269 unixsock_reply_asciiz("200 Killing now\n");
270 unixsock_reply_send();
276 static int register_core_commands(void)
278 if (unixsock_register_cmd(PRINT_CMD, print_cmd) < 0) {
282 if (unixsock_register_cmd(VERSION_CMD, version_cmd) < 0) {
286 if (unixsock_register_cmd(UPTIME_CMD, uptime_cmd) < 0) {
290 if (unixsock_register_cmd(WHICH_CMD, which_cmd) < 0) {
294 if (unixsock_register_cmd(PS_CMD, ps_cmd) < 0) {
298 if (unixsock_register_cmd(PWD_CMD, pwd_cmd) < 0) {
302 if (unixsock_register_cmd(ARG_CMD, arg_cmd) < 0) {
306 if (unixsock_register_cmd(KILL_CMD, kill_cmd) < 0) {
314 * Create and bind local socket
316 int init_unixsock_socket(void)
318 struct sockaddr_un addr;
321 if (unixsock_name == 0) {
322 DBG("init_unixsock_socket: No unix domain socket"
323 " will be opened\n");
327 len = strlen(unixsock_name);
329 DBG("init_unixsock_socket: Unix domain socket server disabled\n");
331 } else if (len > 107) {
332 LOG(L_ERR, "ERROR: init_unixsock_socket: Socket name too long\n");
336 DBG("init_unixsock_socket: Initializing Unix domain socket server @ %s\n",
339 if (unlink(unixsock_name) == -1) {
340 if (errno != ENOENT) {
341 LOG(L_ERR, "ERROR: init_unixsock_socket: Error while unlinking "
342 "old socket (%s): %s\n", unixsock_name, strerror(errno));
347 rx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
349 LOG(L_ERR, "ERROR: init_unixsock_socket: Cannot create RX "
350 "socket: %s\n", strerror(errno));
354 memset(&addr, 0, sizeof(addr));
355 addr.sun_family = PF_LOCAL;
356 memcpy(addr.sun_path, unixsock_name, len);
358 if (bind(rx_sock, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
359 LOG(L_ERR, "ERROR: init_unixsock_socket: bind: %s\n", strerror(errno));
362 /* try to change the permissions */
363 if (sock_mode){ /* sock_mode==0 doesn't make sense, nobody can read/write*/
364 if (chmod(unixsock_name, sock_mode)<0){
365 LOG(L_ERR, "ERROR: init_unixsock_socket: failed to change the"
366 " permissions for %s to %04o: %s[%d]\n",
367 unixsock_name, sock_mode, strerror(errno), errno);
371 /* try to change the ownership */
372 if ((sock_uid!=-1) || (sock_gid!=-1)){
373 if (chown(unixsock_name, sock_uid, sock_gid)<0){
374 LOG(L_ERR, "ERROR: init_unixsock_socket: failed to change the"
375 " owner/group for %s to %d.%d; %s[%d]\n",
376 unixsock_name, sock_uid, sock_gid, strerror(errno), errno);
381 tx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
383 LOG(L_ERR, "ERROR: init_unixsock_socket: Cannot create TX socket:"
384 " %s\n", strerror(errno));
388 /* Turn non-blocking mode on */
389 flags = fcntl(tx_sock, F_GETFL);
391 LOG(L_ERR, "ERROR: init_unixsock_socket: fcntl failed: %s\n",
396 if (fcntl(tx_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
397 LOG(L_ERR, "ERROR: init_unixsock_socket: fcntl: "
398 "set non-blocking failed: %s\n", strerror(errno));
411 static struct unixsock_cmd* lookup_cmd(str* cmd)
413 struct unixsock_cmd* c;
415 for(c = cmd_list; c; c = c->next) {
416 if ((cmd->len == c->name.len) &&
417 (strncasecmp(c->name.s, cmd->s, cmd->len) == 0)) {
425 static int parse_cmd(str* res, str* buffer)
429 if (!res || !buffer) {
430 LOG(L_ERR, "parse_cmd: Invalid parameter value\n");
434 if (buffer->len < 3) {
435 LOG(L_ERR, "parse_cmd: Message too short\n");
439 if (buffer->s[0] != CMD_SEPARATOR) {
440 LOG(L_ERR, "parse_cmd: Command must start with %c\n",
445 cmd_end = q_memchr(buffer->s + 1, CMD_SEPARATOR, buffer->len - 1);
447 LOG(L_ERR, "parse_cmd: Closing '%c' missing\n", CMD_SEPARATOR);
451 res->s = buffer->s + 1;
452 res->len = cmd_end - res->s;
457 static void skip_line(str* buffer)
462 while (buffer->len && (buffer->s[0] != '\n')) {
472 /* Skip CR following LF */
473 while (buffer->len && (buffer->s[0] == '\r')) {
480 static void unix_server_loop(void)
484 static char buf[UNIXSOCK_BUF_SIZE];
485 struct unixsock_cmd* c;
489 reply_addr_len = sizeof(reply_addr);
490 ret = recvfrom(rx_sock, buf, UNIXSOCK_BUF_SIZE, 0,
491 (struct sockaddr*)&reply_addr, &reply_addr_len);
493 LOG(L_ERR, "unix_server_loop: recvfrom: (%d) %s\n",
494 errno, strerror(errno));
495 if ((errno == EINTR) ||
497 (errno == EWOULDBLOCK) ||
498 (errno == ECONNREFUSED)) {
499 DBG("unix_server_loop: Got %d (%s), going on\n",
500 errno, strerror(errno));
503 LOG(L_CRIT, "BUG: unix_server_loop: unexpected recvfrom error\n");
509 unixsock_reply_reset();
511 if (parse_cmd(&cmd, &buffer) < 0) {
512 unixsock_reply_asciiz("400 First line malformed\n");
513 unixsock_reply_send();
517 buffer.s = cmd.s + cmd.len + 1;
518 buffer.len -= cmd.len + 1 + 1;
519 skip_line(&buffer); /* Skip the reply filename */
521 c = lookup_cmd(&cmd);
523 LOG(L_ERR, "unix_server_loop: Could not find "
524 "command '%.*s'\n", cmd.len, ZSW(cmd.s));
525 unixsock_reply_printf("500 Command %.*s not found\n", cmd.len, ZSW(cmd.s));
526 unixsock_reply_send();
532 LOG(L_ERR, "unix_server_loop: Command '%.*s' failed with "
533 "return value %d\n", cmd.len, ZSW(cmd.s), ret);
534 /* Note that we do not send reply here, the
535 * function is supposed to do so, it knows the
536 * reason of the failure better than us
543 static int get_uptime(void)
548 t = ctime(&up_since);
549 if (strlen(t) + 1 >= MAX_CTIME_LEN) {
550 LOG(L_ERR, "get_uptime: Too long date %d\n", (int)strlen(t));
553 memcpy(up_since_ctime, t, strlen(t) + 1);
561 int init_unixsock_children(void)
569 if (!unixsock_name || *unixsock_name == '\0') {
573 if (get_uptime() < 0) {
577 if (register_core_commands() < 0) {
583 for(i = 0; i < unixsock_children; i++) {
587 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
588 LOG(L_ERR, "ERROR: init_unixsock_server: socketpair"
589 " failed: %s\n", strerror(errno));
596 LOG(L_ERR, "init_unixsock_server: Unable to fork: %s\n",
601 } else if (pid == 0) { /* child */
605 unix_tcp_sock=sockfd[1];
608 if (init_child(PROC_UNIXSOCK) < 0) {
609 LOG(L_ERR, "init_unixsock_server: Error in "
616 unix_server_loop(); /* Never returns */
620 pt[process_no].pid = pid;
621 strncpy(pt[process_no].desc, "unix domain socket server",
626 pt[process_no].unix_sock=sockfd[0];
627 pt[process_no].idx=-1; /* this is not a "tcp"
634 DBG("init_unixsock_server: Unix domain socket server successfully initialized @ %s\n",
643 void close_unixsock_server(void)
645 struct unixsock_cmd* c;
651 cmd_list = cmd_list->next;
658 * Register a new command
660 int unixsock_register_cmd(char* command, unixsock_f* f)
663 struct unixsock_cmd* new_cmd;
666 cmd.len = strlen(command);
668 if (lookup_cmd(&cmd)) {
669 LOG(L_ERR, "unixsock_register_cmd: Function already exists\n");
673 new_cmd = pkg_malloc(sizeof(struct unixsock_cmd));
675 LOG(L_ERR, "register_unixsock_cmd: Out of mem\n");
682 new_cmd->next = cmd_list;
685 DBG("unixsock_register_cmd: New command (%.*s) registered\n",
686 cmd.len, ZSW(cmd.s));
691 int unixsock_add_to_reply(const char* buf, size_t len)
693 if (reply_pos.len < len) {
694 LOG(L_ERR, "unixsock_add_to_reply: Buffer too small\n");
698 memcpy(reply_pos.s, buf, len);
700 reply_pos.len -= len;
708 ssize_t unixsock_reply_send(void)
710 return tsend_dgram(tx_sock,
711 reply_buf, reply_pos.s - reply_buf,
712 (struct sockaddr*)&reply_addr, reply_addr_len,
713 unixsock_tx_timeout);
720 ssize_t unixsock_reply_sendto(struct sockaddr_un* to)
723 LOG(L_ERR, "unixsock_reply_sendto: Invalid parameter value\n");
727 return tsend_dgram(tx_sock,
728 reply_buf, reply_pos.s - reply_buf,
729 (struct sockaddr*)to, SUN_LEN(to),
730 unixsock_tx_timeout);
735 * Read a line, the result will be stored in line
736 * parameter, the data is not copied, it's just
737 * a pointer to an existing buffer
739 int unixsock_read_line(str* line, str* source)
741 if (!line || !source) {
742 LOG(L_ERR, "unixsock_read_line: Invalid parameter value\n");
748 line->len = source->s - line->s;
759 * Read body until the closing .CRLF, no CRLF recovery
760 * is done so no additional buffer is necessary, body will
761 * point to an existing buffer
763 int unixsock_read_body(str* body, str* source)
765 int i, state, last_dot;
774 if (!body || !source) {
775 LOG(L_ERR, "unixsock_read_body: Invalid parameter value\n");
779 if (source->len < 2) {
780 LOG(L_ERR, "unixsock_read_body: Not enough input data "
781 "(malformed message ?)\n");
788 for(i = 0; i < source->len; i++) {
791 if (source->s[i] == '.') {
794 } else if (source->s[i] == '\n') {
802 if (source->s[i] == '\n') {
803 body->len = last_dot;
805 source->len -= i + 1;
807 } else if (source->s[i] != '\r') {
813 if (source->s[i] == '\n') {
819 if (source->s[i] == '.') {
827 LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
833 * Read a set of lines, the functions performs CRLF recovery,
834 * therefore lineset must point to an additional buffer
835 * to which the data will be copied. Initial lineset->len contains
836 * the size of the buffer
838 int unixsock_read_lineset(str* lineset, str* source)
849 if (!lineset || !source) {
850 LOG(L_ERR, "unixsock_read_lineset: Invalid parameter value\n");
854 if (!lineset->s || !lineset->len) {
855 LOG(L_ERR, "unixsock_read_lineset: Buffer too small\n");
859 if (source->len < 2) {
860 LOG(L_ERR, "unixsock_read_lineset: Not enough input "
861 "data (malformed message ?)\n");
867 for(i = 0; i < source->len; i++) {
868 if (source->s[i] == '\r') {
875 if (source->s[i] == '.') {
877 } else if (source->s[i] == '\n') {
878 if (len + 2 > lineset->len) goto buf_err;
879 lineset->s[len++] = '\r';
880 lineset->s[len++] = '\n';
883 if (len + 1 > lineset->len) goto buf_err;
884 lineset->s[len++] = source->s[i];
889 if (source->s[i] == '\n') {
892 source->len -= i + 1;
895 if (len + 2 > lineset->len) goto buf_err;
896 lineset->s[len++] = '.';
897 lineset->s[len++] = source->s[i];
903 if (source->s[i] == '\n') {
904 if (len + 2 > lineset->len) goto buf_err;
905 lineset->s[len++] = '\r';
906 lineset->s[len++] = '\n';
909 if (len + 1 > lineset->len) goto buf_err;
910 lineset->s[len++] = source->s[i];
915 if (source->s[i] == '.') {
918 if (len + 1 > lineset->len) goto buf_err;
919 lineset->s[len++] = source->s[i];
926 LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
930 LOG(L_ERR, "unixsock_read_lineset: Buffer too small\n");
936 * Reset the reply buffer -- start to write
939 void unixsock_reply_reset(void)
941 reply_pos.s = reply_buf;
942 reply_pos.len = UNIXSOCK_BUF_SIZE;
947 * Add ASCIIZ to the reply buffer
949 int unixsock_reply_asciiz(char* str)
954 LOG(L_ERR, "unixsock_reply_asciiz: Invalid parameter value\n");
960 if (reply_pos.len < len) {
961 LOG(L_ERR, "unixsock_reply_asciiz: Buffer too small\n");
965 memcpy(reply_pos.s, str, len);
967 reply_pos.len -= len;
973 * Add a string represented by str structure
974 * to the reply buffer
976 int unixsock_reply_str(str* s)
979 LOG(L_ERR, "unixsock_reply_str: Invalid parameter value\n");
983 if (reply_pos.len < s->len) {
984 LOG(L_ERR, "unixsock_reply_str: Buffer too small\n");
988 memcpy(reply_pos.s, s->s, s->len);
989 reply_pos.s += s->len;
990 reply_pos.len -= s->len;
996 * Printf-like reply function
998 int unixsock_reply_printf(char* fmt, ...)
1004 LOG(L_ERR, "unixsock_reply_printf: Invalid parameter value\n");
1009 ret = vsnprintf(reply_pos.s, reply_pos.len, fmt, ap);
1010 if ((ret < 0) || (ret >= reply_pos.len)) {
1011 LOG(L_ERR, "unixsock_reply_printf: Buffer too small\n");
1018 reply_pos.len -= ret;
1024 * Return the address of the sender
1026 struct sockaddr_un* unixsock_sender_addr(void)