Browse code

- unixsock module skeleton

Jan Janak authored on 06/01/2006 13:29:00
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+# $Id$
1
+#
2
+# 
3
+# WARNING: do not run this directly, it should be run by the master Makefile
4
+
5
+include ../../Makefile.defs
6
+auto_gen=
7
+NAME=unixsock.so
8
+LIBS=
9
+
10
+include ../../Makefile.modules
11
+
0 12
new file mode 100644
... ...
@@ -0,0 +1,94 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2005 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License 
23
+ * along with this program; if not, write to the Free Software 
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+#include "../../str.h"
28
+#include "../../sr_module.h"
29
+#include "../../error.h"
30
+#include "../../mem/mem.h"
31
+#include "../../parser/msg_parser.h"
32
+#include "../../ut.h"
33
+#include "../../dprint.h"
34
+#include "../../pt.h"
35
+#include "unixsock_server.h"
36
+
37
+MODULE_VERSION
38
+
39
+static int mod_init(void);
40
+static int child_init(int rank);
41
+
42
+/*
43
+ * Exported functions
44
+ */
45
+static cmd_export_t cmds[] = {
46
+	{0, 0, 0, 0, 0}
47
+};
48
+
49
+/*
50
+ * Exported parameters
51
+ */
52
+static param_export_t params[] = {
53
+	{"socket",       STR_PARAM, &unixsock_name      },
54
+	{"children",     INT_PARAM, &unixsock_children  },
55
+	{"send_timeout", INT_PARAM, &unixsock_tx_timeout},
56
+	{"socket_user",  INT_PARAM, &unixsock_user      },
57
+	{"socket_mode",  INT_PARAM, &unixsock_mode      },
58
+	{"socket_group", INT_PARAM, &unixsock_group     },
59
+	{0, 0, 0}
60
+};
61
+
62
+
63
+struct module_exports exports = {
64
+	"unixsock", 
65
+	cmds,           /* Exported commands */
66
+	0,              /* Exported RPC methods */
67
+	params,         /* Exported parameters */
68
+	mod_init,       /* module initialization function */
69
+	0,              /* response function*/
70
+	0,              /* destroy function */
71
+	0,              /* oncancel function */
72
+	child_init      /* per-child init function */
73
+};
74
+
75
+
76
+static int mod_init(void)
77
+{
78
+	if (init_unixsock_socket() < 0) return -1;
79
+	     /* Signal to the core that we will be
80
+	      * creating additional processes
81
+	      */
82
+	if (unixsock_name) process_count += unixsock_children;
83
+	return 0;
84
+}
85
+
86
+
87
+static int child_init(int rank)
88
+{
89
+	if (rank == PROC_MAIN) {
90
+		if (init_unixsock_children() < 0) return -1;
91
+	}
92
+	return 0;
93
+}
0 94
new file mode 100644
... ...
@@ -0,0 +1,376 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * UNIX Domain Socket Server
4
+ *
5
+ * Copyright (C) 2001-2004 FhG Fokus
6
+ * Copyright (C) 2005 iptelorg GmbH
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 <stdio.h>
44
+#include <time.h>
45
+#include <fcntl.h>
46
+#include "../../config.h"
47
+#include "../../ut.h"
48
+#include "../../globals.h"
49
+#include "../../trim.h"
50
+#include "../../pt.h"
51
+#include "../../sr_module.h"
52
+#include "../../mem/mem.h"
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
+char* unixsock_user = 0;
77
+char* unixsock_mode = 0;
78
+char* unixsock_group = 0;
79
+unsigned int unixsock_children = 1;
80
+unsigned int unixsock_tx_timeout = 2000; /* Timeout for sending replies in milliseconds */
81
+
82
+static int rx_sock, tx_sock;
83
+static char reply_buf[UNIXSOCK_BUF_SIZE];
84
+static str reply_pos;
85
+static struct sockaddr_un reply_addr;
86
+static unsigned int reply_addr_len;
87
+
88
+static int parse_cmd(str* cmd, str* buffer)
89
+{
90
+	return 1;
91
+}
92
+
93
+
94
+/*
95
+ * Create and bind local socket
96
+ */
97
+int init_unixsock_socket(void)
98
+{
99
+	struct sockaddr_un addr;
100
+	int len, flags;
101
+
102
+	if (unixsock_name == 0) {
103
+		DBG("No unix domain socket will be opened\n");
104
+		return 1;
105
+	}
106
+
107
+	len = strlen(unixsock_name);
108
+	if (len == 0) {
109
+		DBG("Unix domain socket server disabled\n");
110
+		return 1;
111
+	} else if (len > 107) {
112
+		ERR("Socket name too long\n");
113
+		return -1;
114
+	}
115
+
116
+	DBG("Initializing Unix domain socket server @ %s\n", 
117
+	    unixsock_name);
118
+
119
+	if (unlink(unixsock_name) == -1) {
120
+		if (errno != ENOENT) {
121
+			ERR(L_ERR, "Error while unlinking "
122
+			    "old socket (%s): %s\n", unixsock_name, strerror(errno));
123
+			return -1;
124
+		}
125
+	}
126
+
127
+	rx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
128
+	if (rx_sock == -1) {
129
+		ERR("Cannot create listening socket: %s\n", strerror(errno));
130
+		return -1;
131
+	}
132
+
133
+	memset(&addr, 0, sizeof(addr));
134
+	addr.sun_family = PF_LOCAL;
135
+	memcpy(addr.sun_path, unixsock_name, len);
136
+
137
+	if (bind(rx_sock, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
138
+		ERR("bind: %s\n", strerror(errno));
139
+		goto err_rx;
140
+	}
141
+	/* try to change permissions */
142
+	if (sock_mode){ /* sock_mode==0 doesn't make sense, nobody can read/write*/
143
+		if (chmod(unixsock_name, sock_mode)<0){
144
+			ERR("Failed to change the"
145
+			    " permissions for %s to %04o: %s[%d]\n",
146
+			    unixsock_name, sock_mode, strerror(errno), errno);
147
+			goto err_rx;
148
+		}
149
+	}
150
+	/* try to change the ownership */
151
+	if ((sock_uid!=-1) || (sock_gid!=-1)){
152
+		if (chown(unixsock_name, sock_uid, sock_gid)<0){
153
+			ERR("Failed to change the"
154
+			    " owner/group for %s  to %d.%d; %s[%d]\n",
155
+			    unixsock_name, sock_uid, sock_gid, strerror(errno), errno);
156
+			goto err_rx;
157
+		}
158
+	}
159
+
160
+	tx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
161
+	if (tx_sock == -1) {
162
+		ERR("Cannot create sending socket:"
163
+		    " %s\n", strerror(errno));
164
+		goto err_rx;
165
+	}
166
+	
167
+	     /* Turn non-blocking mode on */
168
+	flags = fcntl(tx_sock, F_GETFL);
169
+	if (flags == -1){
170
+		ERR("fcntl failed: %s\n", strerror(errno));
171
+		goto err_both;
172
+	}
173
+		
174
+	if (fcntl(tx_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
175
+		ERR("fcntl: set non-blocking failed: %s\n", strerror(errno));
176
+		goto err_both;
177
+	}
178
+	
179
+	return 1;
180
+ err_both:
181
+	close(tx_sock);
182
+ err_rx:
183
+	close(rx_sock);
184
+	return -1;
185
+}
186
+
187
+
188
+static void unix_server_loop(void)
189
+{
190
+	int ret;
191
+	str cmd, buffer;
192
+	static char buf[UNIXSOCK_BUF_SIZE];
193
+	struct unixsock_cmd* c;
194
+	
195
+	while(1) {
196
+		reply_addr_len = sizeof(reply_addr);
197
+		ret = recvfrom(rx_sock, buf, UNIXSOCK_BUF_SIZE, 0, 
198
+			       (struct sockaddr*)&reply_addr, &reply_addr_len);
199
+		if (ret == -1) {
200
+			ERR("recvfrom: (%d) %s\n", errno, strerror(errno));
201
+			if ((errno == EINTR) || 
202
+			    (errno == EAGAIN) || 
203
+			    (errno == EWOULDBLOCK) || 
204
+			    (errno == ECONNREFUSED)) {
205
+				DBG("Got %d (%s), going on\n", errno, strerror(errno));
206
+				continue;
207
+			}
208
+			ERR("BUG: unexpected recvfrom error\n");
209
+			continue;
210
+		}
211
+
212
+		buffer.s = buf;
213
+		buffer.len = ret;
214
+		unixsock_reply_reset();
215
+
216
+		if (parse_cmd(&cmd, &buffer) < 0) {
217
+			     /*			unixsock_reply_asciiz("400 First line malformed\n"); */
218
+			unixsock_reply_send();
219
+			continue;
220
+		}
221
+
222
+		buffer.s = cmd.s + cmd.len + 1;
223
+		buffer.len -= cmd.len + 1 + 1;
224
+
225
+		     /*		c = lookup_cmd(&cmd); */
226
+		if (c == 0) {
227
+			ERR("Could not find "
228
+			    "command '%.*s'\n", cmd.len, ZSW(cmd.s));
229
+			     /*			unixsock_reply_printf("500 Command %.*s not found\n", cmd.len, ZSW(cmd.s)); */
230
+			unixsock_reply_send();
231
+			continue;
232
+		}
233
+
234
+		     /*		ret = c->f(&buffer); */
235
+		if (ret < 0) {
236
+			ERR("Command '%.*s' failed with "
237
+			    "return value %d\n", cmd.len, ZSW(cmd.s), ret);
238
+			     /* Note that we do not send reply here, the 
239
+			      * function is supposed to do so, it knows the 
240
+			      * reason of the failure better than us
241
+			      */
242
+		}
243
+	}
244
+}
245
+
246
+
247
+/*
248
+ * Spawn listeners
249
+ */
250
+int init_unixsock_children(void)
251
+{
252
+	int i, backup;
253
+	pid_t pid;
254
+#ifdef USE_TCP
255
+	int sockfd[2];
256
+#endif
257
+
258
+	if (!unixsock_name || *unixsock_name == '\0') {
259
+		return 1;
260
+	}
261
+
262
+	for(i = 0; i < unixsock_children; i++) {
263
+		last_process++;
264
+#ifdef USE_TCP
265
+		if(!tcp_disable){
266
+ 			if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
267
+				ERR("socketpair failed: %s\n", strerror(errno));
268
+				return -1;
269
+			}
270
+		}
271
+#endif
272
+		pid = fork();
273
+		if (pid < 0) {
274
+			ERR("Unable to fork: %s\n", strerror(errno));
275
+			close(rx_sock);
276
+			close(tx_sock);
277
+			return -1;
278
+		} else if (pid == 0) { /* child */
279
+			process_no = last_process;
280
+			is_main = 0;
281
+#ifdef USE_TCP
282
+			if (!tcp_disable){
283
+				close(sockfd[0]);
284
+				unix_tcp_sock=sockfd[1];
285
+			}
286
+#endif
287
+			/* record pid twice to avoid the child using it, before
288
+			 * parent gets a chance to set it*/
289
+			pt[process_no].pid=getpid();
290
+			if (init_child(PROC_UNIXSOCK) < 0) {
291
+				ERR("Error in init_child\n");
292
+				close(rx_sock);
293
+				close(tx_sock);
294
+				return -1;
295
+			}
296
+			unix_server_loop(); /* Never returns */
297
+		}
298
+
299
+		     /* Parent */
300
+		pt[last_process].pid = pid;
301
+		snprintf(pt[last_process].desc, MAX_PT_DESC, 
302
+			"unix domain socket server @ %s", 
303
+			 unixsock_name);
304
+#ifdef USE_TCP
305
+		if (!tcp_disable){
306
+			close(sockfd[1]);
307
+			pt[last_process].unix_sock=sockfd[0];
308
+			pt[last_process].idx=-1; /* this is not a "tcp"
309
+									  process*/
310
+		}
311
+#endif
312
+
313
+	}
314
+
315
+	DBG("Unix domain socket server successfully initialized @ %s\n", unixsock_name);
316
+	return 1;
317
+}
318
+
319
+
320
+/*
321
+ * Clean up
322
+ */
323
+void close_unixsock_server(void)
324
+{
325
+	close(rx_sock);
326
+	close(tx_sock);
327
+}
328
+
329
+/*
330
+ * Send a reply
331
+ */
332
+ssize_t unixsock_reply_send(void)
333
+{
334
+	return tsend_dgram(tx_sock, 
335
+			   reply_buf, reply_pos.s - reply_buf,
336
+			   (struct sockaddr*)&reply_addr, reply_addr_len, 
337
+			   unixsock_tx_timeout);
338
+}
339
+
340
+
341
+/*
342
+ * Send a reply
343
+ */
344
+ssize_t unixsock_reply_sendto(struct sockaddr_un* to)
345
+{
346
+	if (!to) {
347
+	        ERR("Invalid parameter value\n");
348
+		return -1;
349
+	}
350
+
351
+	return tsend_dgram(tx_sock, 
352
+			   reply_buf, reply_pos.s - reply_buf, 
353
+			   (struct sockaddr*)to, SUN_LEN(to), 
354
+			   unixsock_tx_timeout);
355
+}
356
+
357
+
358
+/*
359
+ * Reset the reply buffer -- start to write
360
+ * at the beginning
361
+ */
362
+void unixsock_reply_reset(void)
363
+{
364
+	reply_pos.s = reply_buf;
365
+	reply_pos.len = UNIXSOCK_BUF_SIZE;
366
+}
367
+
368
+
369
+/*
370
+ * Return the address of the sender
371
+ */
372
+struct sockaddr_un* unixsock_sender_addr(void)
373
+{
374
+	return &reply_addr;
375
+}
0 376
new file mode 100644
... ...
@@ -0,0 +1,83 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * UNIX Domain Socket Server
4
+ *
5
+ * Copyright (C) 2001-2004 FhG Fokus
6
+ * Copyright (C) 2005 iptelorg GmbH
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/types.h>
35
+#include <sys/un.h>
36
+#include <unistd.h>
37
+#include "../../str.h"
38
+
39
+extern char* unixsock_name;
40
+extern char* unixsock_user;
41
+extern char* unixsock_mode;
42
+extern char* unixsock_group;
43
+extern unsigned int unixsock_children;
44
+extern unsigned int unixsock_tx_timeout;
45
+
46
+/*
47
+ * Initialize Unix domain socket server
48
+ */
49
+int init_unixsock_socket(void);
50
+
51
+
52
+/*
53
+ * Initialize Unix domain socket server
54
+ */
55
+int init_unixsock_children(void);
56
+
57
+
58
+/*
59
+ * Clean up
60
+ */
61
+void close_unixsock_server(void);
62
+
63
+
64
+/*
65
+ * Send the reply
66
+ */
67
+ssize_t unixsock_reply_send(void);
68
+
69
+
70
+/*
71
+ * Send the reply to the given destination
72
+ */
73
+ssize_t unixsock_reply_sendto(struct sockaddr_un* to);
74
+
75
+/*
76
+ * Return the address of the sender
77
+ */
78
+struct sockaddr_un* unixsock_sender_addr(void);
79
+
80
+void unixsock_reply_reset(void);
81
+
82
+#endif /* _UNIXSOCK_SERVER_H */