some bugfixes for slirpvde
[vde.git] / vde-2 / slirpvde / slirpvde.c
blob217169e9468266dac3895ca32fe665f74d137530
1 /* Copyright 2003 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
4 */
6 #include <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <string.h>
11 #include <syslog.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <stdint.h>
15 #include <libgen.h>
16 #include <sys/ioctl.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/uio.h>
20 #include <sys/poll.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <libslirp.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <getopt.h>
27 #include <stdarg.h>
28 #include <fcntl.h>
29 #include <vde.h>
31 #define SWITCH_MAGIC 0xfeedface
32 #define BUFSIZE 2048
33 #define ETH_ALEN 6
35 int dhcpmgmt=0;
36 static char *pidfile = NULL;
37 static char pidfile_path[_POSIX_PATH_MAX];
38 int logok=0;
39 char *prog;
41 void printlog(int priority, const char *format, ...)
43 va_list arg;
45 va_start (arg, format);
47 if (logok)
48 vsyslog(priority,format,arg);
49 else {
50 fprintf(stderr,"%s: ",prog);
51 vfprintf(stderr,format,arg);
52 fprintf(stderr,"\n");
54 va_end (arg);
57 enum request_type { REQ_NEW_CONTROL };
59 #define MAXDESCR 128
61 struct request_v3 {
62 uint32_t magic;
63 uint32_t version;
64 enum request_type type;
65 struct sockaddr_un sock;
66 char description[MAXDESCR];
69 static struct sockaddr_un inpath;
71 static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int port, char *g, int m)
73 int pid = getpid();
74 struct request_v3 req;
75 int fdctl;
76 int gid;
77 struct group *gs;
78 struct passwd *callerpwd;
80 struct sockaddr_un sock;
82 callerpwd=getpwuid(getuid());
83 if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
84 perror("socket");
85 exit(1);
88 if (name == NULL)
89 name=VDESTDSOCK;
90 else {
91 char *split;
92 if(name[strlen(name)-1] == ']' && (split=rindex(name,'[')) != NULL) {
93 *split=0;
94 split++;
95 port=atoi(split);
96 if (*name==0) name=VDESTDSOCK;
100 sock.sun_family = AF_UNIX;
101 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s/ctl", name);
102 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
103 if (name == VDESTDSOCK) {
104 name=VDETMPSOCK;
105 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s/ctl", name);
106 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
107 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
108 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
109 perror("connect");
110 exit(1);
116 req.magic=SWITCH_MAGIC;
117 req.version=3;
118 req.type=REQ_NEW_CONTROL+(port << 8);
119 req.sock.sun_family=AF_UNIX;
121 /* First choice, return socket from the switch close to the control dir*/
122 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
123 sprintf(req.sock.sun_path, "%s.%05d-%02d", name, pid, 0);
124 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){
125 /* if it is not possible -> /tmp */
126 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
127 sprintf(req.sock.sun_path, "/tmp/vde.%05d-%02d", pid, 0);
128 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0) {
129 perror("bind");
130 exit(1);
134 snprintf(req.description,MAXDESCR,"slirpvde user=%s PID=%d SOCK=%s",
135 callerpwd->pw_name,pid,req.sock.sun_path);
136 memcpy(&inpath,&req.sock,sizeof(req.sock));
138 if (send(fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
139 perror("send");
140 exit(1);
143 if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) {
144 perror("recv");
145 exit(1);
148 if (g) {
149 if ((gs=getgrnam(g)) == NULL)
150 gid=atoi(g);
151 else
152 gid=gs->gr_gid;
153 chown(inpath.sun_path,-1,gid);
155 if (m>=0)
156 chmod(inpath.sun_path,m);
158 return fdctl;
161 static void save_pidfile()
163 if(pidfile[0] != '/')
164 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
165 else
166 strcpy(pidfile_path, pidfile);
168 int fd = open(pidfile_path,
169 O_WRONLY | O_CREAT | O_EXCL,
170 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
171 FILE *f;
173 if(fd == -1) {
174 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
175 exit(1);
178 if((f = fdopen(fd, "w")) == NULL) {
179 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
180 exit(1);
183 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
184 printlog(LOG_ERR, "Error in writing pidfile");
185 exit(1);
188 fclose(f);
191 static void cleanup(void)
193 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
194 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
196 unlink(inpath.sun_path);
199 static void sig_handler(int sig)
201 cleanup();
202 signal(sig, SIG_DFL);
203 kill(getpid(), sig);
206 static void setsighandlers()
208 /* setting signal handlers.
209 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
210 * ignores all the others signals which could cause termination. */
211 struct { int sig; const char *name; int ignore; } signals[] = {
212 { SIGHUP, "SIGHUP", 0 },
213 { SIGINT, "SIGINT", 0 },
214 { SIGPIPE, "SIGPIPE", 1 },
215 { SIGALRM, "SIGALRM", 1 },
216 { SIGTERM, "SIGTERM", 0 },
217 { SIGUSR1, "SIGUSR1", 1 },
218 { SIGUSR2, "SIGUSR2", 1 },
219 { SIGPROF, "SIGPROF", 1 },
220 { SIGVTALRM, "SIGVTALRM", 1 },
221 #ifdef VDE_LINUX
222 { SIGPOLL, "SIGPOLL", 1 },
223 { SIGSTKFLT, "SIGSTKFLT", 1 },
224 { SIGIO, "SIGIO", 1 },
225 { SIGPWR, "SIGPWR", 1 },
226 { SIGUNUSED, "SIGUNUSED", 1 },
227 #endif
228 #ifdef VDE_DARWIN
229 { SIGXCPU, "SIGXCPU", 1 },
230 { SIGXFSZ, "SIGXFSZ", 1 },
231 #endif
232 { 0, NULL, 0 }
235 int i;
236 for(i = 0; signals[i].sig != 0; i++)
237 if(signal(signals[i].sig,
238 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
239 perror("Setting handler");
242 unsigned char bufin[BUFSIZE];
244 int slirp_can_output(void)
246 return 1;
249 static int fddata;
250 static struct sockaddr_un dataout;
252 #if 0
253 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
254 void dumppkt(const uint8_t *pkt, int pkt_len)
256 register int i,j;
257 printf("Packet dump len=%d\n",pkt_len);
258 if (pkt_len == 0)
259 return;
260 for (i=0;i<((pkt_len-1)/16)+1;i++) {
261 for (j=0;j<16;j++)
262 if (i*16+j > pkt_len)
263 printf(" ");
264 else
265 printf("%02x ",pkt[i*16+j]);
266 printf(" ");
267 for (j=0;j<16;j++)
268 if (i*16+j > pkt_len)
269 printf(" ");
270 else
271 printf("%c",convery2ascii(pkt[i*16+j]));
272 printf("\n");
275 #endif
277 void slirp_output(const uint8_t *pkt, int pkt_len)
279 /* slirp -> vde */
280 //fprintf(stderr,"RX from slirp %d\n",pkt_len);
281 //dumppkt(pkt,pkt_len);
282 sendto(fddata,pkt,pkt_len,0,(struct sockaddr *) &dataout, sizeof(struct sockaddr_un));
285 void usage(char *name) {
286 fprintf(stderr,"Usage: %s [-socket vdesock] [-dhcp] [-daemon] [-network netaddr] \n\t%s [-s vdesock] [-D] [-d] [-n netaddr]\n",name,name);
287 exit(-1);
290 struct option slirpvdeopts[] = {
291 {"socket",1,NULL,'s'},
292 {"sock",1,NULL,'s'},
293 {"vdesock",1,NULL,'s'},
294 {"unix",1,NULL,'s'},
295 {"pidfile", 1, 0, 'p'},
296 {"dhcp",0,NULL,'D'},
297 {"daemon",0,NULL,'d'},
298 {"network",0,NULL,'n'},
299 {"mod",1,0,'m'},
300 {"group",1,0,'g'},
301 {"port",1,0,'P'},
302 {NULL,0,0,0}};
304 int main(int argc, char **argv)
306 char *sockname=NULL;
307 int result,nfds;
308 int port=0;
309 int connected_fd;
310 register ssize_t nx;
311 register int i;
312 fd_set rs,ws,xs;
313 int opt,longindx;
314 char *netw=NULL;
315 char *group=NULL;
316 int mode=0700;
317 int daemonize=0;
319 prog=basename(argv[0]);
321 while ((opt=GETOPT_LONG(argc,argv,"s:n:p:g:m:dD",slirpvdeopts,&longindx)) > 0) {
322 switch (opt) {
323 case 's' : sockname=optarg;
324 break;
325 case 'D' : dhcpmgmt = 1;
326 break;
327 case 'd' : daemonize = 1;
328 break;
329 case 'n' : netw=optarg;
330 break;
331 case 'm' : sscanf(optarg,"%o",&mode);
332 break;
333 case 'g' : group=strdup(optarg);
334 break;
335 case 'p': pidfile=strdup(optarg);
336 break;
337 case 'P' : port=atoi(optarg);
338 break;
339 default : usage(prog);
340 break;
343 atexit(cleanup);
344 if (daemonize) {
345 openlog(basename(prog), LOG_PID, 0);
346 logok=1;
347 syslog(LOG_INFO,"slirpvde started");
349 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
350 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
351 exit(1);
353 strcat(pidfile_path, "/");
354 if (daemonize && daemon(0, 1)) {
355 printlog(LOG_ERR,"daemon: %s",strerror(errno));
356 exit(1);
359 if((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
360 perror("socket");
361 exit(1);
363 connected_fd=send_fd(sockname, fddata, &dataout, port, group, mode);
364 slirp_init(netw);
366 for(;;) {
367 FD_ZERO(&rs);
368 FD_ZERO(&ws);
369 FD_ZERO(&xs);
370 nfds= -1;
371 slirp_select_fill(&nfds,&rs,&ws,&xs);
372 FD_SET(fddata,&rs);
373 FD_SET(connected_fd,&rs);
374 if (fddata>nfds) nfds=fddata;
375 if (connected_fd>nfds) nfds=connected_fd;
376 result=select(nfds+1,&rs,&ws,&xs,NULL);
377 //printf("SELECT %d %d\n",nfds,result);
378 if (FD_ISSET(fddata,&rs)) {
379 nx=recv(fddata,bufin,BUFSIZE,0);
380 //fprintf(stderr,"TX to slirp %d\n",nx);
381 result--;
382 slirp_input(bufin,nx);
383 //fprintf(stderr,"TX to slirp %d exit\n",nx);
385 if (result > 0) {
386 //fprintf(stderr,"slirp poll\n");
387 slirp_select_poll(&rs,&ws,&xs);
388 //fprintf(stderr,"slirp poll exit\n");
390 if (FD_ISSET(connected_fd,&rs)) {
391 if(read(connected_fd,bufin,BUFSIZE)==0)
392 exit(0);
395 return(0);