Indent
[bcusdk.git] / eibd / server / eibd.cpp
blob2028656dc1449dbe6a2f70e8693a0ac9a71a30ba
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2007 Martin Kögler <mkoegler@auto.tuwien.ac.at>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <argp.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include "layer3.h"
28 #include "localserver.h"
29 #include "inetserver.h"
30 #include "eibnetserver.h"
31 #include "groupcacheclient.h"
33 /** structure to store the arguments */
34 struct arguments
36 /** port to listen */
37 int port;
38 /** path for unix domain socket */
39 const char *name;
40 /** path to pid file */
41 const char *pidfile;
42 /** path to trace log file */
43 const char *daemon;
44 /** trace level */
45 int tracelevel;
46 /** EIB address (for some backends) */
47 eibaddr_t addr;
48 /* EIBnet/IP server */
49 bool tunnel;
50 bool route;
51 bool discover;
52 bool groupcache;
53 const char *serverip;
55 /** storage for the arguments*/
56 struct arguments arg;
58 /** aborts program with a printf like message */
59 void
60 die (const char *msg, ...)
62 va_list ap;
63 va_start (ap, msg);
64 vprintf (msg, ap);
65 printf ("\n");
66 va_end (ap);
68 if (arg.pidfile)
69 unlink (arg.pidfile);
71 exit (1);
75 #include "layer2conf.h"
77 /** structure to store layer 2 backends */
78 struct urldef
80 /** URL-prefix */
81 const char *prefix;
82 /** factory function */
83 Layer2_Create_Func Create;
86 /** list of URLs */
87 struct urldef URLs[] = {
88 #undef L2_NAME
89 #define L2_NAME(a) { a##_PREFIX, a##_CREATE },
90 #include "layer2create.h"
91 {0, 0}
94 /** determines the right backend for the url and creates it */
95 Layer2Interface *
96 Create (const char *url, Trace * t)
98 unsigned int p = 0;
99 struct urldef *u = URLs;
100 while (url[p] && url[p] != ':')
101 p++;
102 if (url[p] != ':')
103 die ("not a valid url");
104 while (u->prefix)
106 if (strlen (u->prefix) == p && !memcmp (u->prefix, url, p))
108 return u->Create (url + p + 1, t);
110 u++;
112 die ("url not supported");
113 return 0;
116 /** parses an EIB individual address */
117 eibaddr_t
118 readaddr (const char *addr)
120 int a, b, c;
121 sscanf (addr, "%d.%d.%d", &a, &b, &c);
122 return ((a & 0x0f) << 12) | ((b & 0x0f) << 8) | ((c & 0xff));
125 /** version */
126 const char *argp_program_version = "eibd " VERSION;
127 /** documentation */
128 static char doc[] =
129 "eibd -- a commonication stack for EIB\n"
130 "(C) 2005-2007 Martin Kögler <mkoegler@auto.tuwien.ac.at>\n"
131 "supported URLs are:\n"
132 #undef L2_NAME
133 #define L2_NAME(a) a##_URL
134 #include "layer2create.h"
135 "\n"
136 #undef L2_NAME
137 #define L2_NAME(a) a##_DOC
138 #include "layer2create.h"
139 "\n";
141 /** documentation for arguments*/
142 static char args_doc[] = "URL";
144 /** option list */
145 static struct argp_option options[] = {
146 {"listen-tcp", 'i', "PORT", OPTION_ARG_OPTIONAL,
147 "listen at TCP port PORT (default 6720)"},
148 {"listen-local", 'u', "FILE", OPTION_ARG_OPTIONAL,
149 "listen at Unix domain socket FILE (default /tmp/eib)"},
150 {"trace", 't', "LEVEL", 0, "set trace level"},
151 {"eibaddr", 'e', "EIBADDR", 0,
152 "set our own EIB-address to EIBADDR (default 0.0.1), for drivers, which need an address"},
153 {"pid-file", 'p', "FILE", 0, "write the PID of the process to FILE"},
154 {"daemon", 'd', "FILE", OPTION_ARG_OPTIONAL,
155 "start the programm as daemon, the output will be written to FILE, if the argument present"},
156 #ifdef HAVE_EIBNETIPSERVER
157 {"Tunnelling", 'T', 0, 0,
158 "enable EIBnet/IP Tunneling in the EIBnet/IP server"},
159 {"Routing", 'R', 0, 0, "enable EIBnet/IP Routing in the EIBnet/IP server"},
160 {"Discovery", 'D', 0, 0,
161 "enable the EIBnet/IP server to answer discovery and description requests (SEARCH, DESCRIPTION)"},
162 {"Server", 'S', "ip[:port]", OPTION_ARG_OPTIONAL,
163 "starts the EIBnet/IP server part"},
164 #endif
165 #ifdef HAVE_GROUPCACHE
166 {"GroupCache", 'c', 0, 0,
167 "enable caching of group communication network state"},
168 #endif
172 /** parses and stores an option */
173 static error_t
174 parse_opt (int key, char *arg, struct argp_state *state)
176 struct arguments *arguments = (struct arguments *) state->input;
177 switch (key)
179 case 'T':
180 arguments->tunnel = 1;
181 break;
182 case 'R':
183 arguments->route = 1;
184 break;
185 case 'D':
186 arguments->discover = 1;
187 break;
188 case 'S':
189 arguments->serverip = (arg ? arg : "224.0.23.12");
190 break;
191 case 'u':
192 arguments->name = (char *) (arg ? arg : "/tmp/eib");
193 break;
194 case 'i':
195 arguments->port = (arg ? atoi (arg) : 6720);
196 break;
197 case 't':
198 arguments->tracelevel = (arg ? atoi (arg) : 0);
199 break;
200 case 'e':
201 arguments->addr = readaddr (arg);
202 break;
203 case 'p':
204 arguments->pidfile = arg;
205 break;
206 case 'd':
207 arguments->daemon = (char *) (arg ? arg : "/dev/null");
208 break;
209 case 'c':
210 arguments->groupcache = 1;
211 break;
212 default:
213 return ARGP_ERR_UNKNOWN;
215 return 0;
218 /** information for the argument parser*/
219 static struct argp argp = { options, parse_opt, args_doc, doc };
221 #ifdef HAVE_EIBNETIPSERVER
222 EIBnetServer *
223 startServer (Layer3 * l3, Trace * t)
225 EIBnetServer *c;
226 char *ip;
227 int port;
228 if (!arg.serverip)
229 return 0;
231 char *a = strdup (arg.serverip);
232 char *b;
233 if (!a)
234 die ("out of memory");
235 for (b = a; *b; b++)
236 if (*b == ':')
237 break;
238 if (*b == ':')
240 *b = 0;
241 port = atoi (b + 1);
243 else
244 port = 3671;
245 c = new EIBnetServer (a, port, arg.tunnel, arg.route, arg.discover, l3, t);
246 free (a);
247 return c;
249 #endif
252 main (int ac, char *ag[])
254 int index;
255 Queue < Server * >server;
256 Layer2Interface *l2;
257 Layer3 *l3;
258 #ifdef HAVE_EIBNETIPSERVER
259 EIBnetServer *serv = 0;
260 #endif
262 memset (&arg, 0, sizeof (arg));
263 arg.addr = 0x0001;
265 argp_parse (&argp, ac, ag, 0, &index, &arg);
266 if (index > ac - 1)
267 die ("url expected");
268 if (index < ac - 1)
269 die ("unexpected parameter");
271 if (arg.port == 0 && arg.name == 0 && arg.serverip == 0)
272 die ("No listen-address given");
274 signal (SIGPIPE, SIG_IGN);
275 pth_init ();
277 Trace t;
278 t.SetTraceLevel (arg.tracelevel);
280 if (arg.daemon)
282 int fd = open (arg.daemon, O_WRONLY | O_APPEND | O_CREAT);
283 if (fd == -1)
284 die ("Can not open file %s", arg.daemon);
285 int i = fork ();
286 if (i < 0)
287 die ("fork failed");
288 if (i > 0)
289 exit (0);
290 close (1);
291 close (2);
292 close (0);
293 dup2 (fd, 1);
294 dup2 (fd, 2);
295 setsid ();
299 FILE *pidf;
300 if (arg.pidfile)
301 if ((pidf = fopen (arg.pidfile, "w")) != NULL)
303 fprintf (pidf, "%d", getpid ());
304 fclose (pidf);
309 l2 = Create (ag[index], &t);
310 l3 = new Layer3 (l2, &t);
311 if (arg.port)
312 server.put (new InetServer (l3, &t, arg.port));
313 if (arg.name)
314 server.put (new LocalServer (l3, &t, arg.name));
315 #ifdef HAVE_EIBNETIPSERVER
316 serv = startServer (l3, &t);
317 #endif
318 #ifdef HAVE_GROUPCACHE
319 CreateGroupCache (l3, &t, arg.groupcache);
320 #endif
322 catch (Exception e)
324 die ("initialisation failed");
327 sigset_t t1;
328 sigemptyset (&t1);
329 sigaddset (&t1, SIGINT);
330 sigaddset (&t1, SIGTERM);
331 signal (SIGINT, SIG_IGN);
332 signal (SIGTERM, SIG_IGN);
334 int x;
335 pth_sigwait (&t1, &x);
337 signal (SIGINT, SIG_DFL);
338 signal (SIGTERM, SIG_DFL);
340 while (!server.isempty ())
341 delete server.get ();
342 #ifdef HAVE_EIBNETIPSERVER
343 if (serv)
344 delete serv;
345 #endif
346 #ifdef HAVE_GROUPCACHE
347 DeleteGroupCache ();
348 #endif
350 delete l3;
352 if (arg.pidfile)
353 unlink (arg.pidfile);
355 pth_exit (0);
356 return 0;