1 /*-
2  * Copyright (c) 2001, 2002, 2004 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $Id: servers.c,v 1.10 2006/04/07 18:58:02 vlm Exp $
27  */
28 
29 #include "ipcad.h"
30 #include "servers.h"
31 #include "opt.h"
32 
33 server *servers_head = NULL;
34 
35 int
add_server(void * (* func)(void *),char * name,struct in_addr * ip,int hport)36 add_server(void *(*func)(void *), char *name, struct in_addr *ip, int hport) {
37 	server *srv;
38 
39 	if(!func || !name)
40 		return -1;
41 
42 	srv = (server *)calloc(1, sizeof(server));
43 	if(!srv)
44 		return -1;
45 
46 	srv->name = strdup(name);
47 	if(!srv->name) {
48 		free(srv);
49 		return -1;
50 	}
51 
52 	srv->server_func = func;
53 
54 	srv->addr.sin_family = AF_INET;
55 	if(ip) srv->addr.sin_addr = *ip;
56 	srv->addr.sin_port = htons(hport);
57 	srv->sockfd = -1;
58 
59 	srv->next = servers_head;
60 	servers_head = srv;
61 
62 	return 0;
63 }
64 
65 int
start_servers()66 start_servers() {
67 	sigset_t old_set;
68 	server *srv;
69 	int rc;
70 
71 	if(!servers_head) {
72 		if(daemon_mode)
73 		printf("No servers defined. How will you gather data? ;)\n");
74 		return 0;
75 	}
76 
77 	/*
78 	 * Do not allow other threads receive signals for the main thread.
79 	 * The signal mask is inherited from the creating thread.
80 	 */
81 	block_certain_signals(&old_set);
82 
83 	/* Iterate through defined servers */
84 	for(srv = servers_head; srv; srv=srv->next) {
85 		if(srv->started_ok)
86 			continue;
87 
88 		rc = pthread_create(&srv->thid, NULL, srv->server_func, (void *)srv);
89 
90 		if(rc == 0) {
91 			/* Wait for thread to terminate or report success */
92 			while(
93 				(pthread_kill(srv->thid, 0) == 0)
94 				&& (srv->started_ok == 0)
95 			) {
96 #ifdef	HAVE_SCHED_YIELD
97 				sched_yield();
98 #else
99 				sleep(1);
100 #endif
101 			}
102 			if(!srv->started_ok)
103 				rc = -1;
104 		}
105 
106 		/* Failed to create particular server */
107 		if(rc == -1) {
108 			srv->thid = 0;
109 
110 			/* Terminate previously started servers */
111 			end_servers();
112 			sigprocmask(SIG_SETMASK, &old_set, NULL);
113 			return -1;
114 		}
115 
116 		printf("%s thread %lu started.\n",
117 			srv->name, (long)srv->thid);
118 
119 	}
120 
121 	sigprocmask(SIG_SETMASK, &old_set, NULL);
122 
123 	return 0;
124 }
125 
126 void
end_servers_r(server * srv)127 end_servers_r(server *srv) {
128 	if(!srv)
129 		return;
130 
131 	if(srv->next)
132 		end_servers_r(srv->next);
133 
134 	/* If alive */
135 	if(srv->thid && srv->started_ok) {
136 
137 		/* Kick it */
138 		pthread_kill(srv->thid, SIGALRM);
139 
140 		printf("Waiting for %s thread to terminate... ",
141 			srv->name);
142 		fflush(stdout);
143 
144 		pthread_join(srv->thid, NULL);
145 		printf("DONE.\n");
146 
147 	}	/* if(thid) */
148 
149 	free(srv);
150 }
151 
152 
153 void
end_servers()154 end_servers() {
155 	sig_atomic_t tmps;
156 
157 	/* Remember value */
158 	tmps = signoff_now;
159 
160 	/* Enable global signoff flag */
161 	signoff_now = 1;
162 
163 	/* Terminate working servers */
164 	end_servers_r(servers_head);
165 
166 	servers_head = NULL;
167 
168 	/* Restore previous value */
169 	signoff_now = tmps;
170 }
171