bugfix:
[vde.git] / vde-2 / libvdeplug / libvdeplug.c
blob02c745da8a441030dd7752f8cfffabd6ce4fbda9
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>
33 #ifndef VDESTDSOCK
34 #define VDESTDSOCK "/var/run/vde.ctl"
35 #define VDETMPSOCK "/tmp/vde.ctl"
36 #endif
38 struct vdeconn {
39 int fdctl;
40 int fddata;
41 struct sockaddr_un inpath;
44 #define SWITCH_MAGIC 0xfeedface
45 #define MAXDESCR 128
47 enum request_type { REQ_NEW_CONTROL };
49 struct request_v3 {
50 uint32_t magic;
51 uint32_t version;
52 enum request_type type;
53 struct sockaddr_un sock;
54 char description[MAXDESCR];
57 VDECONN *vde_open_real(char *sockname,char *descr,int interface_version,
58 struct vde_open_args *open_args)
60 struct vdeconn *conn;
61 struct passwd *callerpwd;
62 struct request_v3 req;
63 int pid = getpid();
64 static struct sockaddr_un sockun;
65 static struct sockaddr_un dataout;
66 int port=0;
67 char *group=NULL;
68 int sockno=0;
69 int res;
70 mode_t mode=0700;
72 if (open_args != NULL) {
73 if (interface_version == 1) {
74 port=open_args->port;
75 group=open_args->group;
76 mode=open_args->mode;
78 else {
79 errno=EINVAL;
80 return NULL;
84 if ((conn=calloc(1,sizeof(struct vdeconn)))==NULL)
86 errno=ENOMEM;
87 return NULL;
89 //get the login name
90 callerpwd=getpwuid(getuid());
91 if((conn->fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
92 int err=errno;
93 free(conn);
94 errno=err;
95 return NULL;
97 if((conn->fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
98 int err=errno;
99 close(conn->fddata);
100 free(conn);
101 errno=err;
102 return NULL;
104 if (sockname == NULL || *sockname == NULL)
105 sockname=VDESTDSOCK;
106 else {
107 char *split;
108 if(sockname[strlen(sockname)-1] == ']' && (split=rindex(sockname,'[')) != NULL) {
109 *split=0;
110 split++;
111 port=atoi(split);
112 if (*sockname==0) sockname=VDESTDSOCK;
115 sockun.sun_family = AF_UNIX;
116 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
117 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
118 if (sockname == VDESTDSOCK) {
119 sockname=VDETMPSOCK;
120 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
121 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
122 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
123 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
124 close(conn->fddata);
125 close(conn->fdctl);
126 free(conn);
127 errno=ENOENT;
128 return NULL;
134 req.magic=SWITCH_MAGIC;
135 req.version=3;
136 req.type=REQ_NEW_CONTROL+(port << 8);
137 req.sock.sun_family=AF_UNIX;
139 /* First choice, store the return socket from the switch in the control dir*/
140 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
143 sprintf(req.sock.sun_path, "%s.%05d-%05d", sockname, pid, sockno++);
144 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
146 while (res < 0 && errno == EADDRINUSE);
147 if (res < 0){
148 /* if it is not possible -> /tmp */
149 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
152 sprintf(req.sock.sun_path, "/tmp/vde.%05d-%05d", pid, sockno++);
153 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
155 while (res < 0 && errno == EADDRINUSE);
157 if (res < 0){
158 int err=errno;
159 close(conn->fddata);
160 close(conn->fdctl);
161 free(conn);
162 errno=err;
163 return NULL;
167 memcpy(&(conn->inpath),&req.sock,sizeof(req.sock));
168 if (group) {
169 struct group *gs;
170 gid_t gid;
171 if ((gs=getgrnam(group)) == NULL)
172 gid=atoi(group);
173 else
174 gid=gs->gr_gid;
175 chown(conn->inpath.sun_path,-1,gid);
177 if (mode>=0)
178 chmod(conn->inpath.sun_path,mode);
180 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s SOCK=%s",
181 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
182 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"",req.sock.sun_path);
184 if (send(conn->fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
185 int err=errno;
186 close(conn->fddata);
187 close(conn->fdctl);
188 free(conn);
189 errno=err;
190 return NULL;
193 if (recv(conn->fdctl,&(dataout),sizeof(struct sockaddr_un),0)<0) {
194 int err=errno;
195 close(conn->fddata);
196 close(conn->fdctl);
197 free(conn);
198 errno=err;
199 return NULL;
202 if (connect(conn->fddata,(struct sockaddr *)&(dataout),sizeof(struct sockaddr_un))<0) {
203 int err=errno;
204 close(conn->fddata);
205 close(conn->fdctl);
206 free(conn);
207 errno=err;
208 return NULL;
210 chmod(dataout.sun_path,mode);
212 return conn;
215 ssize_t vde_recv(VDECONN *conn,char *buf,size_t len,int flags)
217 if (__builtin_expect(conn!=0,1))
218 return recv(conn->fddata,buf,len,0);
219 else {
220 errno=EBADF;
221 return -1;
225 ssize_t vde_send(VDECONN *conn,const char *buf,size_t len,int flags)
227 if (__builtin_expect(conn!=0,1))
228 return send(conn->fddata,buf,len,0);
229 else {
230 errno=EBADF;
231 return -1;
235 int vde_datafd(VDECONN *conn)
237 if (__builtin_expect(conn!=0,1))
238 return conn->fddata;
239 else {
240 errno=EBADF;
241 return -1;
245 int vde_ctlfd(VDECONN *conn)
247 if (__builtin_expect(conn!=0,1))
248 return conn->fdctl;
249 else {
250 errno=EBADF;
251 return -1;
255 int vde_close(VDECONN *conn)
257 if (__builtin_expect(conn!=0,1)) {
258 unlink(conn->inpath.sun_path);
259 close(conn->fddata);
260 close(conn->fdctl);
261 free(conn);
262 return 0;
263 } else {
264 errno=EBADF;
265 return -1;