1 /* Copyright 2001, 2002 Jeff Dike and others
2 * Copyright 2003 Renzo Davoli (modified for daemon and vde)
3 * Licensed under the GPL
4 * Modified for --pidfile/-p and better cleanup management by Mattia Belletti.
15 #include <sys/socket.h>
20 #include <sys/types.h>
40 static int daemonize
= 0;
43 void printlog(int priority
, const char *format
, ...)
47 va_start (arg
, format
);
50 vsyslog(priority
,format
,arg
);
52 fprintf(stderr
,"%s: ",prog
);
53 vfprintf(stderr
,format
,arg
);
60 enum request_type
{ REQ_NEW_CONTROL
};
62 #define SWITCH_MAGIC 0xfeedface
66 enum request_type type
;
69 unsigned char addr
[ETH_ALEN
];
70 struct sockaddr_un name
;
78 enum request_type type
;
79 struct sockaddr_un sock
;
87 static char *ctl_socket
= VDESTDSOCK
;
88 static int ctl_socket_created
= 0;
90 static char *data_socket
= NULL
;
91 static struct sockaddr_un data_sun
;
93 static char *pidfile
= NULL
;
94 static char pidfile_path
[_POSIX_PATH_MAX
];
96 static void cleanup(void)
98 if(ctl_socket_created
&& unlink(ctl_socket
) < 0){
99 printlog(LOG_WARNING
,"Couldn't remove control socket '%s' : %s", ctl_socket
, strerror(errno
));
101 if((data_socket
!= NULL
) && (unlink(data_socket
) < 0)){
102 printlog(LOG_WARNING
,"Couldn't remove data socket '%s' : %s", data_socket
, strerror(errno
));
104 if((pidfile
!= NULL
) && unlink(pidfile_path
) < 0) {
105 printlog(LOG_WARNING
,"Couldn't remove pidfile '%s': %s", pidfile
, strerror(errno
));
109 /* array of pointer to struct port */
110 void **g_fdsdata
= NULL
;
113 static struct pollfd
*fds
= NULL
;
114 static int maxfds
= 0;
117 /* adds file descriptor 'fd' to the set of file descriptors whose input we wait
118 * for in main loop */
119 static void add_fd(int fd
)
123 /* enlarge fds and g_fdsdata array if needed */
125 maxfds
= maxfds
? 2 * maxfds
: 8;
126 if((fds
= realloc(fds
, maxfds
* sizeof(struct pollfd
))) == NULL
){
127 printlog(LOG_ERR
,"realloc fds %s",strerror(errno
));
130 if((g_fdsdata
= realloc(g_fdsdata
, maxfds
* sizeof(void *))) == NULL
){
131 printlog(LOG_ERR
,"realloc fdsdata %s",strerror(errno
));
138 g_fdsdata
[nfds
]=NULL
;
143 static void remove_fd(int fd
)
147 for(i
= 0; i
< nfds
; i
++){
148 if(fds
[i
].fd
== fd
) break;
151 printlog(LOG_WARNING
,"remove_fd : Couldn't find descriptor %d", fd
);
153 memmove(&fds
[i
], &fds
[i
+ 1], (maxfds
- i
- 1) * sizeof(struct pollfd
));
154 memmove(&g_fdsdata
[i
], &g_fdsdata
[i
+ 1], (maxfds
- i
- 1) * sizeof(void *));
160 static void sig_handler(int sig
)
162 printlog(LOG_ERR
,"Caught signal %d, cleaning up and exiting", sig
);
164 signal(sig
, SIG_DFL
);
168 static void close_descriptor(int i
, int fd
)
175 static void new_port_v1_v3(int i
, int fd
, enum request_type type_group
,
176 struct sockaddr_un
*sock
, int data_fd
)
179 enum request_type type
= type_group
& 0xff;
180 int group
=type_group
>> 8;
184 case REQ_NEW_CONTROL
:
185 err
= setup_sock_port(i
, fd
, sock
, data_fd
, group
);
187 n
= write(fd
, &data_sun
, sizeof(data_sun
));
188 if(n
!= sizeof(data_sun
)){
189 printlog(LOG_WARNING
,"Sending data socket name %s",strerror(errno
));
190 close_descriptor(i
, fd
);
194 printlog(LOG_WARNING
,"Bad request type : %d", type
);
195 close_descriptor(i
, fd
);
199 static void new_port(int i
, int fd
, int data_fd
)
204 len
= read(fd
, &req
, sizeof(req
));
207 printlog(LOG_WARNING
,"Reading request %s", strerror(errno
));
208 close_descriptor(i
, fd
);
213 printlog(LOG_WARNING
,"EOF from new port");
214 close_descriptor(i
, fd
);
217 if(req
.v1
.magic
== SWITCH_MAGIC
){
218 if(req
.v3
.version
== 3)
219 new_port_v1_v3(i
,fd
, req
.v3
.type
, &req
.v3
.sock
, data_fd
);
220 else if(req
.v3
.version
> 2 || req
.v3
.version
== 2)
221 printlog(LOG_ERR
, "Request for a version %d port, which this "
222 "vde_switch doesn't support", req
.v3
.version
);
223 else new_port_v1_v3(i
, fd
, req
.v1
.type
, &req
.v1
.u
.new_control
.name
, data_fd
);
226 printlog(LOG_WARNING
,"V0 request not supported");
227 close_descriptor(i
, fd
);
232 /* accept a new connection from socket fd, then set received connection as non
233 * blocking and add it between the fds whose input we wait for */
234 void accept_connection(int fd
)
236 struct sockaddr addr
;
240 new = accept(fd
, &addr
, &len
);
242 printlog(LOG_WARNING
,"accept %s",strerror(errno
));
245 if(fcntl(new, F_SETFL
, O_NONBLOCK
) < 0){
246 printlog(LOG_WARNING
,"fcntl - setting O_NONBLOCK %s",strerror(errno
));
253 /* check to see if given unix socket is still in use; if it isn't, remove the
254 * socket from the file system */
255 int still_used(struct sockaddr_un
*sun
)
257 int test_fd
, ret
= 1;
259 if((test_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
260 printlog(LOG_ERR
,"socket %s",strerror(errno
));
263 if(connect(test_fd
, (struct sockaddr
*) sun
, sizeof(*sun
)) < 0){
264 if(errno
== ECONNREFUSED
){
265 if(unlink(sun
->sun_path
) < 0){
266 printlog(LOG_ERR
,"Failed to removed unused socket '%s': %s",
267 sun
->sun_path
,strerror(errno
));
271 else printlog(LOG_ERR
,"connect %s",strerror(errno
));
277 /* try to bind socket fd to unix socket at path name; resulting sockaddr is
278 * returned in sock_out if != NULL; returns 0 if alright, or the error
280 int bind_socket(int fd
, const char *name
, struct sockaddr_un
*sock_out
)
282 struct sockaddr_un sun
;
284 sun
.sun_family
= AF_UNIX
;
285 strncpy(sun
.sun_path
, name
, sizeof(sun
.sun_path
));
287 if(bind(fd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
288 if((errno
== EADDRINUSE
) && still_used(&sun
)) return(EADDRINUSE
);
289 else if(bind(fd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
290 printlog(LOG_ERR
,"bind %s",strerror(errno
));
294 if(sock_out
!= NULL
) *sock_out
= sun
;
299 /* bind the data socket as an unix socket in the abstract namespace (as
300 * detailed in man 7 unix), exit with error from the program if it fails.
301 * obtained sockaddr is returned in sun, which must not be NULL. */
302 void bind_data_socket(int fd
, struct sockaddr_un
*sun
)
313 gettimeofday(&tv
, NULL
);
314 name
.usecs
= tv
.tv_usec
;
315 sun
->sun_family
= AF_UNIX
;
316 memcpy(sun
->sun_path
, &name
, sizeof(name
));
317 if(bind(fd
, (struct sockaddr
*) sun
, sizeof(*sun
)) < 0){
318 printlog(LOG_ERR
,"Binding to data socket %s",strerror(errno
));
323 /* try to bind both control socket ctl_fd to file ctl_name and data socket
324 * data_fd, as detailed in bind_socket and bind_data_socket, and exit from the
325 * program with error if it can't */
326 void bind_sockets(int ctl_fd
, const char *ctl_name
, int data_fd
)
330 /* do it in advance, so we avoid race conditions */
331 ctl_socket_created
= 1;
333 err
= bind_socket(ctl_fd
, ctl_name
, NULL
);
335 bind_data_socket(data_fd
, &data_sun
);
338 else if(err
== EADDRINUSE
) used
= 1;
341 fprintf(stderr
, "The control socket '%s' has another server "
342 "attached to it\n", ctl_name
);
343 fprintf(stderr
, "You can either\n");
344 fprintf(stderr
, "\tremove '%s'\n", ctl_name
);
345 fprintf(stderr
, "\tor rerun with a different, unused filename for a "
349 fprintf(stderr
, "The control socket '%s' exists, isn't used, but couldn't "
350 "be removed\n", ctl_name
);
354 static void save_pidfile()
356 if(pidfile
[0] != '/')
357 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
));
359 strcpy(pidfile_path
, pidfile
);
361 int fd
= open(pidfile_path
,
362 O_WRONLY
| O_CREAT
| O_EXCL
,
363 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
367 printlog(LOG_ERR
, "Error in pidfile creation: %s", strerror(errno
));
371 if((f
= fdopen(fd
, "w")) == NULL
) {
372 printlog(LOG_ERR
, "Error in FILE* construction: %s", strerror(errno
));
376 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
377 printlog(LOG_ERR
, "Error in writing pidfile");
384 static void Usage(void)
387 "Usage: vde_switch [OPTIONS]\n"
388 "Runs a VDE switch.\n"
390 " -s, --sock SOCK Choose name of the control UNIX socket\n"
391 " -s, --vdesock SOCK Same as --sock SOCK\n"
392 " -s, --unix SOCK Same as --sock SOCK\n"
394 " -t, --tap TAP Enable routing through TAP tap interface\n"
396 " -d, --daemon Daemonize vde_switch once run\n"
397 " -x, --hub Make the switch act as a hub\n"
398 " -p, --pidfile PIDFILE Write pid of daemon to PIDFILE\n"
399 " -h, --help Display this help and exit\n"
400 " -v, --version Display informations on version and exit\n"
402 "Report bugs to PACKAGE_BUGREPORT\n"
407 static void version(void)
410 "VDE " PACKAGE_VERSION
"\n"
411 "Copyright (C) 2001, 2002 Jeff Dike and others\n"
412 "Copyright 2003 Renzo Davoli (modified for daemon and vde)\n"
413 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
414 "You may redistribute copies of VDE under the terms of the\n"
415 "GNU General Public License.\n"
416 "For more information about these matters, see the files\n"
421 int main(int argc
, char **argv
)
423 int connect_fd
, data_fd
, n
, i
, /*new,*/ one
= 1;
425 char *tap_dev
= NULL
;
435 int option_index
= 0;
437 static struct option long_options
[] = {
439 {"vdesock", 1, 0, 's'},
442 {"daemon", 0, 0, 'd'},
444 {"pidfile", 1, 0, 'p'},
446 {"version", 0, 0, 'v'},
449 c
= getopt_long_only (argc
, argv
, "s:t:dxp:h",
450 long_options
, &option_index
);
455 ctl_socket
=strdup(optarg
);
460 tap_dev
=strdup(optarg
);
462 fprintf(stderr
, "-tap isn't supported since TUNTAP isn't enabled\n");
467 printlog(LOG_INFO
,"s will be a hub instead of a switch", prog
);
474 pidfile
=strdup(optarg
);
488 /* connect_fd is a stream UNIX socket, whose address can be reused, and set
490 if((connect_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
491 printlog(LOG_ERR
,"socket: %s",strerror(errno
));
494 if(setsockopt(connect_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
496 printlog(LOG_ERR
,"setsockopt: %s",strerror(errno
));
499 if(fcntl(connect_fd
, F_SETFL
, O_NONBLOCK
) < 0){
500 printlog(LOG_ERR
,"Setting O_NONBLOCK on connection fd: %s",strerror(errno
));
503 /* data_fd is similar, but datagram */
504 if((data_fd
= socket(PF_UNIX
, SOCK_DGRAM
, 0)) < 0){
505 printlog(LOG_ERR
,"socket: %s",strerror(errno
));
508 if(fcntl(data_fd
, F_SETFL
, O_NONBLOCK
) < 0){
509 printlog(LOG_ERR
,"Setting O_NONBLOCK on data fd %s",strerror(errno
));
513 /* make needed binds to complete connect_fd and data_fd initialization */
514 bind_sockets(connect_fd
, ctl_socket
, data_fd
);
516 /* tell that connect_fd will be able to accept connections */
517 if(listen(connect_fd
, 15) < 0){
518 printlog(LOG_ERR
,"listen: %s",strerror(errno
));
523 /* setting signal handlers.
524 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
525 * ignores all the others signals which could cause termination. */
526 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
527 { SIGHUP
, "SIGHUP", 0 },
528 { SIGINT
, "SIGINT", 0 },
529 { SIGPIPE
, "SIGPIPE", 1 },
530 { SIGALRM
, "SIGALRM", 1 },
531 { SIGTERM
, "SIGTERM", 0 },
532 { SIGUSR1
, "SIGUSR1", 1 },
533 { SIGUSR2
, "SIGUSR2", 1 },
534 { SIGPOLL
, "SIGPOLL", 1 },
535 { SIGPROF
, "SIGPROF", 1 },
536 { SIGVTALRM
, "SIGVTALRM", 1 },
537 { SIGSTKFLT
, "SIGSTKFLT", 1 },
538 { SIGIO
, "SIGIO", 1 },
539 { SIGPWR
, "SIGPWR", 1 },
540 { SIGUNUSED
, "SIGUNUSED", 1 },
545 for(i
= 0; signals
[i
].sig
!= 0; i
++)
546 if(signal(signals
[i
].sig
,
547 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
548 printlog(LOG_ERR
,"Setting handler for %s: %s", signals
[i
].name
,
552 /* initialize ARP table */
555 /* take care about logging */
557 openlog(basename(prog
), LOG_PID
, 0);
559 syslog(LOG_INFO
,"VDE_SWITCH started");
561 printlog(LOG_INFO
,"attached to unix socket '%s'", ctl_socket
);
563 /* add stdin (if tty), connect and data fds to the set of fds we wait for
565 if(isatty(0) && ! daemonize
)
572 if(tap_dev
!= NULL
) tap_fd
= open_tap(tap_dev
);
575 setup_port(g_nfds
-1, tap_fd
, send_tap
, NULL
, 0, 0);
579 /* saves current path in pidfile_path, because otherwise with daemonize() we
581 if(getcwd(pidfile_path
, PATH_MAX
-1) == NULL
) {
582 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
585 strcat(pidfile_path
, "/");
586 if (daemonize
&& daemon(0, 1)) {
587 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
591 /* once here, we're sure we're the true process which will continue as a
592 * server: save PID file if needed */
593 if(pidfile
) save_pidfile();
595 /* main loop of events processing */
599 /* wait for some input */
600 n
= poll(fds
, nfds
, -1);
602 if(errno
== EINTR
) continue;
603 printlog(LOG_WARNING
,"poll %s",strerror(errno
));
607 /* check the input received */
608 for(i
= 0; i
< nfds
; i
++){
609 if(fds
[i
].revents
== 0) continue;
611 /* special case for standard input */
613 /* POLLHUP; e.g., pressed Ctrl+C on a non-daemonized vde_switch; thus
615 if(fds
[i
].revents
& POLLHUP
){
616 printlog(LOG_WARNING
,"EOF on stdin, cleaning up and exiting");
620 /* otherwise read data from stdin, log it, and eventually catch EOFs as
622 n
= read(0, buf
, sizeof(buf
));
624 printlog(LOG_WARNING
,"Reading from stdin %s",strerror(errno
));
628 printlog(LOG_WARNING
,"EOF on stdin, cleaning up and exiting");
633 /* special case for connect fd - is there some connection pending? */
634 else if(fds
[i
].fd
== connect_fd
){
635 if(fds
[i
].revents
& POLLHUP
){
636 printlog(LOG_WARNING
,"Error on connection fd");
639 accept_connection(connect_fd
);
642 /* data socket - ??? */
643 else if(fds
[i
].fd
== data_fd
) handle_sock_data(data_fd
, hub
);
646 /* special case for tap data */
647 else if(fds
[i
].fd
== tap_fd
) handle_tap_data(i
, tap_fd
, hub
);
650 if (g_fdsdata
[i
] == NULL
)
651 new_port(i
,fds
[i
].fd
, data_fd
);
653 if (handle_sock_direct_data(i
, fds
[i
].fd
, hub
))
654 close_descriptor(i
, fds
[i
].fd
);