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"
22 #include <sys/socket.h>
29 #include <sys/types.h>
43 #define VDESTDSOCK "/var/run/vde.ctl"
44 #define VDETMPSOCK "/tmp/vde.ctl"
50 struct sockaddr_un inpath
;
53 #define SWITCH_MAGIC 0xfeedface
56 enum request_type
{ REQ_NEW_CONTROL
, REQ_NEW_PORT0
};
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
)
70 struct passwd
*callerpwd
;
71 struct request_v3 req
;
73 static struct sockaddr_un sockun
;
74 static struct sockaddr_un dataout
;
81 if (open_args
!= NULL
) {
82 if (interface_version
== 1) {
84 group
=open_args
->group
;
93 if ((conn
=calloc(1,sizeof(struct vdeconn
)))==NULL
)
99 callerpwd
=getpwuid(getuid());
100 req
.type
= REQ_NEW_CONTROL
;
101 if (sockname
== NULL
|| *sockname
== '\0')
105 if(sockname
[strlen(sockname
)-1] == ']' && (split
=rindex(sockname
,'[')) != NULL
) {
110 req
.type
= REQ_NEW_PORT0
;
111 if (*sockname
==0) sockname
=VDESTDSOCK
;
115 if((conn
->fddata
= socket(AF_IPN
,SOCK_RAW
,IPN_ANY
)) >= 0) {
116 /* IPN service exists */
117 sockun
.sun_family
= AF_IPN
;
118 if (port
!= 0 || req
.type
== REQ_NEW_PORT0
)
119 setsockopt(conn
->fddata
,0,IPN_SO_PORT
,&port
,sizeof(port
));
120 snprintf(sockun
.sun_path
, sizeof(sockun
.sun_path
), "%s", sockname
);
121 if (connect(conn
->fddata
, (struct sockaddr
*) &sockun
, sizeof(sockun
)) == 0) {
122 snprintf(req
.description
,MAXDESCR
,"%s user=%s PID=%d %s",
123 descr
,(callerpwd
!= NULL
)?callerpwd
->pw_name
:"??",
124 pid
,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"");
125 setsockopt(conn
->fddata
,0,IPN_SO_DESCR
,req
.description
,
126 strlen(req
.description
+1));
127 *(conn
->inpath
.sun_path
)=0; /*null string, do not delete "return path"*/
133 if((conn
->fdctl
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0){
139 if((conn
->fddata
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) < 0){
146 sockun
.sun_family
= AF_UNIX
;
147 snprintf(sockun
.sun_path
, sizeof(sockun
.sun_path
), "%s/ctl", sockname
);
148 if(connect(conn
->fdctl
, (struct sockaddr
*) &sockun
, sizeof(sockun
))){
149 if (!strcmp(sockname
, VDESTDSOCK
)) {
151 snprintf(sockun
.sun_path
, sizeof(sockun
.sun_path
), "%s/ctl", sockname
);
152 if(connect(conn
->fdctl
, (struct sockaddr
*) &sockun
, sizeof(sockun
))){
153 snprintf(sockun
.sun_path
, sizeof(sockun
.sun_path
), "%s", sockname
);
154 if(connect(conn
->fdctl
, (struct sockaddr
*) &sockun
, sizeof(sockun
))){
165 req
.magic
=SWITCH_MAGIC
;
167 req
.type
=req
.type
+(port
<< 8);
168 req
.sock
.sun_family
=AF_UNIX
;
170 /* First choice, store the return socket from the switch in the control dir*/
171 memset(req
.sock
.sun_path
, 0, sizeof(req
.sock
.sun_path
));
174 sprintf(req
.sock
.sun_path
, "%s.%05d-%05d", sockname
, pid
, sockno
++);
175 res
=bind(conn
->fddata
, (struct sockaddr
*) &req
.sock
, sizeof (req
.sock
));
177 while (res
< 0 && errno
== EADDRINUSE
);
179 /* if it is not possible -> /tmp */
180 memset(req
.sock
.sun_path
, 0, sizeof(req
.sock
.sun_path
));
183 sprintf(req
.sock
.sun_path
, "/tmp/vde.%05d-%05d", pid
, sockno
++);
184 res
=bind(conn
->fddata
, (struct sockaddr
*) &req
.sock
, sizeof (req
.sock
));
186 while (res
< 0 && errno
== EADDRINUSE
);
198 memcpy(&(conn
->inpath
),&req
.sock
,sizeof(req
.sock
));
202 if ((gs
=getgrnam(group
)) == NULL
)
206 chown(conn
->inpath
.sun_path
,-1,gid
);
208 chmod(conn
->inpath
.sun_path
,mode
);
210 snprintf(req
.description
,MAXDESCR
,"%s user=%s PID=%d %s SOCK=%s",
211 descr
,(callerpwd
!= NULL
)?callerpwd
->pw_name
:"??",
212 pid
,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"",req
.sock
.sun_path
);
214 if (send(conn
->fdctl
,&req
,sizeof(req
)-MAXDESCR
+strlen(req
.description
),0) < 0) {
223 if (recv(conn
->fdctl
,&(dataout
),sizeof(struct sockaddr_un
),0)<0) {
232 if (connect(conn
->fddata
,(struct sockaddr
*)&(dataout
),sizeof(struct sockaddr_un
))<0) {
240 chmod(dataout
.sun_path
,mode
);
245 ssize_t
vde_recv(VDECONN
*conn
,void *buf
,size_t len
,int flags
)
247 if (__builtin_expect(conn
!=0,1))
248 return recv(conn
->fddata
,buf
,len
,0);
255 ssize_t
vde_send(VDECONN
*conn
,const void *buf
,size_t len
,int flags
)
257 if (__builtin_expect(conn
!=0,1))
258 return send(conn
->fddata
,buf
,len
,0);
265 int vde_datafd(VDECONN
*conn
)
267 if (__builtin_expect(conn
!=0,1))
275 int vde_ctlfd(VDECONN
*conn
)
277 if (__builtin_expect(conn
!=0,1))
285 int vde_close(VDECONN
*conn
)
287 if (__builtin_expect(conn
!=0,1)) {
288 if (*(conn
->inpath
.sun_path
))
289 unlink(conn
->inpath
.sun_path
);