Port 0 management
[vde.git] / vde-2 / libvdeplug / libvdeplug.c
blobece6f9c43aab82d249a72a6262105d6354ac7960
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 /* IPN - Kernel VDE
36 #define USE_IPN
38 #ifdef USE_IPN
39 #include <af_ipn.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, REQ_NEW_PORT0 };
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 req.type = REQ_NEW_CONTROL;
101 if (sockname == NULL || *sockname == '\0')
102 sockname=VDESTDSOCK;
103 else {
104 char *split;
105 if(sockname[strlen(sockname)-1] == ']' && (split=rindex(sockname,'[')) != NULL) {
106 *split=0;
107 split++;
108 port=atoi(split);
109 if (port == 0)
110 req.type = REQ_NEW_PORT0;
111 if (*sockname==0) sockname=VDESTDSOCK;
114 #ifdef USE_IPN
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"*/
128 conn->fdctl=-1;
129 return conn;
132 #endif
133 if((conn->fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
134 int err=errno;
135 free(conn);
136 errno=err;
137 return NULL;
139 if((conn->fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
140 int err=errno;
141 close(conn->fdctl);
142 free(conn);
143 errno=err;
144 return NULL;
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)) {
150 sockname=VDETMPSOCK;
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))){
155 close(conn->fddata);
156 close(conn->fdctl);
157 free(conn);
158 errno=ENOENT;
159 return NULL;
165 req.magic=SWITCH_MAGIC;
166 req.version=3;
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);
178 if (res < 0){
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);
188 if (res < 0){
189 int err=errno;
190 close(conn->fddata);
191 close(conn->fdctl);
192 free(conn);
193 errno=err;
194 return NULL;
198 memcpy(&(conn->inpath),&req.sock,sizeof(req.sock));
199 if (group) {
200 struct group *gs;
201 gid_t gid;
202 if ((gs=getgrnam(group)) == NULL)
203 gid=atoi(group);
204 else
205 gid=gs->gr_gid;
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) {
215 int err=errno;
216 close(conn->fddata);
217 close(conn->fdctl);
218 free(conn);
219 errno=err;
220 return NULL;
223 if (recv(conn->fdctl,&(dataout),sizeof(struct sockaddr_un),0)<0) {
224 int err=errno;
225 close(conn->fddata);
226 close(conn->fdctl);
227 free(conn);
228 errno=err;
229 return NULL;
232 if (connect(conn->fddata,(struct sockaddr *)&(dataout),sizeof(struct sockaddr_un))<0) {
233 int err=errno;
234 close(conn->fddata);
235 close(conn->fdctl);
236 free(conn);
237 errno=err;
238 return NULL;
240 chmod(dataout.sun_path,mode);
242 return conn;
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);
249 else {
250 errno=EBADF;
251 return -1;
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);
259 else {
260 errno=EBADF;
261 return -1;
265 int vde_datafd(VDECONN *conn)
267 if (__builtin_expect(conn!=0,1))
268 return conn->fddata;
269 else {
270 errno=EBADF;
271 return -1;
275 int vde_ctlfd(VDECONN *conn)
277 if (__builtin_expect(conn!=0,1))
278 return conn->fdctl;
279 else {
280 errno=EBADF;
281 return -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);
290 close(conn->fddata);
291 close(conn->fdctl);
292 free(conn);
293 return 0;
294 } else {
295 errno=EBADF;
296 return -1;