bugfix (fdctl is not used)
[vde.git] / vde-2 / libvdeplug / libvdeplug.c
blob3e00c7f809ce59dc76e170436f5aee5adcc1dd63
1 /*
2 * libvdeplug - A library to connect to a VDE Switch.
3 * Copyright (C) 2006 Renzo Davoli, University of Bologna
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation version 2.1 of the License, or (at
8 * your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "libvdeplug.h"
21 #include <errno.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pwd.h>
28 #include <grp.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <string.h>
34 /* IPNVDE - Kernel VDE
36 #define USE_IPNVDE
38 #ifdef USE_IPNVDE
39 #include <af_ipnvde.h>
40 #endif
42 #ifndef VDESTDSOCK
43 #define VDESTDSOCK "/var/run/vde.ctl"
44 #define VDETMPSOCK "/tmp/vde.ctl"
45 #endif
47 struct vdeconn {
48 int fdctl;
49 int fddata;
50 struct sockaddr_un inpath;
53 #define SWITCH_MAGIC 0xfeedface
54 #define MAXDESCR 128
56 enum request_type { REQ_NEW_CONTROL };
58 struct request_v3 {
59 uint32_t magic;
60 uint32_t version;
61 enum request_type type;
62 struct sockaddr_un sock;
63 char description[MAXDESCR];
66 VDECONN *vde_open_real(char *sockname,char *descr,int interface_version,
67 struct vde_open_args *open_args)
69 struct vdeconn *conn;
70 struct passwd *callerpwd;
71 struct request_v3 req;
72 int pid = getpid();
73 static struct sockaddr_un sockun;
74 static struct sockaddr_un dataout;
75 int port=0;
76 char *group=NULL;
77 int sockno=0;
78 int res;
79 mode_t mode=0700;
81 if (open_args != NULL) {
82 if (interface_version == 1) {
83 port=open_args->port;
84 group=open_args->group;
85 mode=open_args->mode;
87 else {
88 errno=EINVAL;
89 return NULL;
93 if ((conn=calloc(1,sizeof(struct vdeconn)))==NULL)
95 errno=ENOMEM;
96 return NULL;
98 //get the login name
99 callerpwd=getpwuid(getuid());
100 if (sockname == NULL || *sockname == '\0')
101 sockname=VDESTDSOCK;
102 else {
103 char *split;
104 if(sockname[strlen(sockname)-1] == ']' && (split=rindex(sockname,'[')) != NULL) {
105 *split=0;
106 split++;
107 port=atoi(split);
108 if (*sockname==0) sockname=VDESTDSOCK;
111 #ifdef USE_IPNVDE
112 if((conn->fddata = socket(AF_IPNVDE,SOCK_RAW,IPNVDE_ANY)) >= 0) {
113 /* IPNVDE service exists */
114 sockun.sun_family = AF_IPNVDE;
115 if (port != 0)
116 setsockopt(conn->fddata,0,IPNVDE_SO_PORT,&port,sizeof(port));
117 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
118 if (connect(conn->fddata, (struct sockaddr *) &sockun, sizeof(sockun)) == 0) {
119 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s",
120 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
121 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"");
122 setsockopt(conn->fddata,0,IPNVDE_SO_DESCR,req.description,
123 strlen(req.description+1));
124 *(conn->inpath.sun_path)=0; /*null string, do not delete "return path"*/
125 conn->fdctl=-1;
126 return conn;
129 #endif
130 if((conn->fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
131 int err=errno;
132 free(conn);
133 errno=err;
134 return NULL;
136 if((conn->fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
137 int err=errno;
138 close(conn->fdctl);
139 free(conn);
140 errno=err;
141 return NULL;
143 sockun.sun_family = AF_UNIX;
144 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
145 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
146 if (!strcmp(sockname, VDESTDSOCK)) {
147 sockname=VDETMPSOCK;
148 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
149 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
150 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
151 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
152 close(conn->fddata);
153 close(conn->fdctl);
154 free(conn);
155 errno=ENOENT;
156 return NULL;
162 req.magic=SWITCH_MAGIC;
163 req.version=3;
164 req.type=REQ_NEW_CONTROL+(port << 8);
165 req.sock.sun_family=AF_UNIX;
167 /* First choice, store the return socket from the switch in the control dir*/
168 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
171 sprintf(req.sock.sun_path, "%s.%05d-%05d", sockname, pid, sockno++);
172 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
174 while (res < 0 && errno == EADDRINUSE);
175 if (res < 0){
176 /* if it is not possible -> /tmp */
177 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
180 sprintf(req.sock.sun_path, "/tmp/vde.%05d-%05d", pid, sockno++);
181 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
183 while (res < 0 && errno == EADDRINUSE);
185 if (res < 0){
186 int err=errno;
187 close(conn->fddata);
188 close(conn->fdctl);
189 free(conn);
190 errno=err;
191 return NULL;
195 memcpy(&(conn->inpath),&req.sock,sizeof(req.sock));
196 if (group) {
197 struct group *gs;
198 gid_t gid;
199 if ((gs=getgrnam(group)) == NULL)
200 gid=atoi(group);
201 else
202 gid=gs->gr_gid;
203 chown(conn->inpath.sun_path,-1,gid);
205 chmod(conn->inpath.sun_path,mode);
207 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s SOCK=%s",
208 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
209 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"",req.sock.sun_path);
211 if (send(conn->fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
212 int err=errno;
213 close(conn->fddata);
214 close(conn->fdctl);
215 free(conn);
216 errno=err;
217 return NULL;
220 if (recv(conn->fdctl,&(dataout),sizeof(struct sockaddr_un),0)<0) {
221 int err=errno;
222 close(conn->fddata);
223 close(conn->fdctl);
224 free(conn);
225 errno=err;
226 return NULL;
229 if (connect(conn->fddata,(struct sockaddr *)&(dataout),sizeof(struct sockaddr_un))<0) {
230 int err=errno;
231 close(conn->fddata);
232 close(conn->fdctl);
233 free(conn);
234 errno=err;
235 return NULL;
237 chmod(dataout.sun_path,mode);
239 return conn;
242 ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags)
244 if (__builtin_expect(conn!=0,1))
245 return recv(conn->fddata,buf,len,0);
246 else {
247 errno=EBADF;
248 return -1;
252 ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags)
254 if (__builtin_expect(conn!=0,1))
255 return send(conn->fddata,buf,len,0);
256 else {
257 errno=EBADF;
258 return -1;
262 int vde_datafd(VDECONN *conn)
264 if (__builtin_expect(conn!=0,1))
265 return conn->fddata;
266 else {
267 errno=EBADF;
268 return -1;
272 int vde_ctlfd(VDECONN *conn)
274 if (__builtin_expect(conn!=0,1))
275 return conn->fdctl;
276 else {
277 errno=EBADF;
278 return -1;
282 int vde_close(VDECONN *conn)
284 if (__builtin_expect(conn!=0,1)) {
285 if (*(conn->inpath.sun_path))
286 unlink(conn->inpath.sun_path);
287 close(conn->fddata);
288 close(conn->fdctl);
289 free(conn);
290 return 0;
291 } else {
292 errno=EBADF;
293 return -1;