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