Browse code

Did not commit in the previous run...

Jan Janak authored on 02/03/2004 16:07:14
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,554 @@
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
+
30
+#include <unistd.h>
31
+#include <errno.h>
32
+#include <string.h>
33
+#include <sys/types.h>
34
+#include <sys/socket.h>
35
+#include <sys/stat.h>
36
+#include <stdarg.h>
37
+#include "ut.h"
38
+#include "globals.h"
39
+#include "trim.h"
40
+#include "pt.h"
41
+#include "sr_module.h"
42
+#include "mem/mem.h"
43
+#include "fifo_server.h" /* CMD_SEPARATOR */
44
+#include "unixsock_server.h"
45
+
46
+#define UNIXSOCK_BUF_SIZE BUF_SIZE
47
+
48
+char* unixsock_name = 0;
49
+int unixsock_children = 1;
50
+
51
+static int sock;
52
+static struct unixsock_cmd* cmd_list;
53
+static char reply_buf[UNIXSOCK_BUF_SIZE];
54
+static str reply_pos;
55
+static struct sockaddr_un reply_addr;
56
+
57
+#define CMD_NOT_FOUND "500 Command not found"
58
+#define CMD_NOT_FOUND_LEN (sizeof(CMD_NOT_FOUND) - 1)
59
+
60
+#define FLINE_ERR "400 First line malformed"
61
+#define FLINE_ERR_LEN (sizeof(FLINE_ERR) - 1)
62
+
63
+
64
+/*
65
+ * Create and bind local socket
66
+ */
67
+static int create_unix_socket(char* name)
68
+{
69
+	struct sockaddr_un addr;
70
+	int len;
71
+
72
+	if (name == 0) {
73
+		DBG("create_unix_socket: No unix domain socket"
74
+		    " will be opened\n");
75
+		return 1;
76
+	}
77
+
78
+	len = strlen(name);
79
+	if (len == 0) {
80
+		DBG("create_unix_socket: Unix domain socket server disabled\n");
81
+		return 1;
82
+	} else if (len > 107) {
83
+		LOG(L_ERR, "create_unix_socket: Socket name too long\n");
84
+		return -1;
85
+	}
86
+
87
+	DBG("create_unix_socket: Initializing Unix domain socket server\n");
88
+
89
+	if (unlink(name) == -1) {
90
+		if (errno != ENOENT) {
91
+			LOG(L_ERR, "create_unix_socket: Error while unlinking "
92
+			    "old socket (%s): %s\n", name, strerror(errno));
93
+			return -1;
94
+		}
95
+	}
96
+
97
+	sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
98
+	if (sock == -1) {
99
+		LOG(L_ERR, "create_unix_socket: Cannot create socket: %s\n", 
100
+		    strerror(errno));
101
+		return -1;
102
+	}
103
+
104
+	memset(&addr, 0, sizeof(addr));
105
+	addr.sun_family = PF_LOCAL;
106
+	memcpy(addr.sun_path, name, len);
107
+
108
+	if (bind(sock, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
109
+		LOG(L_ERR, "create_unix_socket: bind: %s\n", strerror(errno));
110
+		close(sock);
111
+		return -1;
112
+	}
113
+
114
+	return 0;
115
+}
116
+
117
+
118
+static struct unixsock_cmd* lookup_cmd(str* cmd)
119
+{
120
+	struct unixsock_cmd* c;
121
+
122
+	for(c = cmd_list; c; c = c->next) {
123
+		if ((cmd->len == c->name.len) &&
124
+		    (strncasecmp(c->name.s, cmd->s, cmd->len) == 0)) {
125
+			return c;
126
+		}
127
+	}
128
+	return 0;
129
+}
130
+
131
+
132
+static int parse_cmd(str* res, str* buffer)
133
+{
134
+	char* cmd_end;
135
+
136
+	if (!res || !buffer) {
137
+		LOG(L_ERR, "parse_cmd: Invalid parameter value\n");
138
+		return -1;
139
+	}
140
+
141
+	if (buffer->len < 3) {
142
+		LOG(L_ERR, "parse_cmd: Message too short\n");
143
+		return -1;
144
+	}
145
+
146
+	if (buffer->s[0] != CMD_SEPARATOR) {
147
+		LOG(L_ERR, "parse_cmd: Command must start with %c\n", 
148
+		    CMD_SEPARATOR);
149
+		return -1;
150
+	}
151
+	
152
+	cmd_end = q_memchr(buffer->s + 1, CMD_SEPARATOR, buffer->len - 1);
153
+	if (!cmd_end) {
154
+		LOG(L_ERR, "parse_cmd: Closing '%c' missing\n", CMD_SEPARATOR);
155
+		return -1;
156
+	}
157
+
158
+	res->s = buffer->s + 1;
159
+	res->len = cmd_end - res->s;
160
+	return 0;
161
+} 
162
+
163
+
164
+static void skip_line(str* buffer)
165
+{
166
+	if (!buffer) return;
167
+
168
+	     /* Find \n */
169
+	while (buffer->len && (buffer->s[0] != '\n')) {
170
+		buffer->s++;
171
+		buffer->len--;
172
+	}
173
+
174
+	if (buffer->len) {
175
+		buffer->s++;
176
+		buffer->len--;
177
+	}
178
+
179
+	     /* Skip CR following LF */
180
+	while (buffer->len && (buffer->s[0] == '\r')) {
181
+		buffer->s++;
182
+		buffer->len--;
183
+	}
184
+}
185
+
186
+
187
+static void unix_server_loop(void)
188
+{
189
+	int addr_len, ret;
190
+	str cmd, buffer;
191
+	static char buf[UNIXSOCK_BUF_SIZE];
192
+	struct unixsock_cmd* c;
193
+
194
+	buffer.s = buf;
195
+	buffer.len = 0;
196
+	
197
+	reply_pos.s = reply_buf;
198
+	reply_pos.len = UNIXSOCK_BUF_SIZE;
199
+
200
+	while(1) {
201
+		addr_len = sizeof(reply_addr);
202
+		ret = recvfrom(sock, buffer.s, UNIXSOCK_BUF_SIZE, 0, 
203
+			       (struct sockaddr*)&reply_addr, &addr_len);
204
+		if (ret == -1) {
205
+			LOG(L_ERR, "unix_server_loop: recvfrom: (%d) %s\n", 
206
+			    errno, strerror(errno));
207
+			if ((errno == EINTR) || 
208
+			    (errno == EAGAIN) || 
209
+			    (errno == EWOULDBLOCK) || 
210
+			    (errno == ECONNREFUSED)) {
211
+				DBG("unix_server_loop: Got %d (%s), going on\n",
212
+				    errno, strerror(errno));
213
+				continue;
214
+			}
215
+		}
216
+
217
+		buffer.len = ret;
218
+
219
+		if (parse_cmd(&cmd, &buffer) < 0) {
220
+			unixsock_add_to_reply(FLINE_ERR, FLINE_ERR_LEN);
221
+			unixsock_send_reply();
222
+			continue;
223
+		}
224
+
225
+		buffer.s = cmd.s + cmd.len + 1;
226
+		buffer.len -= cmd.len + 1 + 1;
227
+		skip_line(&buffer); /* Skip the reply filename */
228
+
229
+		c = lookup_cmd(&cmd);
230
+		if (c == 0) {
231
+			LOG(L_ERR, "unix_server_loop: Could not find "
232
+			    "command '%.*s'\n", cmd.len, ZSW(cmd.s));
233
+			unixsock_add_to_reply(CMD_NOT_FOUND, CMD_NOT_FOUND_LEN);
234
+			unixsock_send_reply();
235
+			continue;
236
+		}
237
+
238
+		ret = c->f(&buffer);
239
+		if (ret < 0) {
240
+			LOG(L_ERR, "unix_server_loop: Command '%.*s' failed with "
241
+			    "return value %d\n", cmd.len, ZSW(cmd.s), ret);
242
+			     /* Note that we do not send reply here, the 
243
+			      * function is supposed to do so, it knows the 
244
+			      * reason of the failure better than us
245
+			      */
246
+		}
247
+	}
248
+}
249
+
250
+
251
+/*
252
+ * Initialize Unix domain socket server
253
+ */
254
+int init_unixsock_server(void)
255
+{
256
+	int ret, i;
257
+	pid_t pid;
258
+	
259
+	ret = create_unix_socket(unixsock_name);
260
+	if (ret < 0) {
261
+		LOG(L_ERR, "init_unixsock_server: Error while creating "
262
+		    "local socket\n");
263
+		return -1;
264
+	} else if (ret > 0) {
265
+		return 1;
266
+	}
267
+
268
+	for(i = 0; i < unixsock_children; i++) {
269
+		process_no++;
270
+		pid = fork();
271
+		if (pid < 0) {
272
+			LOG(L_ERR, "init_unixsock_server: Unable to fork: %s\n",
273
+			    strerror(errno));
274
+			close(sock);
275
+			return -1;
276
+		} else if (pid == 0) { /* child */
277
+			if (init_child(PROC_UNIXSOCK) < 0) {
278
+				LOG(L_ERR, "init_unixsock_server: Error in "
279
+				    "init_child\n");
280
+				close(sock);
281
+				return -1;
282
+			}
283
+
284
+			unix_server_loop(); /* Never returns */
285
+		}
286
+
287
+		     /* Parent */
288
+		pt[process_no].pid = pid;
289
+		strncpy(pt[process_no].desc, "unix domain socket server", 
290
+			MAX_PT_DESC);
291
+	}
292
+	return 1;
293
+}
294
+
295
+
296
+/*
297
+ * Clean up
298
+ */
299
+void close_unixsock_server(void)
300
+{
301
+	struct unixsock_cmd* c;
302
+	close(sock);
303
+
304
+	while(cmd_list) {
305
+		c = cmd_list;
306
+		cmd_list = cmd_list->next;
307
+		pkg_free(c);
308
+	}
309
+}
310
+
311
+
312
+/*
313
+ * Register a new command
314
+ */
315
+int unixsock_register_cmd(str* cmd, unixsock_f* f)
316
+{
317
+	struct unixsock_cmd* new_cmd;
318
+
319
+	if (lookup_cmd(cmd)) {
320
+		LOG(L_ERR, "unixsock_register_cmd: Function already exists\n");
321
+		return -1;
322
+	}
323
+
324
+	new_cmd = pkg_malloc(sizeof(struct unixsock_cmd));
325
+	if (new_cmd == 0) {
326
+		LOG(L_ERR, "register_unixsock_cmd: Out of mem\n");
327
+		return -1;
328
+	}
329
+
330
+	new_cmd->name = *cmd;
331
+	new_cmd->f = f;
332
+
333
+	new_cmd->next = cmd_list;
334
+	cmd_list = new_cmd;
335
+	
336
+	DBG("unixsock_register_cmd: New command (%.*s) registered\n", 
337
+	    cmd->len, ZSW(cmd->s));
338
+	return 1;
339
+}
340
+
341
+
342
+int unixsock_add_to_reply(const char* buf, size_t len)
343
+{
344
+	if (reply_pos.len < len) {
345
+		LOG(L_ERR, "unixsock_add_to_reply: Buffer too small\n");
346
+		return -1;
347
+	}
348
+
349
+	memcpy(reply_pos.s, buf, len);
350
+	reply_pos.s += len;
351
+	reply_pos.len -= len;
352
+	return 0;
353
+}
354
+
355
+
356
+/*
357
+ * Send a reply
358
+ */
359
+ssize_t unixsock_send_reply(void)
360
+{
361
+	int ret;
362
+
363
+	ret = sendto(sock, reply_buf, reply_pos.s - reply_buf, MSG_DONTWAIT, 
364
+		     (struct sockaddr*)&reply_addr, SUN_LEN(&reply_addr));
365
+
366
+	if (ret == -1) {
367
+		LOG(L_ERR, "unixsock_send_reply: sendto: %s\n", 
368
+		    strerror(errno));
369
+	}
370
+
371
+	return ret;
372
+}
373
+
374
+
375
+/*
376
+ * Read a line, the result will be stored in line
377
+ * parameter, the data is not copied, it's just
378
+ * a pointer to an existing buffer
379
+ */
380
+int unixsock_read_line(str* line, str* source)
381
+{
382
+	if (!line || !source) {
383
+		LOG(L_ERR, "unixsock_read_line: Invalid parameter value\n");
384
+		return -1;
385
+	}
386
+
387
+	*line = *source;
388
+	skip_line(source);
389
+	line->len = source->s - line->s;
390
+	if (line->len) {
391
+		trim_trailing(line);
392
+		return 0;
393
+	} else {
394
+		return 1;
395
+	}
396
+}
397
+
398
+
399
+/*
400
+ * Read body until the closing .CRLF, no CRLF recovery
401
+ * is done so no additional buffer is necessary, body will
402
+ * point to an existing buffer
403
+ */
404
+int unixsock_read_body(str* body, str* source)
405
+{
406
+	int i, state, last_dot;
407
+
408
+	enum states {
409
+		ST_BEGIN,
410
+		ST_CRLF,
411
+		ST_DATA,
412
+		ST_NEWLINE
413
+	};
414
+
415
+	if (!body || !source) {
416
+		LOG(L_ERR, "unixsock_read_body: Invalid parameter value\n");
417
+		return -1;
418
+	}
419
+
420
+	if (source->len < 2) {
421
+		LOG(L_ERR, "unixsock_read_body: Not enough input data "
422
+		    "(malformed message ?)\n");
423
+		return -1;
424
+	}
425
+
426
+	state = ST_BEGIN;
427
+	body->s = source->s;
428
+	last_dot = 0;
429
+	for(i = 0; i < source->len; i++) {
430
+		switch(state) {
431
+		case ST_BEGIN:
432
+			if (source->s[i] == '.') {
433
+				last_dot = i;
434
+				state = ST_CRLF;
435
+			} else if (source->s[i] == '\n') {
436
+				state = ST_NEWLINE;
437
+			} else {
438
+				state = ST_DATA;
439
+			}
440
+			break;
441
+			
442
+		case ST_CRLF:
443
+			if (source->s[i] == '\n') {
444
+				body->len = last_dot;
445
+				return 0;
446
+			} else if (source->s[i] != '\r') {
447
+				state = ST_DATA;
448
+			}
449
+			break;
450
+
451
+		case ST_DATA:
452
+			if (source->s[i] == '\n') {
453
+				state = ST_NEWLINE;
454
+			}
455
+			break;
456
+
457
+		case ST_NEWLINE:
458
+			if (source->s[i] == '.') {
459
+				last_dot = i;
460
+				state = ST_CRLF;
461
+			}
462
+			break;
463
+		}
464
+	}
465
+
466
+	LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
467
+	return -1;
468
+}
469
+
470
+
471
+/*
472
+ * Read a set of lines, the functions performs CRLF recovery,
473
+ * therefore lineset must point to an additional buffer
474
+ * to which the data will be copied. Initial lineset->len contains
475
+ * the size of the buffer
476
+ */
477
+int unixsock_read_lineset(str* lineset, str* source)
478
+{
479
+	int i, state, len;
480
+
481
+	enum states {
482
+		ST_BEGIN,
483
+		ST_CRLF,
484
+		ST_DATA,
485
+		ST_NEWLINE
486
+	};
487
+
488
+	if (!lineset || !source) {
489
+		LOG(L_ERR, "unixsock_read_lineset: Invalid parameter value\n");
490
+		return -1;
491
+	}
492
+
493
+	if (source->len < 2) {
494
+		LOG(L_ERR, "unixsock_read_lineset: Not enough input "
495
+		    "data (malformed message ?)\n");
496
+		return -1;
497
+	}                 
498
+
499
+	state = ST_BEGIN;
500
+	len = 0;
501
+	for(i = 0; i < source->len; i++) {
502
+		if (source->s[i] == '\r') {
503
+			     /* Filter out CR */
504
+			continue;
505
+		}
506
+
507
+		switch(state) {
508
+		case ST_BEGIN:
509
+			if (source->s[i] == '.') {
510
+				state = ST_CRLF;
511
+			} else if (source->s[i] == '\n') {
512
+				lineset->s[len++] = '\r';
513
+				lineset->s[len++] = '\n';
514
+				state = ST_NEWLINE;
515
+			} else {
516
+				lineset->s[len++] = source->s[i];
517
+			}
518
+			break;
519
+			
520
+		case ST_CRLF:
521
+			if (source->s[i] == '\n') {
522
+				lineset->len = len;
523
+				return 0;
524
+			} else {
525
+				lineset->s[len++] = '.';
526
+				lineset->s[len++] = source->s[i];
527
+				state = ST_DATA;
528
+			}
529
+			break;
530
+
531
+		case ST_DATA:
532
+			if (source->s[i] == '\n') {
533
+				lineset->s[len++] = '\r';
534
+				lineset->s[len++] = '\n';
535
+				state = ST_NEWLINE;
536
+			} else {
537
+				lineset->s[len++] = source->s[i];
538
+			}
539
+			break;
540
+
541
+		case ST_NEWLINE:
542
+			if (source->s[i] == '.') {
543
+				state = ST_CRLF;
544
+			} else {
545
+				lineset->s[len++] = source->s[i];
546
+				state = ST_DATA;
547
+			}
548
+			break;
549
+		}
550
+	}
551
+
552
+	LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
553
+	return -1;
554
+}
0 555
new file mode 100644
... ...
@@ -0,0 +1,103 @@
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
+
30
+#ifndef _UNIXSOCK_SERVER_H
31
+#define _UNIXSOCK_SERVER_H
32
+
33
+
34
+#include <sys/un.h>
35
+#include "str.h"
36
+
37
+
38
+typedef int (unixsock_f)(str* msg);
39
+
40
+
41
+struct unixsock_cmd {
42
+	str name;                   /* The name of the function */
43
+	unixsock_f* f;              /* Function to be called */
44
+	struct unixsock_cmd* next;  /* Next element in the linked list */
45
+};
46
+
47
+
48
+/*
49
+ * Initialize Unix domain socket server
50
+ */
51
+int init_unixsock_server(void);
52
+
53
+
54
+/*
55
+ * Clean up
56
+ */
57
+void close_unixsock_server(void);
58
+
59
+
60
+/*
61
+ * Register a new command
62
+ */
63
+int unixsock_register_cmd(str* name, unixsock_f* f);
64
+
65
+
66
+/*
67
+ * add a text to the reply
68
+ */
69
+int unixsock_add_to_reply(const char* buf, size_t len);
70
+
71
+
72
+/*
73
+ * Send the reply
74
+ */
75
+ssize_t unixsock_send_reply(void);
76
+
77
+
78
+/*
79
+ * Read a line, the result will be stored in line
80
+ * parameter, the data is not copied, it's just
81
+ * a pointer to an existing buffer
82
+ */
83
+int unixsock_read_line(str* line, str* source);
84
+
85
+
86
+/*
87
+ * Read body until the closing .CRLF, no CRLF recovery
88
+ * is done so no additional buffer is necessary, body will
89
+ * point to an existing buffer
90
+ */
91
+int unixsock_read_body(str* body, str* source);
92
+
93
+
94
+/*
95
+ * Read a set of lines, the functions performs CRLF recovery,
96
+ * therefore lineset must point to an additional buffer
97
+ * to which the data will be copied. Initial lineset->len contains
98
+ * the size of the buffer
99
+ */
100
+int unixsock_read_lineset(str* lineset, str* source);
101
+
102
+
103
+#endif /* _UNIXSOCK_SERVER_H */