OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / ser / unixsock_server.c
1 /*
2  * $Id: unixsock_server.c,v 1.17 2004/12/03 19:09:31 andrei Exp $
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                         if (init_child(PROC_UNIXSOCK) < 0) {
609                                 LOG(L_ERR, "init_unixsock_server: Error in "
610                                     "init_child\n");
611                                 close(rx_sock);
612                                 close(tx_sock);
613                                 return -1;
614                         }
615
616                         unix_server_loop(); /* Never returns */
617                 }
618
619                      /* Parent */
620                 pt[process_no].pid = pid;
621                 strncpy(pt[process_no].desc, "unix domain socket server", 
622                         MAX_PT_DESC);
623 #ifdef USE_TCP
624                 if (!tcp_disable){
625                         close(sockfd[1]);
626                         pt[process_no].unix_sock=sockfd[0];
627                         pt[process_no].idx=-1; /* this is not a "tcp"
628                                                                           process*/
629                 }
630 #endif
631
632         }
633
634         DBG("init_unixsock_server: Unix domain socket server successfully initialized @ %s\n",
635             unixsock_name);
636         return 1;
637 }
638
639
640 /*
641  * Clean up
642  */
643 void close_unixsock_server(void)
644 {
645         struct unixsock_cmd* c;
646         close(rx_sock);
647         close(tx_sock);
648
649         while(cmd_list) {
650                 c = cmd_list;
651                 cmd_list = cmd_list->next;
652                 pkg_free(c);
653         }
654 }
655
656
657 /*
658  * Register a new command
659  */
660 int unixsock_register_cmd(char* command, unixsock_f* f)
661 {
662         str cmd;
663         struct unixsock_cmd* new_cmd;
664
665         cmd.s = command;
666         cmd.len = strlen(command);
667
668         if (lookup_cmd(&cmd)) {
669                 LOG(L_ERR, "unixsock_register_cmd: Function already exists\n");
670                 return -1;
671         }
672
673         new_cmd = pkg_malloc(sizeof(struct unixsock_cmd));
674         if (new_cmd == 0) {
675                 LOG(L_ERR, "register_unixsock_cmd: Out of mem\n");
676                 return -1;
677         }
678
679         new_cmd->name = cmd;
680         new_cmd->f = f;
681
682         new_cmd->next = cmd_list;
683         cmd_list = new_cmd;
684         
685         DBG("unixsock_register_cmd: New command (%.*s) registered\n", 
686             cmd.len, ZSW(cmd.s));
687         return 1;
688 }
689
690
691 int unixsock_add_to_reply(const char* buf, size_t len)
692 {
693         if (reply_pos.len < len) {
694                 LOG(L_ERR, "unixsock_add_to_reply: Buffer too small\n");
695                 return -1;
696         }
697
698         memcpy(reply_pos.s, buf, len);
699         reply_pos.s += len;
700         reply_pos.len -= len;
701         return 0;
702 }
703
704
705 /*
706  * Send a reply
707  */
708 ssize_t unixsock_reply_send(void)
709 {
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);
714 }
715
716
717 /*
718  * Send a reply
719  */
720 ssize_t unixsock_reply_sendto(struct sockaddr_un* to)
721 {
722         if (!to) {
723                 LOG(L_ERR, "unixsock_reply_sendto: Invalid parameter value\n");
724                 return -1;
725         }
726
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);
731 }
732
733
734 /*
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
738  */
739 int unixsock_read_line(str* line, str* source)
740 {
741         if (!line || !source) {
742                 LOG(L_ERR, "unixsock_read_line: Invalid parameter value\n");
743                 return -1;
744         }
745
746         *line = *source;
747         skip_line(source);
748         line->len = source->s - line->s;
749         trim_trailing(line);
750         if (line->len) {
751                 return 0;
752         } else {
753                 return 1;
754         }
755 }
756
757
758 /*
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
762  */
763 int unixsock_read_body(str* body, str* source)
764 {
765         int i, state, last_dot;
766
767         enum states {
768                 ST_BEGIN,
769                 ST_CRLF,
770                 ST_DATA,
771                 ST_NEWLINE
772         };
773
774         if (!body || !source) {
775                 LOG(L_ERR, "unixsock_read_body: Invalid parameter value\n");
776                 return -1;
777         }
778
779         if (source->len < 2) {
780                 LOG(L_ERR, "unixsock_read_body: Not enough input data "
781                     "(malformed message ?)\n");
782                 return -1;
783         }
784
785         state = ST_BEGIN;
786         body->s = source->s;
787         last_dot = 0;
788         for(i = 0; i < source->len; i++) {
789                 switch(state) {
790                 case ST_BEGIN:
791                         if (source->s[i] == '.') {
792                                 last_dot = i;
793                                 state = ST_CRLF;
794                         } else if (source->s[i] == '\n') {
795                                 state = ST_NEWLINE;
796                         } else {
797                                 state = ST_DATA;
798                         }
799                         break;
800                         
801                 case ST_CRLF:
802                         if (source->s[i] == '\n') {
803                                 body->len = last_dot;
804                                 source->s += i + 1;
805                                 source->len -= i + 1;
806                                 return 0;
807                         } else if (source->s[i] != '\r') {
808                                 state = ST_DATA;
809                         }
810                         break;
811
812                 case ST_DATA:
813                         if (source->s[i] == '\n') {
814                                 state = ST_NEWLINE;
815                         }
816                         break;
817
818                 case ST_NEWLINE:
819                         if (source->s[i] == '.') {
820                                 last_dot = i;
821                                 state = ST_CRLF;
822                         }
823                         break;
824                 }
825         }
826
827         LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
828         return -1;
829 }
830
831
832 /*
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
837  */
838 int unixsock_read_lineset(str* lineset, str* source)
839 {
840         int i, state, len;
841
842         enum states {
843                 ST_BEGIN,
844                 ST_CRLF,
845                 ST_DATA,
846                 ST_NEWLINE
847         };
848
849         if (!lineset || !source) {
850                 LOG(L_ERR, "unixsock_read_lineset: Invalid parameter value\n");
851                 return -1;
852         }
853
854         if (!lineset->s || !lineset->len) {
855                 LOG(L_ERR, "unixsock_read_lineset: Buffer too small\n");
856                 return -1;
857         }
858
859         if (source->len < 2) {
860                 LOG(L_ERR, "unixsock_read_lineset: Not enough input "
861                     "data (malformed message ?)\n");
862                 return -1;
863         }                 
864
865         state = ST_BEGIN;
866         len = 0;
867         for(i = 0; i < source->len; i++) {
868                 if (source->s[i] == '\r') {
869                              /* Filter out CR */
870                         continue;
871                 }
872
873                 switch(state) {
874                 case ST_BEGIN:
875                         if (source->s[i] == '.') {
876                                 state = ST_CRLF;
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';
881                                 state = ST_NEWLINE;
882                         } else {
883                                 if (len + 1 > lineset->len) goto buf_err;
884                                 lineset->s[len++] = source->s[i];
885                         }
886                         break;
887                         
888                 case ST_CRLF:
889                         if (source->s[i] == '\n') {
890                                 lineset->len = len;
891                                 source->s += i + 1;
892                                 source->len -= i + 1;
893                                 return 0;
894                         } else {
895                                 if (len + 2 > lineset->len) goto buf_err;
896                                 lineset->s[len++] = '.';
897                                 lineset->s[len++] = source->s[i];
898                                 state = ST_DATA;
899                         }
900                         break;
901
902                 case ST_DATA:
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';
907                                 state = ST_NEWLINE;
908                         } else {
909                                 if (len + 1 > lineset->len) goto buf_err;
910                                 lineset->s[len++] = source->s[i];
911                         }
912                         break;
913
914                 case ST_NEWLINE:
915                         if (source->s[i] == '.') {
916                                 state = ST_CRLF;
917                         } else {
918                                 if (len + 1 > lineset->len) goto buf_err;
919                                 lineset->s[len++] = source->s[i];
920                                 state = ST_DATA;
921                         }
922                         break;
923                 }
924         }
925
926         LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
927         return -1;
928
929  buf_err:
930         LOG(L_ERR, "unixsock_read_lineset: Buffer too small\n");
931         return -1;
932 }
933
934
935 /*
936  * Reset the reply buffer -- start to write
937  * at the beginning
938  */
939 void unixsock_reply_reset(void)
940 {
941         reply_pos.s = reply_buf;
942         reply_pos.len = UNIXSOCK_BUF_SIZE;
943 }
944
945
946 /*
947  * Add ASCIIZ to the reply buffer
948  */
949 int unixsock_reply_asciiz(char* str)
950 {
951         int len;
952         
953         if (!str) {
954                 LOG(L_ERR, "unixsock_reply_asciiz: Invalid parameter value\n");
955                 return -1;
956         }
957
958         len = strlen(str);
959
960         if (reply_pos.len < len) {
961                 LOG(L_ERR, "unixsock_reply_asciiz: Buffer too small\n");
962                 return -1;
963         }
964
965         memcpy(reply_pos.s, str, len);
966         reply_pos.s += len;
967         reply_pos.len -= len;
968         return 0;
969 }
970
971
972 /*
973  * Add a string represented by str structure
974  * to the reply buffer
975  */
976 int unixsock_reply_str(str* s)
977 {
978         if (!s) {
979                 LOG(L_ERR, "unixsock_reply_str: Invalid parameter value\n");
980                 return -1;
981         }
982
983         if (reply_pos.len < s->len) {
984                 LOG(L_ERR, "unixsock_reply_str: Buffer too small\n");
985                 return -1;
986         }
987         
988         memcpy(reply_pos.s, s->s, s->len);
989         reply_pos.s += s->len;
990         reply_pos.len -= s->len;
991         return 0;
992 }
993
994
995 /*
996  * Printf-like reply function
997  */
998 int unixsock_reply_printf(char* fmt, ...)
999 {
1000         va_list ap;
1001         int ret;
1002
1003         if (!fmt) {
1004                 LOG(L_ERR, "unixsock_reply_printf: Invalid parameter value\n");
1005                 return -1;
1006         }
1007
1008         va_start(ap, fmt);
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");
1012                 va_end(ap);
1013                 return -1;
1014         }
1015
1016         va_end(ap);
1017         reply_pos.s += ret;
1018         reply_pos.len -= ret;
1019         return 0;
1020 }
1021
1022
1023 /*
1024  * Return the address of the sender
1025  */
1026 struct sockaddr_un* unixsock_sender_addr(void)
1027 {
1028         return &reply_addr;
1029 }