Browse code

support operation of both TCP and Unix domain sockets simultaneously

git-svn: trunk@1626

Tomasz Kojm authored on 2005/06/23 00:54:28
Showing 12 changed files
... ...
@@ -1,3 +1,8 @@
1
+Wed Jun 22 17:52:08 CEST 2005 (tk)
2
+----------------------------------
3
+  * clamd: support operation of both TCP and Unix domain sockets simultaneously
4
+	   Patch by Mark Pizzolato <clamav-devel*subscriptions.pizzolato.net>
5
+
1 6
 Wed Jun 22 16:43:43 CEST 2005 (tk)
2 7
 ----------------------------------
3 8
   * clamd: limit the internal queue of requests to MaxConnectionQueueLength
... ...
@@ -69,7 +69,8 @@ void clamd(struct optstruct *opt)
69 69
 	time_t currtime;
70 70
 	struct cl_node *root = NULL;
71 71
 	const char *dbdir, *cfgfile;
72
-	int ret, virnum = 0, tcpsock;
72
+	int ret, virnum = 0, tcpsock = 0, localsock = 0;
73
+	int lsockets[2], nlsockets = 0;
73 74
 #ifdef C_LINUX
74 75
 	struct stat sb;
75 76
 #endif
... ...
@@ -213,15 +214,13 @@ void clamd(struct optstruct *opt)
213 213
 
214 214
     /* check socket type */
215 215
 
216
-    if(cfgopt(copt, "TCPSocket")->enabled && cfgopt(copt, "LocalSocket")->enabled) {
217
-	fprintf(stderr, "ERROR: You can only select one mode (local or TCP).\n");
218
-	logg("!Two modes (local and TCP) selected.\n");
219
-	exit(1);
220
-    } else if(cfgopt(copt, "TCPSocket")->enabled) {
216
+    if(cfgopt(copt, "TCPSocket")->enabled)
221 217
 	tcpsock = 1;
222
-    } else if(cfgopt(copt, "LocalSocket")->enabled) {
223
-	tcpsock = 0;
224
-    } else {
218
+
219
+    if(cfgopt(copt, "LocalSocket")->enabled)
220
+	localsock = 1;
221
+
222
+    if(!tcpsock && !localsock) {
225 223
 	fprintf(stderr, "ERROR: You must select server type (local/tcp).\n");
226 224
 	logg("!Please select server type (local/TCP).\n");
227 225
 	exit(1);
... ...
@@ -265,15 +264,15 @@ void clamd(struct optstruct *opt)
265 265
         foreground = 1;
266 266
 
267 267
     if(tcpsock)
268
-	ret = tcpserver(opt, copt, root);
269
-    else
270
-	ret = localserver(opt, copt, root);
268
+	lsockets[nlsockets++] = tcpserver(copt, root);
269
+
270
+    if(localsock)
271
+	lsockets[nlsockets++] = localserver(copt, root);
272
+
273
+    ret = acceptloop_th(lsockets, nlsockets, root, copt);
271 274
 
272
-    printf("server ended; result=%d\n", ret);
273 275
     logg_close();
274 276
     freecfg(copt);
275
-    printf("free() copt\n");
276
-
277 277
 }
278 278
 
279 279
 void help(void)
... ...
@@ -35,7 +35,7 @@
35 35
 #include "server.h"
36 36
 #include "output.h"
37 37
 
38
-int localserver(const struct optstruct *opt, const struct cfgstruct *copt, struct cl_node *root)
38
+int localserver(const struct cfgstruct *copt, struct cl_node *root)
39 39
 {
40 40
 	struct sockaddr_un server;
41 41
 	int sockfd, backlog;
... ...
@@ -100,7 +100,5 @@ int localserver(const struct optstruct *opt, const struct cfgstruct *copt, struc
100 100
 	exit(1);
101 101
     }
102 102
 
103
-    acceptloop_th(sockfd, root, copt);
104
-
105
-    return 0;
103
+    return sockfd;
106 104
 }
... ...
@@ -19,6 +19,6 @@
19 19
 #ifndef __LOCALSERVER_H
20 20
 #define __LOCALSERVER_H
21 21
 
22
-int localserver(const struct optstruct *opt, const struct cfgstruct *copt, struct cl_node *root);
22
+int localserver(const struct cfgstruct *copt, struct cl_node *root);
23 23
 
24 24
 #endif
... ...
@@ -126,45 +126,70 @@ void virusaction(const char *filename, const char *virname, const struct cfgstru
126 126
     }
127 127
 }
