- Modules can properly register processes in SER process table
[sip-router] / unixsock_server.c
1 /*
2  * $Id$
3  *
4  * UNIX Domain Socket Server
5  *
6  * Copyright (C) 2001-2004 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
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
14  *
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:
18  *    info@iptel.org
19  *
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.
24  *
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
28  */
29 /* History:
30  *              created by janakj
31  *  2004-03-03  added tcp init code (andrei)
32  *  2004-04-29  added chmod(sock_perm) & chown(sock_user,sock_group)  (andrei)
33  */
34
35 #include <unistd.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <time.h>
44 #include <fcntl.h>
45 #include "config.h"
46 #include "ut.h"
47 #include "globals.h"
48 #include "trim.h"
49 #include "pt.h"
50 #include "sr_module.h"
51 #include "mem/mem.h"
52 #include "fifo_server.h" /* CMD_SEPARATOR */
53 #include "unixsock_server.h"
54 #include "tsend.h"
55
56
57 /* AF_LOCAL is not defined on solaris */
58 #if !defined(AF_LOCAL)
59 #define AF_LOCAL AF_UNIX
60 #endif
61 #if !defined(PF_LOCAL)
62 #define PF_LOCAL PF_UNIX
63 #endif
64
65
66 /* solaris doesn't have SUN_LEN */
67 #ifndef SUN_LEN
68 #define SUN_LEN(sa)      ( strlen((sa)->sun_path) + \
69                                          (size_t)(((struct sockaddr_un*)0)->sun_path) )
70 #endif
71
72
73 #define UNIXSOCK_BUF_SIZE BUF_SIZE
74
75 char* unixsock_name = 0;
76 int unixsock_children = 1;
77 int unixsock_tx_timeout = 2000; /* Timeout for sending replies in milliseconds */
78
79
80 static int rx_sock, tx_sock;
81 static struct unixsock_cmd* cmd_list = 0;
82 static char reply_buf[UNIXSOCK_BUF_SIZE];
83 static str reply_pos;
84 static struct sockaddr_un reply_addr;
85 static unsigned int reply_addr_len;
86
87 static time_t up_since;
88 static char up_since_ctime[MAX_CTIME_LEN];
89
90
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 */
99
100
101 /* 
102  * Diagnostic and hello-world command 
103  */
104 static int print_cmd(str* msg)
105 {
106         str line;
107         int ret;
108
109         ret = 0;
110
111         if (unixsock_read_line(&line, msg) < 0) {
112                 unixsock_reply_asciiz("500 Error while reading text\n");
113                 ret = -1;
114                 goto end;
115         }
116
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");
120                 ret = -1;
121         }
122
123  end:
124         if (unixsock_reply_send() < 0) ret = -1;
125         return ret;
126 }
127
128
129 /*
130  * Print the version of the server
131  */
132 static int version_cmd(str* msg)
133 {
134         int ret;
135
136         ret = 0;
137         if (unixsock_reply_asciiz("200 OK\n" SERVER_HDR CRLF) < 0) ret = -1;
138         if (unixsock_reply_send() < 0) ret = -1;
139         return ret;
140 }
141
142
143 static int uptime_cmd(str* msg)
144 {
145         time_t now;
146         int ret;
147
148         time(&now);
149         ret = 0;
150         
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");
155                 ret = -1;
156         }
157         
158         if (unixsock_reply_send() < 0) {
159                 ret = -1;
160         }
161         
162         return ret;
163 }
164
165
166 static int which_cmd(str* msg)
167 {
168         struct unixsock_cmd* c;
169         int ret;
170
171         ret = 0;
172         unixsock_reply_asciiz("200 OK\n");
173
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");
178                         ret = -1;
179                         break;
180                 }
181         }
182         
183         if (unixsock_reply_send() < 0) {
184                 ret = -1;
185         }
186         return ret;
187 }
188
189
190 static int ps_cmd(str* msg)
191 {
192         int p, ret;
193
194         ret = 0;
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");
200                         ret = -1;
201                         break;
202                 }
203         }
204         
205         if (unixsock_reply_send() < 0) {
206                 ret = -1;
207         }
208         return ret;
209 }
210
211
212 static int pwd_cmd(str* msg)
213 {
214         char *cwd_buf;
215         int max_len, ret;
216
217         max_len = pathmax();
218         cwd_buf = pkg_malloc(max_len);
219         ret = 0;
220         if (!cwd_buf) {
221                 LOG(L_ERR, "pwd_cmd: No memory left\n");
222                 unixsock_reply_asciiz("500 No Memory Left\n");
223                 ret = -1;
224         }
225
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");
230                         ret = -1;
231                 }
232         } else {
233                 unixsock_reply_asciiz("500 getcwd Failed\n");
234                 ret = -1;
235         }
236
237         pkg_free(cwd_buf);
238         if (unixsock_reply_send() < 0) {
239                 ret = -1;
240         }
241         return ret;
242 }
243
244
245 static int arg_cmd(str* msg)
246 {
247         int p, ret;
248
249         ret = 0;
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");
255                         ret = -1;
256                         break;
257                 }
258         }
259                         
260         if (unixsock_reply_send() < 0) {
261                 ret = -1;
262         }
263         return ret;
264 }
265
266
267 static int kill_cmd(str* msg)
268 {
269         unixsock_reply_asciiz("200 Killing now\n");
270         unixsock_reply_send();
271         kill(0, SIGTERM);
272         return 0;
273 }
274
275
276 static int register_core_commands(void)
277 {
278         if (unixsock_register_cmd(PRINT_CMD, print_cmd) < 0) {
279                 return -1;
280         }
281
282         if (unixsock_register_cmd(VERSION_CMD, version_cmd) < 0) {
283                 return -1;
284         }
285
286         if (unixsock_register_cmd(UPTIME_CMD, uptime_cmd) < 0) {
287                 return -1;
288         }
289
290         if (unixsock_register_cmd(WHICH_CMD, which_cmd) < 0) {
291                 return -1;
292         }
293
294         if (unixsock_register_cmd(PS_CMD, ps_cmd) < 0) {
295                 return -1;
296         }
297
298         if (unixsock_register_cmd(PWD_CMD, pwd_cmd) < 0) {
299                 return -1;
300         }
301
302         if (unixsock_register_cmd(ARG_CMD, arg_cmd) < 0) {
303                 return -1;
304         }
305
306         if (unixsock_register_cmd(KILL_CMD, kill_cmd) < 0) {
307                 return -1;
308         }
309         return 0;
310 }
311
312
313 /*
314  * Create and bind local socket
315  */
316 int init_unixsock_socket(void)
317 {
318         struct sockaddr_un addr;
319         int len, flags;
320
321         if (unixsock_name == 0) {
322                 DBG("init_unixsock_socket: No unix domain socket"
323                     " will be opened\n");
324                 return 1;
325         }
326
327         len = strlen(unixsock_name);
328         if (len == 0) {
329                 DBG("init_unixsock_socket: Unix domain socket server disabled\n");
330                 return 1;
331         } else if (len > 107) {
332                 LOG(L_ERR, "ERROR: init_unixsock_socket: Socket name too long\n");
333                 return -1;
334         }
335
336         DBG("init_unixsock_socket: Initializing Unix domain socket server @ %s\n", 
337             unixsock_name);
338
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));
343                         return -1;
344                 }
345         }
346
347         rx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
348         if (rx_sock == -1) {
349                 LOG(L_ERR, "ERROR: init_unixsock_socket: Cannot create RX "
350                                 "socket: %s\n", strerror(errno));
351                 return -1;
352         }
353
354         memset(&addr, 0, sizeof(addr));
355         addr.sun_family = PF_LOCAL;
356         memcpy(addr.sun_path, unixsock_name, len);
357
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));
360                 goto err_rx;
361         }
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);
368                         goto err_rx;
369                 }
370         }
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);
377                         goto err_rx;
378                 }
379         }
380
381         tx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
382         if (tx_sock == -1) {
383                 LOG(L_ERR, "ERROR: init_unixsock_socket: Cannot create TX socket:"
384                                 " %s\n", strerror(errno));
385                 goto err_rx;
386         }
387
388              /* Turn non-blocking mode on */
389         flags = fcntl(tx_sock, F_GETFL);
390         if (flags == -1){
391                 LOG(L_ERR, "ERROR: init_unixsock_socket: fcntl failed: %s\n",
392                     strerror(errno));
393                 goto err_both;
394         }
395                 
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));
399                 goto err_both;
400         }
401         
402         return 1;
403  err_both:
404         close(tx_sock);
405  err_rx:
406         close(rx_sock);
407         return -1;
408 }
409
410
411 static struct unixsock_cmd* lookup_cmd(str* cmd)
412 {
413         struct unixsock_cmd* c;
414
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)) {
418                         return c;
419                 }
420         }
421         return 0;
422 }
423
424
425 static int parse_cmd(str* res, str* buffer)
426 {
427         char* cmd_end;
428
429         if (!res || !buffer) {
430                 LOG(L_ERR, "parse_cmd: Invalid parameter value\n");
431                 return -1;
432         }
433
434         if (buffer->len < 3) {
435                 LOG(L_ERR, "parse_cmd: Message too short\n");
436                 return -1;
437         }
438
439         if (buffer->s[0] != CMD_SEPARATOR) {
440                 LOG(L_ERR, "parse_cmd: Command must start with %c\n", 
441                     CMD_SEPARATOR);
442                 return -1;
443         }
444         
445         cmd_end = q_memchr(buffer->s + 1, CMD_SEPARATOR, buffer->len - 1);
446         if (!cmd_end) {
447                 LOG(L_ERR, "parse_cmd: Closing '%c' missing\n", CMD_SEPARATOR);
448                 return -1;
449         }
450
451         res->s = buffer->s + 1;
452         res->len = cmd_end - res->s;
453         return 0;
454
455
456
457 static void skip_line(str* buffer)
458 {
459         if (!buffer) return;
460
461              /* Find \n */
462         while (buffer->len && (buffer->s[0] != '\n')) {
463                 buffer->s++;
464                 buffer->len--;
465         }
466
467         if (buffer->len) {
468                 buffer->s++;
469                 buffer->len--;
470         }
471
472              /* Skip CR following LF */
473         while (buffer->len && (buffer->s[0] == '\r')) {
474                 buffer->s++;
475                 buffer->len--;
476         }
477 }
478
479
480 static void unix_server_loop(void)
481 {
482         int ret;
483         str cmd, buffer;
484         static char buf[UNIXSOCK_BUF_SIZE];
485         struct unixsock_cmd* c;
486
487         
488         while(1) {
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);
492                 if (ret == -1) {
493                         LOG(L_ERR, "unix_server_loop: recvfrom: (%d) %s\n", 
494                             errno, strerror(errno));
495                         if ((errno == EINTR) || 
496                             (errno == EAGAIN) || 
497                             (errno == EWOULDBLOCK) || 
498                             (errno == ECONNREFUSED)) {
499                                 DBG("unix_server_loop: Got %d (%s), going on\n",
500                                     errno, strerror(errno));
501                                 continue;
502                         }
503                         LOG(L_CRIT, "BUG: unix_server_loop: unexpected recvfrom error\n");
504                         continue;
505                 }
506
507                 buffer.s = buf;
508                 buffer.len = ret;
509                 unixsock_reply_reset();
510
511                 if (parse_cmd(&cmd, &buffer) < 0) {
512                         unixsock_reply_asciiz("400 First line malformed\n");
513                         unixsock_reply_send();
514                         continue;
515                 }
516
517                 buffer.s = cmd.s + cmd.len + 1;
518                 buffer.len -= cmd.len + 1 + 1;
519                 skip_line(&buffer); /* Skip the reply filename */
520
521                 c = lookup_cmd(&cmd);
522                 if (c == 0) {
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();
527                         continue;
528                 }
529
530                 ret = c->f(&buffer);
531                 if (ret < 0) {
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
537                               */
538                 }
539         }
540 }
541
542
543 static int get_uptime(void)
544 {
545         char* t;
546
547         time(&up_since);
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));
551                 return -1;
552         }
553         memcpy(up_since_ctime, t, strlen(t) + 1);
554         return 0;
555 }
556
557
558 /*
559  * Spawn listeners
560  */
561 int init_unixsock_children(void)
562 {
563         int i;
564         pid_t pid;
565 #ifdef USE_TCP
566         int sockfd[2];
567 #endif
568
569         if (!unixsock_name || *unixsock_name == '\0') {
570                 return 1;
571         }
572
573         if (get_uptime() < 0) {
574                 return -1;
575         }
576         
577         if (register_core_commands() < 0) {
578                 close(rx_sock);
579                 close(tx_sock);
580                 return -1;
581         }
582
583         for(i = 0; i < unixsock_children; i++) {
584                 process_no++;
585 #ifdef USE_TCP
586                 if(!tcp_disable){
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));
590                                 return -1;
591                         }
592                 }
593 #endif
594                 pid = fork();
595                 if (pid < 0) {
596                         LOG(L_ERR, "init_unixsock_server: Unable to fork: %s\n",
597                             strerror(errno));
598                         close(rx_sock);
599                         close(tx_sock);
600                         return -1;
601                 } else if (pid == 0) { /* child */
602 #ifdef USE_TCP
603                         if (!tcp_disable){
604                                 close(sockfd[0]);
605                                 unix_tcp_sock=sockfd[1];
606                         }
607 #endif
608                         /* record pid twice to avoid the child using it, before
609                          * parent gets a chance to set it*/
610                         pt[process_no].pid=getpid();
611                         if (init_child(PROC_UNIXSOCK) < 0) {
612                                 LOG(L_ERR, "init_unixsock_server: Error in "
613                                     "init_child\n");
614                                 close(rx_sock);
615                                 close(tx_sock);
616                                 return -1;
617                         }
618
619                         unix_server_loop(); /* Never returns */
620                 }
621
622                      /* Parent */
623                 pt[process_no].pid = pid;
624                 strncpy(pt[process_no].desc, "unix domain socket server", 
625                         MAX_PT_DESC);
626 #ifdef USE_TCP
627                 if (!tcp_disable){
628                         close(sockfd[1]);
629                         pt[process_no].unix_sock=sockfd[0];
630                         pt[process_no].idx=-1; /* this is not a "tcp"
631                                                                           process*/
632                 }
633 #endif
634
635         }
636
637         DBG("init_unixsock_server: Unix domain socket server successfully initialized @ %s\n",
638             unixsock_name);
639         return 1;
640 }
641
642
643 /*
644  * Clean up
645  */
646 void close_unixsock_server(void)
647 {
648         struct unixsock_cmd* c;
649         close(rx_sock);
650         close(tx_sock);
651
652         while(cmd_list) {
653                 c = cmd_list;
654                 cmd_list = cmd_list->next;
655                 pkg_free(c);
656         }
657 }
658
659
660 /*
661  * Register a new command
662  */
663 int unixsock_register_cmd(char* command, unixsock_f* f)
664 {
665         str cmd;
666         struct unixsock_cmd* new_cmd;
667
668         cmd.s = command;
669         cmd.len = strlen(command);
670
671         if (lookup_cmd(&cmd)) {
672                 LOG(L_ERR, "unixsock_register_cmd: Function already exists\n");
673                 return -1;
674         }
675
676         new_cmd = pkg_malloc(sizeof(struct unixsock_cmd));
677         if (new_cmd == 0) {
678                 LOG(L_ERR, "register_unixsock_cmd: Out of mem\n");
679                 return -1;
680         }
681
682         new_cmd->name = cmd;
683         new_cmd->f = f;
684
685         new_cmd->next = cmd_list;
686         cmd_list = new_cmd;
687         
688         DBG("unixsock_register_cmd: New command (%.*s) registered\n", 
689             cmd.len, ZSW(cmd.s));
690         return 1;
691 }
692
693
694 int unixsock_add_to_reply(const char* buf, size_t len)
695 {
696         if (reply_pos.len < len) {
697                 LOG(L_ERR, "unixsock_add_to_reply: Buffer too small\n");
698                 return -1;
699         }
700
701         memcpy(reply_pos.s, buf, len);
702         reply_pos.s += len;
703         reply_pos.len -= len;
704         return 0;
705 }
706
707
708 /*
709  * Send a reply
710  */
711 ssize_t unixsock_reply_send(void)
712 {
713         return tsend_dgram(tx_sock, 
714                            reply_buf, reply_pos.s - reply_buf,
715                            (struct sockaddr*)&reply_addr, reply_addr_len, 
716                            unixsock_tx_timeout);
717 }
718
719
720 /*
721  * Send a reply
722  */
723 ssize_t unixsock_reply_sendto(struct sockaddr_un* to)
724 {
725         if (!to) {
726                 LOG(L_ERR, "unixsock_reply_sendto: Invalid parameter value\n");
727                 return -1;
728         }
729
730         return tsend_dgram(tx_sock, 
731                            reply_buf, reply_pos.s - reply_buf, 
732                            (struct sockaddr*)to, SUN_LEN(to), 
733                            unixsock_tx_timeout);
734 }
735
736
737 /*
738  * Read a line, the result will be stored in line
739  * parameter, the data is not copied, it's just
740  * a pointer to an existing buffer
741  */
742 int unixsock_read_line(str* line, str* source)
743 {
744         if (!line || !source) {
745                 LOG(L_ERR, "unixsock_read_line: Invalid parameter value\n");
746                 return -1;
747         }
748
749         *line = *source;
750         skip_line(source);
751         line->len = source->s - line->s;
752         trim_trailing(line);
753         if (line->len) {
754                 return 0;
755         } else {
756                 return 1;
757         }
758 }
759
760
761 /*
762  * Read body until the closing .CRLF, no CRLF recovery
763  * is done so no additional buffer is necessary, body will
764  * point to an existing buffer
765  */
766 int unixsock_read_body(str* body, str* source)
767 {
768         int i, state, last_dot;
769
770         enum states {
771                 ST_BEGIN,
772                 ST_CRLF,
773                 ST_DATA,
774                 ST_NEWLINE
775         };
776
777         if (!body || !source) {
778                 LOG(L_ERR, "unixsock_read_body: Invalid parameter value\n");
779                 return -1;
780         }
781
782         if (source->len < 2) {
783                 LOG(L_ERR, "unixsock_read_body: Not enough input data "
784                     "(malformed message ?)\n");
785                 return -1;
786         }
787
788         state = ST_BEGIN;
789         body->s = source->s;
790         last_dot = 0;
791         for(i = 0; i < source->len; i++) {
792                 switch(state) {
793                 case ST_BEGIN:
794                         if (source->s[i] == '.') {
795                                 last_dot = i;
796                                 state = ST_CRLF;
797                         } else if (source->s[i] == '\n') {
798                                 state = ST_NEWLINE;
799                         } else {
800                                 state = ST_DATA;
801                         }
802                         break;
803                         
804                 case ST_CRLF:
805                         if (source->s[i] == '\n') {
806                                 body->len = last_dot;
807                                 source->s += i + 1;
808                                 source->len -= i + 1;
809                                 return 0;
810                         } else if (source->s[i] != '\r') {
811                                 state = ST_DATA;
812                         }
813                         break;
814
815                 case ST_DATA:
816                         if (source->s[i] == '\n') {
817                                 state = ST_NEWLINE;
818                         }
819                         break;
820
821                 case ST_NEWLINE:
822                         if (source->s[i] == '.') {
823                                 last_dot = i;
824                                 state = ST_CRLF;
825                         }
826                         break;
827                 }
828         }
829
830         LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
831         return -1;
832 }
833
834
835 /*
836  * Read a set of lines, the functions performs CRLF recovery,
837  * therefore lineset must point to an additional buffer
838  * to which the data will be copied. Initial lineset->len contains
839  * the size of the buffer
840  */
841 int unixsock_read_lineset(str* lineset, str* source)
842 {
843         int i, state, len;
844
845         enum states {
846                 ST_BEGIN,
847                 ST_CRLF,
848                 ST_DATA,
849                 ST_NEWLINE
850         };
851
852         if (!lineset || !source) {
853                 LOG(L_ERR, "unixsock_read_lineset: Invalid parameter value\n");
854                 return -1;
855         }
856
857         if (!lineset->s || !lineset->len) {
858                 LOG(L_ERR, "unixsock_read_lineset: Buffer too small\n");
859                 return -1;
860         }
861
862         if (source->len < 2) {
863                 LOG(L_ERR, "unixsock_read_lineset: Not enough input "
864                     "data (malformed message ?)\n");
865                 return -1;
866         }                 
867
868         state = ST_BEGIN;
869         len = 0;
870         for(i = 0; i < source->len; i++) {
871                 if (source->s[i] == '\r') {
872                              /* Filter out CR */
873                         continue;
874                 }
875
876                 switch(state) {
877                 case ST_BEGIN:
878                         if (source->s[i] == '.') {
879                                 state = ST_CRLF;
880                         } else if (source->s[i] == '\n') {
881                                 if (len + 2 > lineset->len) goto buf_err;
882                                 lineset->s[len++] = '\r';
883                                 lineset->s[len++] = '\n';
884                                 state = ST_NEWLINE;
885                         } else {
886                                 if (len + 1 > lineset->len) goto buf_err;
887                                 lineset->s[len++] = source->s[i];
888                         }
889                         break;
890                         
891                 case ST_CRLF:
892                         if (source->s[i] == '\n') {
893                                 lineset->len = len;
894                                 source->s += i + 1;
895                                 source->len -= i + 1;
896                                 return 0;
897                         } else {
898                                 if (len + 2 > lineset->len) goto buf_err;
899                                 lineset->s[len++] = '.';
900                                 lineset->s[len++] = source->s[i];
901                                 state = ST_DATA;
902                         }
903                         break;
904
905                 case ST_DATA:
906                         if (source->s[i] == '\n') {
907                                 if (len + 2 > lineset->len) goto buf_err;
908                                 lineset->s[len++] = '\r';
909                                 lineset->s[len++] = '\n';
910                                 state = ST_NEWLINE;
911                         } else {
912                                 if (len + 1 > lineset->len) goto buf_err;
913                                 lineset->s[len++] = source->s[i];
914                         }
915                         break;
916
917                 case ST_NEWLINE:
918                         if (source->s[i] == '.') {
919                                 state = ST_CRLF;
920                         } else {
921                                 if (len + 1 > lineset->len) goto buf_err;
922                                 lineset->s[len++] = source->s[i];
923                                 state = ST_DATA;
924                         }
925                         break;
926                 }
927         }
928
929         LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
930         return -1;
931
932  buf_err:
933         LOG(L_ERR, "unixsock_read_lineset: Buffer too small\n");
934         return -1;
935 }
936
937
938 /*
939  * Reset the reply buffer -- start to write
940  * at the beginning
941  */
942 void unixsock_reply_reset(void)
943 {
944         reply_pos.s = reply_buf;
945         reply_pos.len = UNIXSOCK_BUF_SIZE;
946 }
947
948
949 /*
950  * Add ASCIIZ to the reply buffer
951  */
952 int unixsock_reply_asciiz(char* str)
953 {
954         int len;
955         
956         if (!str) {
957                 LOG(L_ERR, "unixsock_reply_asciiz: Invalid parameter value\n");
958                 return -1;
959         }
960
961         len = strlen(str);
962
963         if (reply_pos.len < len) {
964                 LOG(L_ERR, "unixsock_reply_asciiz: Buffer too small\n");
965                 return -1;
966         }
967
968         memcpy(reply_pos.s, str, len);
969         reply_pos.s += len;
970         reply_pos.len -= len;
971         return 0;
972 }
973
974
975 /*
976  * Add a string represented by str structure
977  * to the reply buffer
978  */
979 int unixsock_reply_str(str* s)
980 {
981         if (!s) {
982                 LOG(L_ERR, "unixsock_reply_str: Invalid parameter value\n");
983                 return -1;
984         }
985
986         if (reply_pos.len < s->len) {
987                 LOG(L_ERR, "unixsock_reply_str: Buffer too small\n");
988                 return -1;
989         }
990         
991         memcpy(reply_pos.s, s->s, s->len);
992         reply_pos.s += s->len;
993         reply_pos.len -= s->len;
994         return 0;
995 }
996
997
998 /*
999  * Printf-like reply function
1000  */
1001 int unixsock_reply_printf(char* fmt, ...)
1002 {
1003         va_list ap;
1004         int ret;
1005
1006         if (!fmt) {
1007                 LOG(L_ERR, "unixsock_reply_printf: Invalid parameter value\n");
1008                 return -1;
1009         }
1010
1011         va_start(ap, fmt);
1012         ret = vsnprintf(reply_pos.s, reply_pos.len, fmt, ap);
1013         if ((ret < 0) || (ret >= reply_pos.len)) {
1014                 LOG(L_ERR, "unixsock_reply_printf: Buffer too small\n");
1015                 va_end(ap);
1016                 return -1;
1017         }
1018
1019         va_end(ap);
1020         reply_pos.s += ret;
1021         reply_pos.len -= ret;
1022         return 0;
1023 }
1024
1025
1026 /*
1027  * Return the address of the sender
1028  */
1029 struct sockaddr_un* unixsock_sender_addr(void)
1030 {
1031         return &reply_addr;
1032 }