1 /*
2 Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*! \file
19 * Main functions to set-up dpi information and to initialise sockets
20 */
21 #include <errno.h>
22 #include <stdlib.h> /* for exit */
23 #include <fcntl.h> /* for F_SETFD, F_GETFD, FD_CLOEXEC */
24
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <sys/socket.h>
28 #include <netinet/tcp.h>
29
30 #include <unistd.h>
31 #include "dpid_common.h"
32 #include "dpid.h"
33 #include "dpi.h"
34 #include "dpi_socket_dir.h"
35 #include "misc_new.h"
36
37 #include "../dpip/dpip.h"
38
39 #define QUEUE 5
40
41 volatile sig_atomic_t caught_sigchld = 0;
42 char *SharedKey = NULL;
43
44 /*! Remove dpid_comm_keys file.
45 * This avoids that dillo instances connect to a stale port after dpid
46 * has exited (e.g. after a reboot).
47 */
cleanup()48 void cleanup()
49 {
50 char *fname;
51 fname = dStrconcat(dGethomedir(), "/", dotDILLO_DPID_COMM_KEYS, NULL);
52 unlink(fname);
53 dFree(fname);
54 }
55
56 /*! Free memory used to describe
57 * a set of dpi attributes
58 */
free_dpi_attr(struct dp * dpi_attr)59 void free_dpi_attr(struct dp *dpi_attr)
60 {
61 if (dpi_attr->id != NULL) {
62 dFree(dpi_attr->id);
63 dpi_attr->id = NULL;
64 }
65 if (dpi_attr->path != NULL) {
66 dFree(dpi_attr->path);
67 dpi_attr->path = NULL;
68 }
69 }
70
71 /*! Free memory used by the plugin list
72 */
free_plugin_list(struct dp ** dpi_attr_list_ptr,int numdpis)73 void free_plugin_list(struct dp **dpi_attr_list_ptr, int numdpis)
74 {
75 int i;
76 struct dp *dpi_attr_list = *dpi_attr_list_ptr;
77
78 if (dpi_attr_list == NULL)
79 return;
80
81 for (i = 0; i < numdpis; i++)
82 free_dpi_attr(dpi_attr_list + i);
83
84 dFree(dpi_attr_list);
85 *dpi_attr_list_ptr = NULL;
86 }
87
88 /*! Free memory used by the services list
89 */
free_services_list(Dlist * s_list)90 void free_services_list(Dlist *s_list)
91 {
92 int i = 0;
93 struct service *s;
94
95 for (i=0; i < dList_length(s_list) ; i++) {
96 s = dList_nth_data(s_list, i);
97 dFree(s->name);
98 }
99 dList_free(s_list);
100 }
101
102 /*! Signal handler for SIGINT, SIGQUIT, and SIGTERM. Calls cleanup
103 */
terminator(int sig)104 static void terminator(int sig)
105 {
106 (void) sig; /* suppress unused parameter warning */
107 cleanup();
108 _exit(0);
109 }
110
111 /*! Establish handler for termination signals
112 * and register cleanup with atexit */
est_dpi_terminator()113 void est_dpi_terminator()
114 {
115 struct sigaction act;
116 sigset_t block;
117
118 sigemptyset(&block);
119 sigaddset(&block, SIGHUP);
120 sigaddset(&block, SIGINT);
121 sigaddset(&block, SIGQUIT);
122 sigaddset(&block, SIGTERM);
123
124 act.sa_handler = terminator;
125 act.sa_mask = block;
126 act.sa_flags = 0;
127
128 if (sigaction(SIGHUP, &act, NULL) ||
129 sigaction(SIGINT, &act, NULL) ||
130 sigaction(SIGQUIT, &act, NULL) ||
131 sigaction(SIGTERM, &act, NULL)) {
132 ERRMSG("est_dpi_terminator", "sigaction", errno);
133 exit(1);
134 }
135
136 if (atexit(cleanup) != 0) {
137 ERRMSG("est_dpi_terminator", "atexit", 0);
138 MSG_ERR("Hey! atexit failed, how did that happen?\n");
139 exit(1);
140 }
141 }
142
143 /*! Identify a given file
144 * Currently there is only one file type associated with dpis.
145 * More file types will be added as needed
146 */
get_file_type(char * file_name)147 enum file_type get_file_type(char *file_name)
148 {
149 char *dot = strrchr(file_name, '.');
150
151 if (dot && !strcmp(dot, ".dpi"))
152 return DPI_FILE; /* Any filename ending in ".dpi" */
153 else {
154 MSG_ERR("get_file_type: Unknown file type for %s\n", file_name);
155 return UNKNOWN_FILE;
156 }
157 }
158
159 /*! Get dpi directory path from dpidrc
160 * \Return
161 * dpi directory on success, NULL on failure
162 * \Important
163 * The dpi_dir definition in dpidrc must have no leading white space.
164 */
get_dpi_dir(char * dpidrc)165 char *get_dpi_dir(char *dpidrc)
166 {
167 FILE *In;
168 int len;
169 char *rcline = NULL, *value = NULL, *p;
170
171 if ((In = fopen(dpidrc, "r")) == NULL) {
172 ERRMSG("dpi_dir", "fopen", errno);
173 MSG_ERR(" - %s\n", dpidrc);
174 return (NULL);
175 }
176
177 while ((rcline = dGetline(In)) != NULL) {
178 if (strncmp(rcline, "dpi_dir", 7) == 0)
179 break;
180 dFree(rcline);
181 }
182 fclose(In);
183
184 if (!rcline) {
185 ERRMSG("dpi_dir", "Failed to find a dpi_dir entry in dpidrc", 0);
186 MSG_ERR("Put your dillo plugins path in %s\n", dpidrc);
187 MSG_ERR("e.g. dpi_dir=/usr/local/libexec/dillo/dpi\n");
188 MSG_ERR("with no leading spaces.\n");
189 value = NULL;
190 } else {
191 len = (int) strlen(rcline);
192 if (len && rcline[len - 1] == '\n')
193 rcline[len - 1] = 0;
194
195 if ((p = strchr(rcline, '='))) {
196 while (*++p == ' ');
197 value = dStrdup(p);
198 } else {
199 ERRMSG("dpi_dir", "strchr", 0);
200 MSG_ERR(" - '=' not found in %s\n", rcline);
201 value = NULL;
202 }
203 }
204
205 dFree(rcline);
206 return (value);
207 }
208
209 /*! Scans a service directory in dpi_dir and fills dpi_attr
210 * \Note
211 * Caller must allocate memory for dpi_attr.
212 * \Return
213 * \li 0 on success
214 * \li -1 on failure
215 * \todo
216 * Add other file types, but first we need to add files associated with a dpi
217 * to the design.
218 */
get_dpi_attr(char * dpi_dir,char * service,struct dp * dpi_attr)219 int get_dpi_attr(char *dpi_dir, char *service, struct dp *dpi_attr)
220 {
221 char *service_dir = NULL;
222 struct stat statinfo;
223 enum file_type ftype;
224 int ret = -1;
225 DIR *dir_stream;
226 struct dirent *dir_entry = NULL;
227
228 service_dir = dStrconcat(dpi_dir, "/", service, NULL);
229 if (stat(service_dir, &statinfo) == -1) {
230 ERRMSG("get_dpi_attr", "stat", errno);
231 MSG_ERR("file=%s\n", service_dir);
232 } else if ((dir_stream = opendir(service_dir)) == NULL) {
233 ERRMSG("get_dpi_attr", "opendir", errno);
234 } else {
235 /* Scan the directory looking for dpi files.
236 * (currently there's only the dpi program, but in the future
237 * there may also be helper scripts.) */
238 while ( (dir_entry = readdir(dir_stream)) != NULL) {
239 if (dir_entry->d_name[0] == '.')
240 continue;
241
242 ftype = get_file_type(dir_entry->d_name);
243 switch (ftype) {
244 case DPI_FILE:
245 dpi_attr->path =
246 dStrconcat(service_dir, "/", dir_entry->d_name, NULL);
247 dpi_attr->id = dStrdup(service);
248 dpi_attr->port = 0;
249 dpi_attr->pid = 1;
250 if (strstr(dpi_attr->path, ".filter") != NULL)
251 dpi_attr->filter = 1;
252 else
253 dpi_attr->filter = 0;
254 ret = 0;
255 break;
256 default:
257 break;
258 }
259 }
260 closedir(dir_stream);
261
262 if (ret != 0)
263 MSG_ERR("get_dpi_attr: No dpi plug-in in %s/%s\n",
264 dpi_dir, service);
265 }
266 dFree(service_dir);
267 return ret;
268 }
269
270 /*! Register a service
271 * Retrieves attributes for "service" and stores them
272 * in dpi_attr. It looks for "service" in ~/.dillo/dpi
273 * first, and then in the system wide dpi directory.
274 * Caller must allocate memory for dpi_attr.
275 * \Return
276 * \li 0 on success
277 * \li -1 on failure
278 */
register_service(struct dp * dpi_attr,char * service)279 int register_service(struct dp *dpi_attr, char *service)
280 {
281 char *user_dpi_dir, *dpidrc, *user_service_dir, *dir = NULL;
282 int ret = -1;
283
284 user_dpi_dir = dStrconcat(dGethomedir(), "/", dotDILLO_DPI, NULL);
285 user_service_dir =
286 dStrconcat(dGethomedir(), "/", dotDILLO_DPI, "/", service, NULL);
287
288 dpidrc = dStrconcat(dGethomedir(), "/", dotDILLO_DPIDRC, NULL);
289 if (access(dpidrc, F_OK) == -1) {
290 if (access(DPIDRC_SYS, F_OK) == -1) {
291 ERRMSG("register_service", "Error ", 0);
292 MSG_ERR("\n - There is no %s or %s file\n", dpidrc,
293 DPIDRC_SYS);
294 dFree(user_dpi_dir);
295 dFree(user_service_dir);
296 dFree(dpidrc);
297 return(-1);
298 }
299 dFree(dpidrc);
300 dpidrc = dStrdup(DPIDRC_SYS);
301 }
302
303 /* Check home dir for dpis */
304 if (access(user_service_dir, F_OK) == 0) {
305 get_dpi_attr(user_dpi_dir, service, dpi_attr);
306 ret = 0;
307 } else { /* Check system wide dpis */
308 if ((dir = get_dpi_dir(dpidrc)) != NULL) {
309 if (access(dir, F_OK) == 0) {
310 get_dpi_attr(dir, service, dpi_attr);
311 ret = 0;
312 } else {
313 ERRMSG("register_service", "get_dpi_attr failed", 0);
314 }
315 } else {
316 ERRMSG("register_service", "dpi_dir: Error getting dpi dir.", 0);
317 }
318 }
319 dFree(user_dpi_dir);
320 dFree(user_service_dir);
321 dFree(dpidrc);
322 dFree(dir);
323 return ret;
324 }
325
326 /*!
327 * Create dpi directory for available
328 * plugins and create plugin list.
329 * \Return
330 * \li Returns number of available plugins on success
331 * \li -1 on failure
332 */
register_all(struct dp ** attlist)333 int register_all(struct dp **attlist)
334 {
335 DIR *user_dir_stream, *sys_dir_stream;
336 char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
337 struct dirent *user_dirent, *sys_dirent;
338 int st;
339 int snum;
340 size_t dp_sz = sizeof(struct dp);
341
342 if (*attlist != NULL) {
343 ERRMSG("register_all", "attlist parameter should be NULL", 0);
344 return -1;
345 }
346
347 user_dpidir = dStrconcat(dGethomedir(), "/", dotDILLO_DPI, NULL);
348 if (access(user_dpidir, F_OK) == -1) {
349 /* no dpis in user's space */
350 dFree(user_dpidir);
351 user_dpidir = NULL;
352 }
353 dpidrc = dStrconcat(dGethomedir(), "/", dotDILLO_DPIDRC, NULL);
354 if (access(dpidrc, F_OK) == -1) {
355 dFree(dpidrc);
356 dpidrc = dStrdup(DPIDRC_SYS);
357 if (access(dpidrc, F_OK) == -1) {
358 dFree(dpidrc);
359 dpidrc = NULL;
360 }
361 }
362 if (!dpidrc || (sys_dpidir = get_dpi_dir(dpidrc)) == NULL)
363 sys_dpidir = NULL;
364 dFree(dpidrc);
365
366 if (!user_dpidir && !sys_dpidir) {
367 ERRMSG("register_all", "Fatal error ", 0);
368 MSG_ERR("\n - Can't find the directory for dpis.\n");
369 exit(1);
370 }
371
372 /* Get list of services in user's .dillo/dpi directory */
373 snum = 0;
374 if (user_dpidir && (user_dir_stream = opendir(user_dpidir)) != NULL) {
375 while ((user_dirent = readdir(user_dir_stream)) != NULL) {
376 if (user_dirent->d_name[0] == '.')
377 continue;
378 *attlist = (struct dp *) dRealloc(*attlist, (snum + 1) * dp_sz);
379 st=get_dpi_attr(user_dpidir, user_dirent->d_name, &(*attlist)[snum]);
380 if (st == 0)
381 snum++;
382 }
383 closedir(user_dir_stream);
384 }
385 if (sys_dpidir && (sys_dir_stream = opendir(sys_dpidir)) != NULL) {
386 /* if system service is not in user list then add it */
387 while ((sys_dirent = readdir(sys_dir_stream)) != NULL) {
388 if (sys_dirent->d_name[0] == '.')
389 continue;
390 *attlist = (struct dp *) dRealloc(*attlist, (snum + 1) * dp_sz);
391 st=get_dpi_attr(sys_dpidir, sys_dirent->d_name, &(*attlist)[snum]);
392 if (st == 0)
393 snum++;
394 }
395 closedir(sys_dir_stream);
396 }
397
398 dFree(sys_dpidir);
399 dFree(user_dpidir);
400
401 /* TODO: do we consider snum == 0 an error?
402 * (if so, we should return -1 ) */
403 return (snum);
404 }
405
406 /*
407 * Compare two struct service pointers
408 * This function is used for sorting services
409 */
services_alpha_comp(const struct service * s1,const struct service * s2)410 static int services_alpha_comp(const struct service *s1,
411 const struct service *s2)
412 {
413 return -strcmp(s1->name, s2->name);
414 }
415
416 /*! Add services reading a dpidrc file
417 * each non empty or commented line has the form
418 * service = path_relative_to_dpidir
419 * \Return:
420 * \li Returns number of available services on success
421 * \li -1 on failure
422 */
fill_services_list(struct dp * attlist,int numdpis,Dlist ** services_list)423 int fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list)
424 {
425 FILE *dpidrc_stream;
426 char *p, *line = NULL, *service, *path;
427 int i, st;
428 struct service *s;
429 char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
430
431 user_dpidir = dStrconcat(dGethomedir(), "/", dotDILLO_DPI, NULL);
432 if (access(user_dpidir, F_OK) == -1) {
433 /* no dpis in user's space */
434 dFree(user_dpidir);
435 user_dpidir = NULL;
436 }
437 dpidrc = dStrconcat(dGethomedir(), "/", dotDILLO_DPIDRC, NULL);
438 if (access(dpidrc, F_OK) == -1) {
439 dFree(dpidrc);
440 dpidrc = dStrdup(DPIDRC_SYS);
441 if (access(dpidrc, F_OK) == -1) {
442 dFree(dpidrc);
443 dpidrc = NULL;
444 }
445 }
446 if (!dpidrc || (sys_dpidir = get_dpi_dir(dpidrc)) == NULL)
447 sys_dpidir = NULL;
448
449 if (!user_dpidir && !sys_dpidir) {
450 ERRMSG("fill_services_list", "Fatal error ", 0);
451 MSG_ERR("\n - Can't find the directory for dpis.\n");
452 exit(1);
453 }
454
455 if ((dpidrc_stream = fopen(dpidrc, "r")) == NULL) {
456 ERRMSG("fill_services_list", "popen failed", errno);
457 dFree(dpidrc);
458 dFree(sys_dpidir);
459 dFree(user_dpidir);
460 return (-1);
461 }
462
463 if (*services_list != NULL) {
464 ERRMSG("fill_services_list", "services_list parameter is not NULL", 0);
465 return -1;
466 }
467 *services_list = dList_new(8);
468
469 /* dpidrc parser loop */
470 for (;(line = dGetline(dpidrc_stream)) != NULL; dFree(line)) {
471 st = dParser_parse_rc_line(&line, &service, &path);
472 if (st < 0) {
473 MSG_ERR("dpid: Syntax error in %s: service=\"%s\" path=\"%s\"\n",
474 dpidrc, service, path);
475 continue;
476 } else if (st != 0) {
477 continue;
478 }
479
480 _MSG("dpid: service=%s, path=%s\n", service, path);
481
482 /* ignore dpi_dir silently */
483 if (strcmp(service, "dpi_dir") == 0)
484 continue;
485
486 s = dNew(struct service, 1);
487 /* init services list entry */
488 s->name = dStrdup(service);
489 s->dp_index = -1;
490
491 dList_append(*services_list, s);
492 /* search the dpi for a service by its path */
493 for (i = 0; i < numdpis; i++)
494 if ((p = strstr(attlist[i].path, path)) && *(p - 1) == '/' &&
495 strlen(p) == strlen(path))
496 break;
497 /* if the dpi exist bind service and dpi */
498 if (i < numdpis)
499 s->dp_index = i;
500 }
501 fclose(dpidrc_stream);
502
503 dList_sort(*services_list, (dCompareFunc)services_alpha_comp);
504
505 dFree(dpidrc);
506 dFree(sys_dpidir);
507 dFree(user_dpidir);
508
509 return (dList_length(*services_list));
510 }
511
512 /*
513 * Return a socket file descriptor
514 * (useful to set socket options in a uniform way)
515 */
make_socket_fd()516 static int make_socket_fd()
517 {
518 int ret, one = 1;
519
520 if ((ret = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
521 ERRMSG("make_socket_fd", "socket", errno);
522 } else {
523 /* avoid delays when sending small pieces of data */
524 setsockopt(ret, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
525 }
526
527 /* set some buffering to increase the transfer's speed */
528 //setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF,
529 // &sock_buflen, (socklen_t)sizeof(sock_buflen));
530
531 return ret;
532 }
533
534 /*! Bind a socket port on localhost. Try to be close to base_port.
535 * \Return
536 * \li listening socket file descriptor on success
537 * \li -1 on failure
538 */
bind_socket_fd(int base_port,int * p_port)539 int bind_socket_fd(int base_port, int *p_port)
540 {
541 int sock_fd, port;
542 struct sockaddr_in sin;
543 int ok = 0, last_port = base_port + 50;
544
545 if ((sock_fd = make_socket_fd()) == -1) {
546 return (-1); /* avoids nested ifs */
547 }
548 /* Set the socket FD to close on exec */
549 fcntl(sock_fd, F_SETFD, FD_CLOEXEC | fcntl(sock_fd, F_GETFD));
550
551
552 memset(&sin, 0, sizeof(sin));
553 sin.sin_family = AF_INET;
554 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
555
556 /* Try to bind a port on localhost */
557 for (port = base_port; port <= last_port; ++port) {
558 sin.sin_port = htons(port);
559 if ((bind(sock_fd, (struct sockaddr *)&sin, sizeof(sin))) == -1) {
560 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL)
561 continue;
562 ERRMSG("bind_socket_fd", "bind", errno);
563 } else if (listen(sock_fd, QUEUE) == -1) {
564 ERRMSG("bind_socket_fd", "listen", errno);
565 } else {
566 *p_port = port;
567 ok = 1;
568 break;
569 }
570 }
571 if (port > last_port) {
572 MSG_ERR("Hey! Can't find an available port from %d to %d\n",
573 base_port, last_port);
574 }
575
576 return ok ? sock_fd : -1;
577 }
578
579 /*! Save the current port and a shared secret in a file so dillo can find it.
580 * \Return:
581 * \li -1 on failure
582 */
save_comm_keys(int srs_port)583 int save_comm_keys(int srs_port)
584 {
585 int fd, ret = -1;
586 char *fname, port_str[32];
587
588 fname = dStrconcat(dGethomedir(), "/", dotDILLO_DPID_COMM_KEYS, NULL);
589 fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
590 dFree(fname);
591 if (fd == -1) {
592 MSG("save_comm_keys: open %s\n", dStrerror(errno));
593 } else {
594 snprintf(port_str, 16, "%d %s\n", srs_port, SharedKey);
595 if (CKD_WRITE(fd, port_str) != -1 && CKD_CLOSE(fd) != -1) {
596 ret = 1;
597 }
598 }
599
600 return ret;
601 }
602
603 /*! Initialise the service request socket (IDS)
604 * \Return:
605 * \li Number of sockets (1 == success)
606 * \li -1 on failure
607 */
init_ids_srs_socket()608 int init_ids_srs_socket()
609 {
610 int srs_port, ret = -1;
611
612 FD_ZERO(&sock_set);
613
614 if ((srs_fd = bind_socket_fd(DPID_BASE_PORT, &srs_port)) != -1) {
615 /* create the shared secret */
616 SharedKey = a_Misc_mksecret(8);
617 /* save port number and SharedKey */
618 if (save_comm_keys(srs_port) != -1) {
619 FD_SET(srs_fd, &sock_set);
620 ret = 1;
621 }
622 }
623
624 return ret;
625 }
626
627 /*! Initialize a single dpi socket
628 * \Return
629 * \li 1 on success
630 * \li -1 on failure
631 */
init_dpi_socket(struct dp * dpi_attr)632 int init_dpi_socket(struct dp *dpi_attr)
633 {
634 int s_fd, port, ret = -1;
635
636 if ((s_fd = bind_socket_fd(DPID_BASE_PORT, &port)) != -1) {
637 dpi_attr->sock_fd = s_fd;
638 dpi_attr->port = port;
639 FD_SET(s_fd, &sock_set);
640 ret = 1;
641 }
642
643 return ret;
644 }
645
646 /*! Setup sockets for the plugins and add them to
647 * the set of sockets (sock_set) watched by select.
648 * \Return
649 * \li Number of sockets on success
650 * \li -1 on failure
651 * \Modifies
652 * dpi_attr_list.sa, dpi_attr_list.socket, numsocks, sock_set, srs
653 * \Uses
654 * numdpis, srs, srs_name
655 */
init_all_dpi_sockets(struct dp * dpi_attr_list)656 int init_all_dpi_sockets(struct dp *dpi_attr_list)
657 {
658 int i;
659
660 /* Initialise sockets for each dpi */
661 for (i = 0; i < numdpis; i++) {
662 if (init_dpi_socket(dpi_attr_list + i) == -1)
663 return (-1);
664 numsocks++;
665 }
666
667 return (numsocks);
668 }
669
670 /*! SIGCHLD handler
671 */
dpi_sigchld(int sig)672 void dpi_sigchld(int sig)
673 {
674 if (sig == SIGCHLD)
675 caught_sigchld = 1;
676 }
677
678 /*! Called by main loop when caught_sigchld == 1 */
handle_sigchld(void)679 void handle_sigchld(void)
680 {
681 // pid_t pid;
682 int i, status; //, num_active;
683
684 /* For all of the dpis in the current list
685 * add the ones that have exited to the set of sockets being
686 * watched by 'select'.
687 */
688 for (i = 0; i < numdpis; i++) {
689 if (waitpid(dpi_attr_list[i].pid, &status, WNOHANG) > 0) {
690 dpi_attr_list[i].pid = 1;
691 FD_SET(dpi_attr_list[i].sock_fd, &sock_set);
692 numsocks++;
693 }
694 }
695
696 /* Wait for any old dpis that have exited */
697 while (waitpid(-1, &status, WNOHANG) > 0)
698 ;
699 }
700
701 /*! Establish SIGCHLD handler */
est_dpi_sigchld(void)702 void est_dpi_sigchld(void)
703 {
704 struct sigaction sigact;
705 sigset_t set;
706
707 (void) sigemptyset(&set);
708 sigact.sa_handler = dpi_sigchld;
709 sigact.sa_mask = set;
710 sigact.sa_flags = SA_NOCLDSTOP;
711 if (sigaction(SIGCHLD, &sigact, NULL) == -1) {
712 ERRMSG("est_dpi_sigchld", "sigaction", errno);
713 exit(1);
714 }
715 }
716
717 /*! EINTR aware connect() call */
ckd_connect(int sock_fd,struct sockaddr * addr,socklen_t len)718 int ckd_connect (int sock_fd, struct sockaddr *addr, socklen_t len)
719 {
720 ssize_t ret;
721
722 do {
723 ret = connect(sock_fd, addr, len);
724 } while (ret == -1 && errno == EINTR);
725 if (ret == -1) {
726 ERRMSG("dpid.c", "connect", errno);
727 }
728 return ret;
729 }
730
731 /*! Send DpiBye command to all active non-filter dpis
732 */
stop_active_dpis(struct dp * dpi_attr_list,int numdpis)733 void stop_active_dpis(struct dp *dpi_attr_list, int numdpis)
734 {
735 char *bye_cmd, *auth_cmd;
736 int i, sock_fd;
737 struct sockaddr_in sin;
738
739 bye_cmd = a_Dpip_build_cmd("cmd=%s", "DpiBye");
740 auth_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "auth", SharedKey);
741
742 memset(&sin, 0, sizeof(sin));
743 sin.sin_family = AF_INET;
744 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
745
746 for (i = 0; i < numdpis; i++) {
747 /* Skip inactive dpis and filters */
748 if (dpi_attr_list[i].pid == 1 || dpi_attr_list[i].filter)
749 continue;
750
751 if ((sock_fd = make_socket_fd()) == -1) {
752 ERRMSG("stop_active_dpis", "socket", errno);
753 continue;
754 }
755
756 sin.sin_port = htons(dpi_attr_list[i].port);
757 if (ckd_connect(sock_fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
758 ERRMSG("stop_active_dpis", "connect", errno);
759 MSG_ERR("%s\n", dpi_attr_list[i].path);
760 } else if (CKD_WRITE(sock_fd, auth_cmd) == -1) {
761 ERRMSG("stop_active_dpis", "write", errno);
762 } else if (CKD_WRITE(sock_fd, bye_cmd) == -1) {
763 ERRMSG("stop_active_dpis", "write", errno);
764 }
765 dClose(sock_fd);
766 }
767
768 dFree(auth_cmd);
769 dFree(bye_cmd);
770
771 /* Allow child dpis some time to read dpid_comm_keys before erasing it */
772 sleep (1);
773 }
774
775 /*! Removes dpis in dpi_attr_list from the
776 * set of sockets watched by select and
777 * closes their sockets.
778 */
ignore_dpi_sockets(struct dp * dpi_attr_list,int numdpis)779 void ignore_dpi_sockets(struct dp *dpi_attr_list, int numdpis)
780 {
781 int i;
782
783 for (i = 0; i < numdpis; i++) {
784 FD_CLR(dpi_attr_list[i].sock_fd, &sock_set);
785 dClose(dpi_attr_list[i].sock_fd);
786 }
787 }
788
789 /*! Registers available dpis and stops active non-filter dpis.
790 * Called when dpid receives
791 * cmd='register' service='all'
792 * command
793 * \Return
794 * Number of available dpis
795 */
register_all_cmd()796 int register_all_cmd()
797 {
798 stop_active_dpis(dpi_attr_list, numdpis);
799 free_plugin_list(&dpi_attr_list, numdpis);
800 free_services_list(services_list);
801 services_list = NULL;
802 numdpis = 0;
803 numsocks = 1; /* the srs socket */
804 FD_ZERO(&sock_set);
805 FD_SET(srs_fd, &sock_set);
806 numdpis = register_all(&dpi_attr_list);
807 fill_services_list(dpi_attr_list, numdpis, &services_list);
808 numsocks = init_all_dpi_sockets(dpi_attr_list);
809 return (numdpis);
810 }
811
812 /*!
813 * Get value of msg field from dpi_tag
814 * \Return
815 * message on success, NULL on failure
816 */
get_message(int sock_fd,char * dpi_tag)817 char *get_message(int sock_fd, char *dpi_tag)
818 {
819 char *msg, *d_cmd;
820
821 msg = a_Dpip_get_attr(dpi_tag, "msg");
822 if (msg == NULL) {
823 ERRMSG("get_message", "failed to parse msg", 0);
824 d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
825 "DpiError", "Failed to parse request");
826 (void) CKD_WRITE(sock_fd, d_cmd);
827 dFree(d_cmd);
828 }
829 return (msg);
830 }
831
832 /*
833 * Compare a struct service pointer and a service name
834 * This function is used for searching services by name
835 */
service_match(const struct service * A,const char * B)836 int service_match(const struct service *A, const char *B)
837 {
838 int A_len, B_len, len;
839
840 A_len = strlen(A->name);
841 B_len = strlen(B);
842 len = MAX (A_len, B_len);
843
844 if (A->name[A_len - 1] == '*')
845 len = A_len - 1;
846
847 return(dStrnAsciiCasecmp(A->name, B, len));
848 }
849
850 /*!
851 * Send socket port that matches dpi_id to client
852 */
send_sockport(int sock_fd,char * dpi_tag,struct dp * dpi_attr_list)853 void send_sockport(int sock_fd, char *dpi_tag, struct dp *dpi_attr_list)
854 {
855 int i;
856 char *dpi_id, *d_cmd, port_str[16];
857 struct service *serv;
858
859 dReturn_if_fail((dpi_id = get_message(sock_fd, dpi_tag)) != NULL);
860
861 serv = dList_find_custom(services_list,dpi_id,(dCompareFunc)service_match);
862
863 if (serv == NULL || (i = serv->dp_index) == -1)
864 for (i = 0; i < numdpis; i++)
865 if (!strncmp(dpi_attr_list[i].id, dpi_id,
866 dpi_attr_list[i].id - strchr(dpi_attr_list[i].id, '.')))
867 break;
868
869 if (i < numdpis) {
870 /* found */
871 snprintf(port_str, 8, "%d", dpi_attr_list[i].port);
872 d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "send_data", port_str);
873 (void) CKD_WRITE(sock_fd, d_cmd);
874 dFree(d_cmd);
875 }
876
877 dFree(dpi_id);
878 }
879