[vde_switch] created vde_switch subdir and moved vde_switch inside it
[vde.git] / vde-2 / vde_switch / datasock.c
blobcc0926470d08539a7b70d89f820fa0e383cdaabb
1 /* Copyright 2005 Renzo Davoli - VDE-2
2 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004.
3 * Licensed under the GPLv2
4 * Modified by Ludovico Gardenghi 2005
5 * -g option (group management) by Daniel P. Berrange
6 * dir permission patch by Alessio Caprari 2006
7 */
9 #include <config.h>
10 #include <stdio.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <syslog.h>
16 #include <stdlib.h>
17 #include <stdint.h>
18 #include <libgen.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <sys/un.h>
25 #include <net/if.h>
26 #include <stdarg.h>
27 #include <grp.h>
28 #define _GNU_SOURCE
29 #include <getopt.h>
31 //#include <linux/if_tun.h>
33 #include <port.h>
34 #include <switch.h>
35 #include <vde.h>
36 #include <sockutils.h>
37 #include <consmgmt.h>
39 static struct swmodule swmi;
40 static struct mod_support modfun;
41 static unsigned int ctl_type;
42 static unsigned int wd_type;
43 static unsigned int data_type;
44 static int mode = 0700;
46 static char *ctl_socket;
47 static gid_t grp_owner = -1;
49 #define MODULENAME "unix prog"
51 #define DATA_BUF_SIZE 131072
52 #define SWITCH_MAGIC 0xfeedface
53 #define REQBUFLEN 256
55 enum request_type { REQ_NEW_CONTROL, REQ_NEW_PORT0 };
57 struct request_v1 {
58 uint32_t magic;
59 enum request_type type;
60 union {
61 struct {
62 unsigned char addr[ETH_ALEN];
63 struct sockaddr_un name;
64 } new_control;
65 } u;
66 char description[];
69 struct request_v3 {
70 uint32_t magic;
71 uint32_t version;
72 enum request_type type;
73 struct sockaddr_un sock;
74 char description[];
77 union request {
78 struct request_v1 v1;
79 struct request_v3 v3;
82 static int send_datasock(int fd, int ctl_fd, void *packet, int len, void *data, int port)
84 int n;
85 struct sockaddr *dst=(struct sockaddr *)data;
87 n = len - sendto(fd, packet, len, 0, dst, sizeof(struct sockaddr_un));
88 if(n){
89 int rv=errno;
90 #ifndef VDE_PQ
91 if(errno != EAGAIN) printlog(LOG_WARNING,"send_sockaddr port %d: %s",port,strerror(errno));
92 #endif
93 if (n>len)
94 return -rv;
95 else
96 return n;
98 return 0;
101 static void closeport(int fd, int portno)
103 if (fd>0)
104 remove_fd(fd);
107 static int newport(int fd, int portno)
109 int data_fd;
110 struct sockaddr_un sun;
111 #ifdef VDE_DARWIN
112 int sockbufsize = DATA_BUF_SIZE;
113 int optsize = sizeof(sockbufsize);
114 #endif
116 if((data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0){
117 printlog(LOG_ERR,"socket: %s",strerror(errno));
118 return -1;
120 if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0){
121 printlog(LOG_ERR,"Setting O_NONBLOCK on data fd %s",strerror(errno));
122 return -1;
125 #ifdef VDE_DARWIN
126 if(setsockopt(data_fd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, optsize) < 0)
127 printlog(LOG_WARNING, "Warning: setting send buffer size on data fd %d to %d failed, expect packet loss: %s",
128 data_fd, sockbufsize, strerror(errno));
129 if(setsockopt(data_fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize, optsize) < 0)
130 printlog(LOG_WARNING, "Warning: setting send buffer size on data fd %d to %d failed, expect packet loss: %s",
131 data_fd, sockbufsize, strerror(errno));
132 #endif
134 sun.sun_family = AF_UNIX;
135 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s/%03d",ctl_socket,portno);
136 if ((unlink(sun.sun_path) < 0 && errno != ENOENT) ||
137 bind(data_fd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
138 printlog(LOG_ERR,"Binding to data socket %s",strerror(errno));
139 close_ep(portno-1,fd);
140 return -1;
142 chmod(sun.sun_path,mode);
143 if(chown(sun.sun_path,-1,grp_owner) < 0) {
144 printlog(LOG_ERR, "chown: %s", strerror(errno));
145 close_ep(portno-1,fd);
146 return -1;
149 add_fd(data_fd,data_type,portno);
151 return data_fd;
154 static void *memdup(void *src,int size)
156 void *dst=malloc(size);
157 if (dst != NULL)
158 memcpy(dst,src,size);
159 return dst;
162 #define GETFILEOWNER(PATH) ({\
163 struct stat s; \
164 (stat((PATH),&s)?-1:s.st_uid); \
167 static int checksockperm(char *path,char *lpath)
169 int rvuid=0;
170 if (access(path,R_OK | W_OK) != 0)
171 return -1;
172 if (geteuid() == 0) { /* switch run by root */
173 int luid;
174 if ((rvuid=GETFILEOWNER(path)) < 0)
175 return -1;
176 luid=GETFILEOWNER(lpath);
177 if (luid > 0 && luid != rvuid) {
178 errno=EADDRINUSE;
179 return -1;
182 return rvuid;
185 static int new_port_v1_v3(int fd, int type_port,
186 struct sockaddr_un *sun_out)
188 int n, port;
189 enum request_type type = type_port & 0xff;
190 int port_request=type_port >> 8;
191 int cluid=-1;
192 struct sockaddr_un sun_in;
193 switch(type){
194 case REQ_NEW_PORT0:
195 port_request= -1;
196 /* no break: falltrough */
197 case REQ_NEW_CONTROL:
198 port = setup_ep(port_request, fd, memdup(sun_out,sizeof(struct sockaddr_un)), &modfun);
199 if(port<0) {
200 remove_fd(fd);
201 return -1;
203 sun_in.sun_family = AF_UNIX;
204 snprintf(sun_in.sun_path,sizeof(sun_in.sun_path),"%s/%03d",ctl_socket,port);
205 if (sun_out->sun_path[0] != 0) { //not for unnamed sockets
206 if ((cluid=checksockperm(sun_out->sun_path,sun_in.sun_path)) < 0) {
207 printlog(LOG_WARNING,"Data_out socket permission: %s",strerror(errno));
208 close_ep(port,fd);
209 return -1;
212 n = write(fd, &sun_in, sizeof(sun_in));
213 if(n != sizeof(sun_in)){
214 printlog(LOG_WARNING,"Sending data socket name %s",strerror(errno));
215 close_ep(port,fd);
216 return -1;
218 if (type==REQ_NEW_PORT0)
219 setmgmtperm(sun_in.sun_path);
220 else if (cluid > 0) {
221 chown(sun_in.sun_path,cluid,-1);
222 chmod(sun_in.sun_path,mode & 0700);
224 return port;
225 break;
226 default:
227 printlog(LOG_WARNING,"Bad request type : %d", type);
228 remove_fd(fd);
229 return -1;
233 static void handle_input(unsigned char type,int fd,int revents,int *arg)
235 if (type == data_type) {
236 struct bipacket packet;
237 struct sockaddr sock;
238 int len;
239 socklen_t socklen = sizeof(sock);
241 len=recvfrom(fd, &(packet.p), sizeof(struct packet),0, &sock, &socklen);
242 if(len < 0){
243 if (errno == EAGAIN) return;
244 printlog(LOG_WARNING,"Reading data: %s",strerror(errno));
246 else if(len == 0)
247 printlog(LOG_WARNING,"EOF data port: %s",strerror(errno));
248 else if(len >= ETH_HEADER_SIZE)
249 handle_in_packet(*arg, &(packet.p), len);
251 else if (type == wd_type) {
252 char reqbuf[REQBUFLEN+1];
253 union request *req=(union request *)reqbuf;
254 int len;
256 len = read(fd, reqbuf, REQBUFLEN);
257 if (len < 0) {
258 if(errno != EAGAIN){
259 printlog(LOG_WARNING,"Reading request %s", strerror(errno));
260 remove_fd(fd);
262 return;
263 } else if (len > 0) {
264 reqbuf[len]=0;
265 if(req->v1.magic == SWITCH_MAGIC){
266 int port=-1;
267 if(req->v3.version == 3) {
268 port=new_port_v1_v3(fd, req->v3.type, &(req->v3.sock));
269 if (port>=0) {
270 *arg=port;
271 setup_description(*arg,fd,strdup(req->v3.description));
274 else if(req->v3.version > 2 || req->v3.version == 2) {
275 printlog(LOG_ERR, "Request for a version %d port, which this "
276 "vde_switch doesn't support", req->v3.version);
277 remove_fd(fd);
279 else {
280 *arg=port=new_port_v1_v3(fd, req->v1.type, &(req->v1.u.new_control.name));
281 setup_description(*arg,fd,strdup(req->v1.description));
284 else {
285 printlog(LOG_WARNING,"V0 request not supported");
286 remove_fd(fd);
287 return;
289 } else {
290 if (*arg >= 0)
291 close_ep(*arg,fd);
292 else
293 remove_fd(fd);
296 else /*if (type == ctl_type)*/ {
297 struct sockaddr addr;
298 socklen_t len;
299 int new;
301 len = sizeof(addr);
302 new = accept(fd, &addr, &len);
303 if(new < 0){
304 printlog(LOG_WARNING,"accept %s",strerror(errno));
305 return;
307 if(fcntl(new, F_SETFL, O_NONBLOCK) < 0){
308 printlog(LOG_WARNING,"fcntl - setting O_NONBLOCK %s",strerror(errno));
309 close(new);
310 return;
313 add_fd(new,wd_type,-1);
317 static void cleanup(unsigned char type,int fd,int arg)
319 struct sockaddr_un clun;
320 int test_fd;
322 if (fd < 0) {
323 if((test_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
324 printlog(LOG_ERR,"socket %s",strerror(errno));
326 clun.sun_family=AF_UNIX;
327 snprintf(clun.sun_path,sizeof(clun.sun_path),"%s/ctl",ctl_socket);
328 if(connect(test_fd, (struct sockaddr *) &clun, sizeof(clun))){
329 close(test_fd);
330 if(unlink(clun.sun_path) < 0)
331 printlog(LOG_WARNING,"Couldn't remove ctl socket '%s' : %s", ctl_socket, strerror(errno));
332 else if(rmdir(ctl_socket) < 0)
333 printlog(LOG_WARNING,"Couldn't remove ctl dir '%s' : %s", ctl_socket, strerror(errno));
335 else printlog(LOG_WARNING,"cleanup not removing files");
336 } else {
337 if (type == data_type && arg>=0) {
338 snprintf(clun.sun_path,sizeof(clun.sun_path),"%s/%03d",ctl_socket,arg);
339 unlink(clun.sun_path);
341 close(fd);
345 static struct option long_options[] = {
346 {"sock", 1, 0, 's'},
347 {"vdesock", 1, 0, 's'},
348 {"unix", 1, 0, 's'},
349 {"mod", 1, 0, 'm'},
350 {"group", 1, 0, 'g'},
353 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
355 static void usage(void)
357 printf(
358 "(opts from datasock module)\n"
359 " -s, --sock SOCK control directory pathname\n"
360 " -s, --vdesock SOCK Same as --sock SOCK\n"
361 " -s, --unix SOCK Same as --sock SOCK\n"
362 " -m, --mod MODE Standard access mode for comm sockets (octal)\n"
363 " -g, --group GROUP Group owner for comm sockets\n"
367 static int parseopt(int c, char *optarg)
369 int outc=0;
370 struct group *grp;
371 switch (c) {
372 case 's':
373 ctl_socket=strdup(optarg);
374 break;
375 case 'm':
376 sscanf(optarg,"%o",&mode);
377 break;
378 case 'g':
379 if (!(grp = getgrnam(optarg))) {
380 fprintf(stderr, "No such group '%s'\n", optarg);
381 exit(1);
383 grp_owner=grp->gr_gid;
384 break;
385 default:
386 outc=c;
388 return outc;
391 static void init(void)
393 int connect_fd;
394 struct sockaddr_un sun;
395 int one = 1;
397 if((connect_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
398 printlog(LOG_ERR,"socket: %s",strerror(errno));
399 return;
401 if(setsockopt(connect_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
402 sizeof(one)) < 0){
403 printlog(LOG_ERR,"setsockopt: %s",strerror(errno));
404 return;
406 if(fcntl(connect_fd, F_SETFL, O_NONBLOCK) < 0){
407 printlog(LOG_ERR,"Setting O_NONBLOCK on connection fd: %s",strerror(errno));
408 return;
410 if (((mkdir(ctl_socket, 0777) < 0) && (errno != EEXIST))){
411 printlog(LOG_ERR,"creating vde ctl dir: %s",strerror(errno));
412 exit(-1);
414 if ((chmod(ctl_socket, 02000 | (mode & 0700 ? 0700 : 0) | (mode & 0070 ? 0070 : 0) | (mode & 0007 ? 0005 : 0)) < 0)) {
415 printlog(LOG_ERR,"setting up vde ctl dir: %s",strerror(errno));
416 exit(-1);
418 sun.sun_family = AF_UNIX;
419 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s/ctl",ctl_socket);
420 if(bind(connect_fd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
421 if((errno == EADDRINUSE) && still_used(&sun)){
422 printlog(LOG_ERR, "bind %s", strerror(errno));
423 exit(-1);
425 else if(bind(connect_fd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
426 printlog(LOG_ERR,"bind %s",strerror(errno));
427 exit(-1);
430 chmod(sun.sun_path,mode);
431 if(chown(sun.sun_path,-1,grp_owner) < 0) {
432 printlog(LOG_ERR, "chown: %s", strerror(errno));
433 exit(-1);
435 if(listen(connect_fd, 15) < 0){
436 printlog(LOG_ERR,"listen: %s",strerror(errno));
437 exit(-1);
439 ctl_type=add_type(&swmi,0);
440 wd_type=add_type(&swmi,0);
441 data_type=add_type(&swmi,1);
442 add_fd(connect_fd,ctl_type,-1);
445 static int showinfo(FILE *fd)
447 printoutc(fd,"ctl dir %s",ctl_socket);
448 printoutc(fd,"std mode 0%03o",mode);
449 return 0;
452 static struct comlist cl[]={
453 {"ds","============","DATA SOCKET MENU",NULL,NOARG},
454 {"ds/showinfo","","show ds info",showinfo,NOARG|WITHFILE},
457 static void delep (int fd, void* data, void *descr)
459 if (fd>=0) remove_fd(fd);
460 if (data) free(data);
461 if (descr) free(descr);
464 void start_datasock(void)
466 ctl_socket = (geteuid()==0)?VDESTDSOCK:VDETMPSOCK;
467 modfun.modname=swmi.swmname=MODULENAME;
468 swmi.swmnopts=Nlong_options;
469 swmi.swmopts=long_options;
470 swmi.usage=usage;
471 swmi.parseopt=parseopt;
472 swmi.init=init;
473 swmi.handle_input=handle_input;
474 swmi.cleanup=cleanup;
475 modfun.sender=send_datasock;
476 modfun.newport=newport;
477 modfun.delep=delep;
478 modfun.delport=closeport;
479 ADDCL(cl);
480 add_swm(&swmi);