some ipnvde bugfixes
[vde.git] / vde-2 / libvdeplug / libvdeplug.c
blobccfea7120b635cb4e61365b58904faf83011830a
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 #undef 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 if((conn->fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
112 int err=errno;
113 free(conn);
114 errno=err;
115 return NULL;
117 #ifdef USE_IPNVDE
118 if((conn->fddata = socket(AF_IPNVDE,SOCK_RAW,IPNVDE_ANY)) >= 0) {
119 /* IPNVDE service exists */
120 sockun.sun_family = AF_IPNVDE;
121 if (port != 0)
122 setsockopt(conn->fddata,0,IPNVDE_SO_PORT,&port,sizeof(port));
123 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
124 if (connect(conn->fddata, (struct sockaddr *) &sockun, sizeof(sockun)) == 0) {
125 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s",
126 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
127 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"");
128 setsockopt(conn->fddata,0,IPNVDE_SO_DESCR,req.description,
129 strlen(req.description+1));
130 *(conn->inpath.sun_path)=0; /*null string, do not delete "return path"*/
131 return conn;
134 #endif
135 if((conn->fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
136 int err=errno;
137 close(conn->fdctl);
138 free(conn);
139 errno=err;
140 return NULL;
142 sockun.sun_family = AF_UNIX;
143 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
144 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
145 if (!strcmp(sockname, VDESTDSOCK)) {
146 sockname=VDETMPSOCK;
147 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
148 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
149 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
150 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
151 close(conn->fddata);
152 close(conn->fdctl);
153 free(conn);
154 errno=ENOENT;
155 return NULL;
161 req.magic=SWITCH_MAGIC;
162 req.version=3;
163 req.type=REQ_NEW_CONTROL+(port << 8);
164 req.sock.sun_family=AF_UNIX;
166 /* First choice, store the return socket from the switch in the control dir*/
167 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
170 sprintf(req.sock.sun_path, "%s.%05d-%05d", sockname, pid, sockno++);
171 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
173 while (res < 0 && errno == EADDRINUSE);
174 if (res < 0){
175 /* if it is not possible -> /tmp */
176 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
179 sprintf(req.sock.sun_path, "/tmp/vde.%05d-%05d", pid, sockno++);
180 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
182 while (res < 0 && errno == EADDRINUSE);
184 if (res < 0){
185 int err=errno;
186 close(conn->fddata);
187 close(conn->fdctl);
188 free(conn);
189 errno=err;
190 return NULL;
194 memcpy(&(conn->inpath),&req.sock,sizeof(req.sock));
195 if (group) {
196 struct group *gs;
197 gid_t gid;
198 if ((gs=getgrnam(group)) == NULL)
199 gid=atoi(group);
200 else
201 gid=gs->gr_gid;
202 chown(conn->inpath.sun_path,-1,gid);
204 chmod(conn->inpath.sun_path,mode);
206 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s SOCK=%s",
207 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
208 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"",req.sock.sun_path);
210 if (send(conn->fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
211 int err=errno;
212 close(conn->fddata);
213 close(conn->fdctl);
214 free(conn);
215 errno=err;
216 return NULL;
219 if (recv(conn->fdctl,&(dataout),sizeof(struct sockaddr_un),0)<0) {
220 int err=errno;
221 close(conn->fddata);
222 close(conn->fdctl);
223 free(conn);
224 errno=err;
225 return NULL;
228 if (connect(conn->fddata,(struct sockaddr *)&(dataout),sizeof(struct sockaddr_un))<0) {
229 int err=errno;
230 close(conn->fddata);
231 close(conn->fdctl);
232 free(conn);
233 errno=err;
234 return NULL;
236 chmod(dataout.sun_path,mode);
238 return conn;
241 ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags)
243 if (__builtin_expect(conn!=0,1))
244 return recv(conn->fddata,buf,len,0);
245 else {
246 errno=EBADF;
247 return -1;
251 ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags)
253 if (__builtin_expect(conn!=0,1))
254 return send(conn->fddata,buf,len,0);
255 else {
256 errno=EBADF;
257 return -1;
261 int vde_datafd(VDECONN *conn)
263 if (__builtin_expect(conn!=0,1))
264 return conn->fddata;
265 else {
266 errno=EBADF;
267 return -1;
271 int vde_ctlfd(VDECONN *conn)
273 if (__builtin_expect(conn!=0,1))
274 return conn->fdctl;
275 else {
276 errno=EBADF;
277 return -1;
281 int vde_close(VDECONN *conn)
283 if (__builtin_expect(conn!=0,1)) {
284 if (*(conn->inpath.sun_path))
285 unlink(conn->inpath.sun_path);
286 close(conn->fddata);
287 close(conn->fdctl);
288 free(conn);
289 return 0;
290 } else {
291 errno=EBADF;
292 return -1;