128 128
 
129
-int poll_fd(int fd, int timeout_sec)
129
+int poll_fds(int *fds, int nfds, int timeout_sec)
130 130
 {
131 131
 	int retval;
132
+	int i;
132 133
 #ifdef HAVE_POLL
133
-	struct pollfd poll_data[1];
134
-
135
-    poll_data[0].fd = fd;
136
-    poll_data[0].events = POLLIN;
137
-    poll_data[0].revents = 0;
134
+	struct pollfd poll_1[1];
135
+	struct pollfd *poll_data = poll_1;
136
+
137
+    if (nfds>1)
138
+	poll_data = malloc(nfds*sizeof(*poll_data));
139
+    for (i=0; i<nfds; i++) {
140
+	poll_data[i].fd = fds[i];
141
+	poll_data[i].events = POLLIN;
142
+	poll_data[i].revents = 0;
143
+    }
138 144
 
139 145
     if (timeout_sec > 0) {
140 146
     	timeout_sec *= 1000;
141 147
     }
142 148
     while (1) {
143
-    	retval = poll(poll_data, 1, timeout_sec);
149
+    	retval = poll(poll_data, nfds, timeout_sec);
144 150
 	if (retval == -1) {
145 151
    	    if (errno == EINTR) {
146 152
 		continue;
147 153
 	    }
154
+	    if (nfds>1)
155
+		free(poll_data);
148 156
 	    return -1;
149 157
 	}
158
+	if (nfds>1) {
159
+	    if (retval>0) {
160
+		for (i=0; i<nfds; i++) {
161
+		    if (poll_data[i].revents) {
162
+			retval = i+1;
163
+			break;
164
+		    }
165
+		}
166
+	    }
167
+	    free(poll_data);
168
+	}
150 169
 	return retval;
151 170
     }
152 171
 
153 172
 #else
154 173
 	fd_set rfds;
155 174
 	struct timeval tv;
175
+	int maxfd = 0;
156 176
 
157
-    if (fd >= DEFAULT_FD_SETSIZE) {
158
-	return -1;
177
+    for (i=0; i<nfds; i++) {
178
+	if (fds[i] >= DEFAULT_FD_SETSIZE) {
179
+	    return -1;
180
+	}
181
+	if (fds[i] > maxfd)
182
+	    maxfd = fds[i];
159 183
     }
160 184
 
161 185
     while (1) {
162 186
 	FD_ZERO(&rfds);
163
-	FD_SET(fd, &rfds);
187
+	for (i=0; i<nfds; i++)
188
+	    FD_SET(fds[i], &rfds);
164 189
 	tv.tv_sec = timeout_sec;
165 190
 	tv.tv_usec = 0;
166 191
 
167
-	retval = select(fd+1, &rfds, NULL, NULL,
192
+	retval = select(maxfd+1, &rfds, NULL, NULL,
168 193
 			(timeout_sec>0 ? &tv : NULL));
169 194
 	if (retval == -1) {
170 195
 	    if (errno == EINTR) {
... ...
@@ -172,6 +197,14 @@ int poll_fd(int fd, int timeout_sec)
172 172
 	    }
173 173
 	    return -1;
174 174
 	}
175
+	if ((nfds>1) && (retval>0)) {
176
+	    for (i=0; i<nfds; i++) {
177
+		if (FD_ISSET(fds[i],&rfds)) {
178
+		    retval = i+1;
179
+		    break;
180
+		}
181
+	    }
182
+	}
175 183
 	return retval;
176 184
     }
177 185
 #endif
... ...
@@ -179,6 +212,11 @@ int poll_fd(int fd, int timeout_sec)
179 179
     return -1;
180 180
 }
181 181
 
182
+int poll_fd(int fd, int timeout_sec)
183
+{
184
+    return poll_fds(&fd, 1, timeout_sec);
185
+}
186
+
182 187
 int is_fd_connected(int fd)
183 188
 {
184 189
 #ifdef HAVE_POLL
... ...
@@ -26,6 +26,7 @@
26 26
 #include <stdlib.h>
27 27
 #include "cfgparser.h"
28 28
 
29
+int poll_fds(int *fds, int nfds, int timeout_sec);
29 30
 int poll_fd(int fd, int timeout_sec);
30 31
 int is_fd_connected(int fd);
31 32
 void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt);
... ...
@@ -62,14 +62,15 @@ typedef struct client_conn_tag {
62 62
     time_t root_timestamp;
63 63
     time_t queue_time;
64 64
     const struct cl_limits *limits;
65
-    pid_t mainpid;
65
+    int *socketds;
66
+    int nsockets;
66 67
 } client_conn_t;
67 68
 
68 69
 void scanner_thread(void *arg)
69 70
 {
70 71
 	client_conn_t *conn = (client_conn_t *) arg;
71 72
 	sigset_t sigset;
72
-	int ret, timeout, session=FALSE;
73
+	int ret, timeout, i, session=FALSE;
73 74
 	struct cfgstruct *cpt;
74 75
 
75 76
 
... ...
@@ -109,7 +110,10 @@ void scanner_thread(void *arg)
109 109
 	    case COMMAND_SHUTDOWN:
110 110
 		pthread_mutex_lock(&exit_mutex);
111 111
 		progexit = 1;
112
-		kill(conn->mainpid, SIGTERM);
112
+		for(i = 0; i < conn->nsockets; i++) {
113
+		    shutdown(conn->socketds[i], 2);
114
+		    close(conn->socketds[i]);
115
+		}
113 116
 		pthread_mutex_unlock(&exit_mutex);
114 117
 		break;
115 118
 
... ...
@@ -258,9 +262,9 @@ static struct cl_node *reload_db(struct cl_node *root, const struct cfgstruct *c
258 258
     return root;
259 259
 }
260 260
 
261
-int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *copt)
261
+int acceptloop_th(int *socketds, int nsockets, struct cl_node *root, const struct cfgstruct *copt)
262 262
 {
263
-	int new_sd, max_threads, max_queue_size;
263
+	int new_sd, max_threads, max_queue_size, i;
264 264
 	unsigned int options = 0;
265 265
 	threadpool_t *thr_pool;
266 266
 	struct sigaction sigact;
... ...
@@ -485,8 +489,20 @@ int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *cop
485 485
     time(&start_time);
486 486
 
487 487
     for(;;) {
488
+    	int socketd = socketds[0];
489
+    	if(nsockets > 1) {
490
+    	    int pollret = poll_fds(socketds, nsockets, -1);
491
+    	    if(pollret > 0) {
492
+    		socketd = socketds[pollret - 1];
493
+    	    } else {
494
+    		socketd = socketds[0]; /* on a poll error use the first socket */
495
+    	    }
496
+    	}    
488 497
 	new_sd = accept(socketd, NULL, NULL);
489 498
 	if((new_sd == -1) && (errno != EINTR)) {
499
+	    if(progexit) {
500
+	    	break;
501
+	    }
490 502
 	    /* very bad - need to exit or restart */
491 503
 #ifdef HAVE_STRERROR_R
492 504
 	    logg("!accept() failed: %s\n", strerror_r(errno, buff, BUFFSIZE));
... ...
@@ -513,7 +529,8 @@ int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *cop
513 513
 		client_conn->root_timestamp = reloaded_time;
514 514
 		time(&client_conn->queue_time);
515 515
 		client_conn->limits = &limits;
516
-		client_conn->mainpid = mainpid;
516
+		client_conn->socketds = socketds;
517
+		client_conn->nsockets = nsockets;
517 518
 		if (!thrmgr_dispatch(thr_pool, client_conn)) {
518 519
 		    close(client_conn->sd);
519 520
 		    free(client_conn);
... ...
@@ -577,11 +594,12 @@ int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *cop
577 577
     }
578 578
 #endif
579 579
     cl_free(root);
580
-    logg("*Shutting down the main socket.\n");
581
-    shutdown(socketd, 2);
582
-    logg("*Closing the main socket.\n");
583
-    close(socketd);
584
-
580
+    logg("*Shutting down the main socket%s.\n", (nsockets > 1) ? "s" : "");
581
+    for (i = 0; i < nsockets; i++)
582
+	shutdown(socketds[i], 2);
583
+    logg("*Closing the main socket%s.\n", (nsockets > 1) ? "s" : "");
584
+    for (i = 0; i < nsockets; i++)
585
+	close(socketds[i]);
585 586
 #ifndef C_OS2
586 587
     if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
587 588
 	if(unlink(cpt->strarg) == -1)
... ...
@@ -48,8 +48,7 @@ struct thrwarg {
48 48
     int options;
49 49
 };
50 50
 
51
-int acceptloop_proc(int socketd, struct cl_node *root, const struct cfgstruct *copt);
52
-int acceptloop_th(int socketd, struct cl_node *root, const struct cfgstruct *copt);
51
+int acceptloop_th(int *socketds, int nsockets, struct cl_node *root, const struct cfgstruct *copt);
53 52
 void sighandler(int sig);
54 53
 void sighandler_th(int sig);
55 54
 void daemonize(void);
... ...
@@ -36,7 +36,7 @@
36 36
 #include "server.h"
37 37
 #include "output.h"
38 38
 
39
-int tcpserver(const struct optstruct *opt, const struct cfgstruct *copt, struct cl_node *root)
39
+int tcpserver(const struct cfgstruct *copt, struct cl_node *root)
40 40
 {
41 41
 	struct sockaddr_in server;
42 42
 	int sockfd, backlog;
... ...
@@ -76,9 +76,9 @@ int tcpserver(const struct optstruct *opt, const struct cfgstruct *copt, struct
76 76
 	exit(1);
77 77
     } else {
78 78
 	if(taddr->enabled)
79
-	    logg("Bound to address %s on port %d\n", taddr->strarg, cfgopt(copt, "TCPSocket")->numarg);
79
+	    logg("Bound to address %s on tcp port %d\n", taddr->strarg, cfgopt(copt, "TCPSocket")->numarg);
80 80
 	else
81
-	    logg("Bound to port %d\n", cfgopt(copt, "TCPSocket")->numarg);
81
+	    logg("Bound to tcp port %d\n", cfgopt(copt, "TCPSocket")->numarg);
82 82
     }
83 83
 
84 84
     backlog = cfgopt(copt, "MaxConnectionQueueLength")->numarg;
... ...
@@ -90,7 +90,5 @@ int tcpserver(const struct optstruct *opt, const struct cfgstruct *copt, struct
90 90
 	exit(1);
91 91
     }
92 92
 
93
-    acceptloop_th(sockfd, root, copt);
94
-
95
-    return 0;
93
+    return sockfd;
96 94
 }
... ...
@@ -22,6 +22,6 @@
22 22
 #include "options.h"
23 23
 #include "cfgparser.h"
24 24
 
25
-int tcpserver(const struct optstruct *opt, const struct cfgstruct *copt, struct cl_node *root);
25
+int tcpserver(const struct cfgstruct *copt, struct cl_node *root);
26 26
 
27 27
 #endif
... ...
@@ -324,10 +324,7 @@ int dconnect(const struct optstruct *opt)
324 324
     /* Set default address to connect to */
325 325
     server2.sin_addr.s_addr = inet_addr("127.0.0.1");    
326 326
 
327
-    if(cfgopt(copt, "TCPSocket")->enabled && cfgopt(copt, "LocalSocket")->enabled) {
328
-	logg("^Clamd is not configured properly.\n");
329
-	return -1;
330
-    } else if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
327
+    if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
331 328
 
332 329
 	server.sun_family = AF_UNIX;
333 330
 	strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));
... ...
@@ -52,10 +52,7 @@ int notify(const char *cfgfile)
52 52
 	return 1;
53 53
     }
54 54
 
55
-    if(cfgopt(copt, "TCPSocket")->enabled && cfgopt(copt, "LocalSocket")->enabled) {
56
-	logg("^Clamd was NOT notified: Both socket types (TCP and local) declared in %s\n", cfgfile);
57
-	return 1;
58
-    } else if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
55
+    if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
59 56
 	socktype = "UNIX";
60 57
 	server.sun_family = AF_UNIX;
61 58
 	strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));