loadlwipv6 inlined
[vde.git] / vde-2 / src / lib / libvdemgmt.c
blobd9b805715f115aebc67a4b5de0fb073250e53700
1 /*
2 * Copyright (C) 2007 - Luca Bigliardi
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #define _GNU_SOURCE
19 #include <string.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
27 #include <config.h>
28 #include <vde.h>
29 #include <vdecommon.h>
31 #include <libvdemgmt.h>
34 #define OPENMACHINE_RC INSTALLPATH"/etc/vde2/libvdemgmt/openmachine.rc"
35 #define CLOSEMACHINE_RC INSTALLPATH"/etc/vde2/libvdemgmt/closemachine.rc"
36 #define SENDCMD_RC INSTALLPATH"/etc/vde2/libvdemgmt/sendcmd.rc"
37 #define ASYNCRECV_RC INSTALLPATH"/etc/vde2/libvdemgmt/asyncrecv.rc"
39 #define DEBUGADD "debug/add"
40 #define DEBUGDEL "debug/del"
42 #define CHECK(expr, errval) { char errstr[1024]; if ((expr) == (errval)) { sprintf(errstr, "%s %d %d", __func__, __LINE__, (int)errval); goto error; } }
43 #define CHECKNOT(expr, errval) { char errstr[1024]; if ((expr) != (errval)) { sprintf(errstr, "%s %d %d", __func__, __LINE__, (int)errval); perror(errstr); goto error; } }
46 #define DATATAG 1
47 #define ASYNTAG 3
49 #define SKIPHEAD 5
51 #define DBGM 0
53 static struct utm* open_utm=NULL;
54 static struct utm* close_utm=NULL;
55 static struct utm* sendcmd_utm=NULL;
56 static struct utm* asyncrecv_utm=NULL;
58 struct asynctab {
59 const char *event;
60 void (*callback)(const char *event, const int tag, const char *data);
61 struct asynctab *next;
64 struct vdemgmt {
65 int fd;
66 struct asynctab *atab;
67 struct utm_buf *pbuf;
68 const char *banner;
69 const char *prompt;
70 const char *version;
74 * INTERNAL
77 struct asynctab *atab_find(struct asynctab *atab, const char *event)
79 if(!atab) return atab;
81 if(!strncmp(atab->event, event, strlen(atab->event))) return atab;
82 else return atab_find(atab->next, event);
86 struct asynctab *atab_add(struct asynctab *atab, struct asynctab *new)
88 if(!atab){
89 new->next=atab;
90 return new;
91 }else{
92 atab->next=atab_add(atab->next, new);
93 return atab;
97 struct asynctab *atab_del(struct asynctab *atab, const char *event)
99 if(!atab) return atab;
101 if(!strncmp(atab->event, event, strlen(atab->event))){
102 struct asynctab *t=atab->next;
103 free(atab);
104 return t;
105 } else {
106 atab->next=atab_del(atab->next, event);
107 return atab;
111 static int qstrcmp(const void *a,const void *b)
113 return strcmp(*(char * const *)a,*(char * const *)b);
118 * INTERFACE
121 /* open vdemgmt connection */
122 struct vdemgmt *vdemgmt_open(const char *path)
125 struct sockaddr_un sun;
126 struct vdemgmt *conn = NULL;
127 struct utm_out *out;
128 int myargc=0;
129 char *myargv = NULL, *sep;
131 if(!open_utm)
132 CHECK( open_utm = utm_alloc(OPENMACHINE_RC) , NULL );
133 if(!close_utm)
134 CHECK( close_utm = utm_alloc(CLOSEMACHINE_RC) , NULL );
135 if(!sendcmd_utm)
136 CHECK( sendcmd_utm = utm_alloc(SENDCMD_RC) , NULL );
137 if(!asyncrecv_utm)
138 CHECK( asyncrecv_utm = utm_alloc(ASYNCRECV_RC) , NULL );
140 /* vdemgmt connection struct */
141 CHECK( conn = (struct vdemgmt*)malloc(sizeof(struct vdemgmt)) , NULL );
142 memset(conn, 0, sizeof(struct vdemgmt));
143 CHECK( conn->pbuf = (struct utm_buf*)malloc(sizeof(struct utm_buf)) , NULL );
144 memset(conn->pbuf, 0, sizeof(struct utm_buf));
146 /* connect to management socket (non block fd) */
147 sun.sun_family=PF_UNIX;
148 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s", path);
149 conn->fd = socket(PF_UNIX,SOCK_STREAM,0);
150 CHECK( fcntl(conn->fd, F_SETFL, O_NONBLOCK) , -1 );
151 CHECK( connect(conn->fd,(struct sockaddr *)(&sun),sizeof(sun)) , -1 );
153 conn->atab = NULL;
155 /* get welcome data */
156 out=utmout_alloc();
157 CHECK( utm_run(open_utm,conn->pbuf,conn->fd,myargc,&myargv,out,DBGM), -1 );
159 /* split banner / prompt and extract version */
160 for( sep=out->buf+out->sz ; ! strstr(sep, "\n") ; sep--);
161 conn->banner = strndup(out->buf, sep - out->buf-1);
162 conn->prompt = strndup(sep+1, (out->buf+out->sz)-sep+1);
163 sep=strstr(conn->banner, "V.")+2;
164 conn->version = strndup(sep, strstr(sep, "\n")-sep);
166 utmout_free(out);
168 return conn;
170 error:
171 if(conn){
172 if(conn->pbuf){
173 if(conn->pbuf->buf)
174 free(conn->pbuf->buf);
175 free(conn->pbuf);
177 if(conn->fd)
178 close(conn->fd);
179 free(conn);
181 return NULL;
184 /* close vdemgmt connection */
185 void vdemgmt_close(struct vdemgmt *conn)
188 int myargc=0;
189 char *myargv = NULL;
190 struct utm_out *out;
192 /* Deactivate all async events */
193 while(conn->atab) vdemgmt_asyncunreg(conn, conn->atab->event);
195 /* logout */
196 out=utmout_alloc();
197 utm_run(close_utm,conn->pbuf,conn->fd,myargc,&myargv,out,DBGM);
198 utmout_free(out);
200 close(conn->fd);
201 if(conn->pbuf->buf)
202 free(conn->pbuf->buf);
203 free(conn->pbuf);
204 free((char *)conn->banner);
205 free((char *)conn->prompt);
206 free((char *)conn->version);
207 free(conn);
210 /* return file descriptor of vdemgmt connection */
211 int vdemgmt_getfd(struct vdemgmt *conn)
213 if(conn)
214 return conn->fd;
215 else
216 return -1;
219 /* send command cmd and wait for its output */
220 int vdemgmt_sendcmd(struct vdemgmt *conn, const char *cmd, struct vdemgmt_out *out)
223 int rv=-1, myargc=0;
224 char *token, *dupcmd, **myargv = NULL;
225 struct utm_out *utmout, *p;
226 struct asynctab *t=NULL;
228 /* create myargv array from cmd */
229 for( dupcmd=strdup(cmd) ; ; dupcmd=NULL){
230 token = strtok(dupcmd, " ");
231 myargv=realloc(myargv, (myargc+1)*sizeof(char *));
232 if(!myargv) exit(1);
233 myargv[myargc]=token;
234 if( !token ) break;
235 myargc++;
238 /* send command using machine */
239 utmout=utmout_alloc();
240 rv=utm_run(sendcmd_utm,conn->pbuf,conn->fd,myargc,myargv,utmout,DBGM);
242 /* scan machine data for sync and async output */
243 p=utmout;
244 while(p) {
245 if( (p->tag == DATATAG) && out) {
246 out->sz = p->sz;
247 out->buf=(char *)malloc(p->sz*sizeof(char));
248 if(!out->buf) { perror(__func__); exit(-1);}
249 memcpy(out->buf, p->buf, p->sz);
251 if( p->tag == ASYNTAG ){
252 t=atab_find(conn->atab, p->buf+SKIPHEAD);
253 if(t) t->callback(t->event, rv, p->buf+strlen(t->event)+SKIPHEAD+1);
255 p=p->next;
258 utmout_free(utmout);
260 return rv;
263 /* free outbuffer returned by vdemgmt_sendcmd */
264 void vdemgmt_freeout(struct vdemgmt_out *out)
266 if(out){
267 if(out->buf) free(out->buf);
268 free(out);
272 /* reset outbuffer after vdemgmt_sendcmd, */
273 void vdemgmt_rstout(struct vdemgmt_out *out)
275 if(out){
276 if(out->buf) free(out->buf);
277 out->buf = NULL;
278 out->sz = 0;
282 /* register func as handler for asyncronous output received with command cmd */
283 int vdemgmt_asyncreg(struct vdemgmt *conn, const char *event, void (*callback)(const char *event, const int tag, const char *data) )
286 struct asynctab *new = NULL;
287 char *swcmd = NULL;
288 int rv=-1;
290 if( atab_find(conn->atab, event) ) return rv;
292 /* Activate debug */
293 CHECK( asprintf(&swcmd,"%s %s",DEBUGADD,event) , -1 );
294 CHECKNOT( rv=vdemgmt_sendcmd(conn, swcmd , NULL) , 0);
295 free(swcmd); swcmd=NULL;
297 /* Add callback function to connection's async tab */
298 CHECK( new = (struct asynctab*)malloc(sizeof(struct asynctab)) , NULL );
299 memset(new, 0, sizeof(struct asynctab));
300 new->event = strdup(event);
301 new->callback = callback;
302 new->next = NULL;
303 conn->atab=atab_add(conn->atab, new);
305 return 0;
307 error:
308 if(swcmd) free(swcmd);
309 return rv;
312 /* unregister asyncronous output callback for command cmd */
313 void vdemgmt_asyncunreg(struct vdemgmt *conn, const char *event)
315 char *swcmd = NULL;
317 /* Dectivate debug on switch */
318 CHECK( asprintf(&swcmd,"%s %s",DEBUGDEL,event) , -1 );
319 CHECKNOT( vdemgmt_sendcmd(conn, swcmd , NULL) , 0);
321 error:
322 if(swcmd) free(swcmd);
323 conn->atab=atab_del(conn->atab, event);
326 /* handle asyncronous output */
327 void vdemgmt_asyncrecv(struct vdemgmt *conn)
329 int myargc=0;
330 int prevpos=0;
331 int outtag=0;
332 char *myargv=NULL;
333 struct utm_out *out;
334 struct asynctab *t;
336 out=utmout_alloc();
338 /* run async machine and call the handler for the event */
339 do {
340 outtag=utm_run(asyncrecv_utm,conn->pbuf,conn->fd,myargc,&myargv,out,DBGM);
341 CHECK( outtag, -1 );
342 t=atab_find(conn->atab, out->buf+SKIPHEAD);
343 if(t) t->callback(t->event, outtag, out->buf+strlen(t->event)+SKIPHEAD+1+prevpos);
344 prevpos = conn->pbuf->pos;
345 free(out->buf) ; out->buf = NULL ; out->sz = 0;
346 } while ( conn->pbuf->len > conn->pbuf->pos );
348 error:
349 utmout_free(out);
353 const char *vdemgmt_getbanner(struct vdemgmt *conn)
355 return conn->banner;
358 const char *vdemgmt_getprompt(struct vdemgmt *conn)
360 return conn->prompt;
363 const char *vdemgmt_getversion(struct vdemgmt *conn)
365 return conn->version;
368 char **vdemgmt_commandlist(struct vdemgmt *conn)
370 int i=0, j, ncommands;
371 char *p=NULL, *s=NULL, **out=NULL, *es="";
372 struct vdemgmt_out buf;
374 memset(&buf, 0, sizeof(struct vdemgmt_out));
376 CHECKNOT(vdemgmt_sendcmd(conn, "help", &buf), 0);
377 p=buf.buf;
378 /* skip head */
379 while(strncmp(p,"------------",12)) p++;
380 p=strstr(p,"\n")+2;
381 /* extract command list */
382 while( p < buf.buf + buf.sz){
383 s=p;
384 while (*s && *s!=' ' && *s!='\t') s++;
385 out=realloc(out, (i+1)*sizeof(char *));
386 out[i]=strndup(p, s-p);
387 p=strstr(p, "\n")+2;
388 i++;
390 ncommands=i;
391 /* delete menu entries */
392 for(j=0; j<i-1; j++){
393 if (!strncmp(out[j],out[j+1],strlen(out[j])) &&
394 out[j+1][strlen(out[j])] == '/') {
395 free(out[j]); out[j]=es;
396 ncommands--;
399 /* sort and resize array */
400 qsort(out,i,sizeof(char *),qstrcmp);
401 memmove(out, out+(i-ncommands), ncommands*sizeof(char *));
402 out=realloc(out, (ncommands+1)*sizeof(char *));
403 out[ncommands]=NULL;
405 return out;
407 error:
408 return NULL;
411 void vdemgmt_freecommandlist(char **cl)
413 int i=0;
414 while(cl[i]){ free(cl[i]); cl[i]=NULL; i++; }
415 free(cl);
418 /* test
420 void handle(const char *e, const char *d){
421 printf("--received %s--\n%s\n--\n", e, d);
424 int main(int argc, char **argv){
426 struct vdemgmt *conn;
427 struct vdemgmt_out buf;
428 char **cl;
429 int rv=-1, i=0;
431 memset(&buf, 0, sizeof(struct vdemgmt_out));
433 if(argc < 2) {printf("bad cmd\n"); exit(-1);}
434 conn = vdemgmt_open(argv[1]);
435 printf("--open done--\n");
436 printf("--command list--\n");
437 cl=vdemgmt_commandlist(conn);
438 {int j=0;
439 while(cl[j]){
440 printf("%d, %s\n", j, cl[j]); j++;}}
441 vdemgmt_freecommandlist(cl);
442 printf("--end command list--\n");
443 printf("--parsebuf--\n");
444 write(1, conn->pbuf->buf + conn->pbuf->pos, conn->pbuf->len - conn->pbuf->pos);
445 printf("\n--end parsebuf--\n");
447 printf("--banner is--\n%s\n--\n", vdemgmt_getbanner(conn));
448 printf("--prompt is--\n%s\n--\n", vdemgmt_getprompt(conn));
449 printf("--version is--\n%s\n--\n", vdemgmt_getversion(conn));
451 rv = vdemgmt_sendcmd(conn, "port/allprint", NULL);
452 printf("--null send done--\n");
453 printf("--parsebuf--\n");
454 write(1, conn->pbuf->buf + conn->pbuf->pos, conn->pbuf->len - conn->pbuf->pos);
455 printf("\n--end parsebuf--\n");
457 rv = vdemgmt_sendcmd(conn, "fstp/print", &buf);
458 printf("--send done--\n");
459 write(1, buf.buf, buf.sz);
461 printf("--async reg--\n");
462 rv=vdemgmt_asyncreg(conn, "fstp/root", &handle);
463 printf("--return is: %d\n", rv);
464 vdemgmt_rstout(&buf);
465 vdemgmt_sendcmd(conn, "debug/list", &buf);
466 write(1, buf.buf, buf.sz);
467 printf("--async re-reg--\n");
468 rv=vdemgmt_asyncreg(conn, "fstp/root", &handle);
469 printf("--return is: %d\n", rv);
470 printf("--begin cycle\n");
471 for(i=0; i < 3; i++){
472 struct pollfd pfd={vdemgmt_getfd(conn), POLLIN, 0};
473 poll(&pfd,1,-1);
474 vdemgmt_asyncrecv(conn);
476 printf("--end cycle\n");
477 printf("--async unreg--\n");
478 vdemgmt_asyncunreg(conn, "fstp/root");
479 vdemgmt_rstout(&buf);
480 vdemgmt_sendcmd(conn, "debug/list", &buf);
481 write(1, buf.buf, buf.sz);
483 vdemgmt_close(conn);
485 return rv;