Bugfix: daemonize must happen before stack_init & removed useless calls
[vde.git] / vdetelweb / web.c
blob2ec9a963ba056b501d8f44099d22f66db4e9e8ce
1 /*
2 * VDETELWEB: VDE telnet and WEB interface
4 * web.c: http micro server for vde mgmt
5 *
6 * Copyright 2005 Virtual Square Team University of Bologna - Italy
7 * written by Renzo Davoli 2005
8 * management of sha1 Marco Dalla Via 2008
9 * modified by Renzo Davoli 2008
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * $Id$
28 #include <config.h>
29 #include <stdio.h>
30 #define __USE_GNU
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <syslog.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/poll.h>
41 #include <sys/ioctl.h>
42 #include <linux/un.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <string.h>
46 #include <getopt.h>
47 #include "vdetelweb.h"
48 #include <lwipv6.h>
50 #define WEB_TCP_PORT 80
51 #define WEB_IDENTIFY 0x0
52 #define WEB_AUTHORIZED 0x1
53 #define WEB_UNAUTHORIZED 0x2
54 #define WEB_OP_GET 0x0
55 #define WEB_OP_POST 0x1
56 #define WEB_OP_POSTDATA 0x2
58 const char b64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60 //static char *base64passwd;
61 struct webstat {
62 unsigned char status;
63 unsigned char op;
64 unsigned int bodylen;
65 char linebuf[BUFSIZE];
66 char path[BUFSIZE];
67 int bufindex;
70 static void lowercase(char *s)
72 while (*s != 0) {
73 *s = tolower(*s);
74 s++;
78 void encode64(const char *from, char *to, int tosize) {
80 int convbuf;
81 int n = strlen(from);
83 while ((n > 0) && (tosize > 3)) {
85 convbuf = *from;
86 from++;
87 n--;
88 convbuf <<= 8;
89 if (n > 0)
90 convbuf |= *from;
91 from++;
92 n--;
93 convbuf <<= 8;
94 if (n > 0)
95 convbuf |= *from;
96 from++;
97 n--;
98 *(to++) = b64_chars[convbuf >> 18];
99 *(to++) = b64_chars[(convbuf >> 12) & 0x3f];
100 *(to++) = (n < -1) ? '=' : b64_chars[(convbuf >> 6) & 0x3f];
101 *(to++) = (n < 0) ? '=' : b64_chars[convbuf & 0x3f];
102 tosize -= 4;
104 *to = 0;
107 void decode64(const char *src, char *dest, int dest_size) {
109 int convbuf;
110 int l = strlen(src);
111 char c_src[l];
112 char *c;
114 int i, j;
116 strcpy(c_src, src);
118 /* Sostitute '=' (paddings) with 0 ['A'] */
119 while ((c = strchr(c_src, '=')) != NULL)
120 *c = 'A';
122 /* Convert 4 byte in 6 bit (64) to 3 byte in 8 bit */
123 for (i = 0, j = 0; i < l; i += 4, j += 3) {
125 convbuf = (((int)(strchr(b64_chars, c_src[i]) - b64_chars) << 18) +
126 ((int)(strchr(b64_chars, c_src[i + 1]) - b64_chars) << 12) +
127 ((int)(strchr(b64_chars, c_src[i + 2]) - b64_chars) << 6) +
128 ((int)(strchr(b64_chars, c_src[i + 3]) - b64_chars)));
129 dest[j] = ((convbuf >> 16) & 255);
130 dest[j + 1] = ((convbuf >> 8) & 255);
131 dest[j + 2] = ((convbuf & 255));
134 dest[j] = '\0';
137 #if 0
138 static void createbase64passwd()
140 char buf[BUFSIZE];
141 char buf64[BUFSIZE*4/3];
142 snprintf(buf,BUFSIZE,"admin:%s",passwd);
143 encode64(buf,buf64,BUFSIZE*4/3);
144 base64passwd=strdup(buf64);
146 #endif
148 static void lwip_printf(int fd, const char *format, ...)
150 char outbuf[BUFSIZE];
151 va_list arg;
152 va_start (arg, format);
153 vsnprintf(outbuf,BUFSIZE,format,arg);
154 lwip_write(fd,outbuf,strlen(outbuf));
157 static void web_close(int fn,int fd)
159 //printf("web_close %d %d\n",fn,fd);
160 free(status[fn]);
161 delpfd(fn);
162 lwip_close(fd);
165 static int vde_getanswer(voidfun f,void *arg,int vdefd)
167 char buf[BUFSIZE];
168 char linebuf[BUFSIZE+1];
169 int n=0,ib=0,il=0,indata=0,eoa=0;
170 do {
171 n=read(vdefd,buf,BUFSIZE);
172 for(ib=0;ib<n;ib++)
174 linebuf[il++]=buf[ib];
175 if (buf[ib] == '\n') {
176 linebuf[il-1]='\r';
177 linebuf[il]='\n';
178 linebuf[il+1]=0;
179 il++;
180 if (indata) {
181 if (linebuf[0]=='.' && linebuf[1]=='\r')
182 indata=0;
183 else
184 f(arg,linebuf,il,indata,0);
185 } else if (strncmp(linebuf,"0000",4)==0)
186 indata=1;
187 else {
188 if(linebuf[0]=='1' &&
189 linebuf[1] >= '0' && linebuf[1] <= '9' &&
190 linebuf[2] >= '0' && linebuf[2] <= '9' &&
191 linebuf[3] >= '0' && linebuf[3] <= '9') {
192 f(arg,linebuf+5,il-5,0,atoi(linebuf));
193 eoa=atoi(linebuf);
196 il=0;
199 } while (!eoa);
200 return(eoa);
203 struct vdesub {
204 char *name;
205 char *descr;
206 char *syntax;
207 struct vdesub *next;
210 struct vdemenu {
211 char *name;
212 char *descr;
213 struct vdesub *sub;
214 struct vdemenu *next;
217 static struct vdemenu *menuhead;
219 static struct vdemenu *vde_findmenu(struct vdemenu *head,char *name)
221 if (head == NULL)
222 return NULL;
223 else
224 if (strcmp(head->name,name)==0)
225 return head;
226 else
227 return vde_findmenu(head->next,name);
230 static void vde_addsub(struct vdesub **headp,char *name,char *syntax,char *help)
232 if (*headp == NULL) {
233 *headp=malloc(sizeof(struct vdesub));
234 if (*headp != NULL) {
235 (*headp)->name=name;
236 (*headp)->descr=help;
237 (*headp)->syntax=syntax;
238 (*headp)->next=NULL;
240 } else
241 vde_addsub(&((*headp)->next),name,syntax,help);
244 static void vde_addcmd(struct vdemenu *head,char *menu,char *name,char *syntax,char *help)
246 if (head != NULL) {
247 if (strcmp(head->name,menu) == 0)
248 vde_addsub(&(head->sub),name,syntax,help);
249 else
250 vde_addcmd(head->next,menu,name,syntax,help);
254 static void vde_addmenu(struct vdemenu **headp,char *name,char *help)
256 if (*headp == NULL) {
257 *headp=malloc(sizeof(struct vdemenu));
258 if (*headp != NULL) {
259 (*headp)->name=name;
260 (*headp)->descr=help;
261 (*headp)->sub=NULL;
262 (*headp)->next=NULL;
264 } else
265 vde_addmenu(&((*headp)->next),name,help);
268 static void vde_helpline(struct vdemenu **headp,char *buf,int len,int indata,int rv)
270 static int nl=0;
271 static int syntaxpos,helppos;
272 nl++;
273 if (nl==2) {
274 int i;
275 for (i=0;i<len && buf[i]=='-';i++) ;
276 for (;i<len && buf[i]==' ';i++) ;
277 syntaxpos=i;
278 for (;i<len && buf[i]=='-';i++) ;
279 for (;i<len && buf[i]==' ';i++) ;
280 helppos=i;
282 else if (nl > 2 && indata && (strncmp(buf,"debug",5) !=0 )) {
283 char *name;
284 char *syntax;
285 char *help;
286 int namelen;
287 for (namelen=0;namelen<syntaxpos && buf[namelen]!=' ';namelen++) ;
288 if (strncmp(buf+syntaxpos,"======",5) ==0) {
289 /* MENU */
290 name=strndup(buf,namelen);
291 help=strndup(buf+helppos,len-helppos-2);
292 vde_addmenu(headp,name,help);
293 } else {
294 int slash;
295 for (slash=0;slash<namelen && buf[slash]!='/';slash++) ;
296 if (slash<namelen) {
297 int synlen;
298 buf[slash]=0;slash++;
299 namelen-=slash;
300 for (synlen=helppos-syntaxpos; synlen>0 && buf[syntaxpos+synlen-1]==' ';synlen--) ;
301 name=strndup(buf+slash,namelen);
302 if (synlen>0)
303 syntax=strndup(buf+syntaxpos,synlen);
304 else
305 syntax="";
306 help=strndup(buf+helppos,len-helppos-2);
307 vde_addcmd(*headp,buf,name,syntax,help);
313 static struct vdemenu *vde_gethelp(int vdefd)
315 struct vdemenu *head=NULL;
316 write(vdefd,"help\n",5);
317 vde_getanswer(vde_helpline,&head,vdefd);
318 return head;
321 static void lwip_showline(int *fdp,char *buf,int len,int indata,int rv)
323 if (indata)
324 lwip_write(*fdp,buf,len);
327 static int lwip_showout(int fd, int vdefd)
329 return vde_getanswer(lwip_showline,&fd,vdefd);
332 static int hex2num(int c)
334 if (c>96) c-=32;
335 c -='0';
336 if (c>9)
337 c-=7;
338 return c;
341 static char *uriconv(char *in)
343 char *s=in;
344 char *t=in;
345 while ((*t=*s) != 0) {
346 if (*s=='+')
347 *t=' ';
348 if (*s=='%') {
349 *t=(hex2num(*(s+1))<<4)+hex2num(*(s+2));
350 s+=2;
352 s++;t++;
354 return in;
357 static void postdata_parse(int fd,int vdefd,char *menu,char *postdata)
359 char cmdbuf[BUFSIZE];
360 int cmdlen,arglen,rv;
361 char *postcmd,*cmd,*endcmd,*arg=NULL;
362 /*printf("PD **%s**\n",postdata);*/
363 if ((postcmd=strstr(postdata,"X="))!=NULL) {
364 /* enter in a text field (catched through the hidden button) */
365 cmd=NULL;
366 while(postdata)
368 char *token=strsep(&postdata,"&");
369 int l=strlen(token);
370 char *targ=index(token,'=');
371 if(strncmp("X=",token,2) != 0) {
372 if (targ+1 < token+l) {
373 if(cmd==NULL) {
374 char *point;
375 if ((point=strstr(token,".arg")) != NULL)
376 *point=0;
377 cmd=token;
378 arg=targ+1;
379 } else
380 cmd="";
384 if(cmd!=NULL && *cmd != 0) {
385 strncpy(cmdbuf,menu,BUFSIZE);
386 strncat(cmdbuf,"/",BUFSIZE);
387 strncat(cmdbuf,cmd,BUFSIZE);
388 strncat(cmdbuf," ",BUFSIZE);
389 strncat(cmdbuf,uriconv(arg),BUFSIZE);
390 write(vdefd,cmdbuf,strlen(cmdbuf));
391 lwip_printf(fd,"<P> </P><B>%s %s</B><PRE>",prompt,cmdbuf);
392 rv=lwip_showout(fd,vdefd);
393 lwip_printf(fd,"</PRE><B>Result: %s</B>\r\n",strerror(rv-1000));
396 else if ((postcmd=strstr(postdata,"COMMAND="))!=NULL) {
397 /* accept button */
398 postcmd+=8;
399 for(cmdlen=0;postcmd[cmdlen] != '&' && postcmd[cmdlen] != 0; cmdlen++)
401 strncpy(cmdbuf,menu,BUFSIZE);
402 strncat(cmdbuf,"/",BUFSIZE);
403 cmd=cmdbuf+strlen(cmdbuf);
404 strncat(cmdbuf,postcmd,(BUFSIZE<cmdlen)?BUFSIZE:cmdlen);
405 endcmd=cmdbuf+strlen(cmdbuf);
406 strncat(cmdbuf,".arg",BUFSIZE);
407 if ((arg=strstr(postdata,cmd))!=NULL) {
408 arg+=strlen(cmd)+1;
409 for(arglen=0;arg[arglen] != '&' && arg[arglen] != 0; arglen++)
411 arg[arglen]=0;
412 *endcmd=0;
413 if (*arg != 0) {
414 strncat(cmdbuf," ",BUFSIZE);
415 strncat(cmdbuf,uriconv(arg),BUFSIZE);
417 } else
418 *endcmd=0;
419 write(vdefd,cmdbuf,strlen(cmdbuf));
420 lwip_printf(fd,"<P> </P><B>%s %s</B><PRE>",prompt,cmdbuf);
421 rv=lwip_showout(fd,vdefd);
422 lwip_printf(fd,"</PRE><B>Result: %s</B>\r\n",strerror(rv-1000));
426 static char css[]=
427 "<style type=\"text/CSS\"\r\n"
428 "<!--\r\n"
429 ".core {\r\n"
430 "font-family: Helvetica;\r\n"
431 "color: #0000FF;\r\n"
432 "background-color: #FFFFFF;\r\n"
433 "text-align: justify;\r\n"
434 "margin-left: 5pt;\r\n"
435 "margin-top: 5pt;\r\n"
436 "margin-right: 5pt;\r\n"
437 "margin-bottom: 5pt;\r\n"
438 "}\r\n"
439 ".sidebar {\r\n"
440 "font-family: Helvetica;\r\n"
441 "font-size: 12px;\r\n"
442 "color: #ff0000;\r\n"
443 "}\r\n"
444 "-->\r\n"
445 "</style>\r\n";
447 static char okmsg[]=
448 "HTTP/1.1 200 OK\r\n"
449 "Content-Type: text/html\r\n"
450 "\r\n";
452 static char errmsg[]=
453 "HTTP/1.1 404 Not Found\r\n"
454 "Content-Type: text/html\r\n"
455 "\r\n"
456 "<HTML><HEAD>\r\n"
457 "<TITLE>404 Not Found</TITLE>\r\n"
458 "</HEAD><BODY>\r\n"
459 "<H1>Not Found</H1>\r\n"
460 "The requested URL was not found on this server.\r\n"
461 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
462 "</BODY></HTML>\r\n";
464 static void web_this_form(int fd,struct vdemenu *this)
466 struct vdesub *sub;
467 for (sub=this->sub;sub!=NULL;sub=sub->next) {
468 if (*(sub->syntax) == 0) {
469 lwip_printf(fd,
470 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
471 "<TD width=100></TD>\r\n"
472 "<TD width=100></TD>\r\n"
473 "<TD width=300>%s</TD></TR>\r\n",
474 "COMMAND",sub->name,sub->descr);
475 } else {
476 lwip_printf(fd,
477 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
478 "<TD width=100>%s</TD>\r\n"
479 "<TD width=100><INPUT type=text name=\"%s.arg\"></TD>\r\n"
480 "<TD width=300>%s</TD></TR>\r\n",
481 "COMMAND",sub->name,sub->syntax,sub->name,sub->descr);
486 static void web_menu_index(int fd)
488 struct vdemenu *this;
489 lwip_printf(fd,"<P><A HREF=\"index.html\">Home Page</A></P>\r\n");
490 for (this=menuhead;this!=NULL;this=this->next)
491 lwip_printf(fd,"<P><A HREF=\"%s.html\">%s</A></P>\r\n",this->name,this->name);
494 static void web_create_page(char *path,int fd,int vdefd,char *postdata)
496 struct vdemenu *this=NULL;
497 char *tail;
498 if ((tail=strstr(path,".html")) != NULL)
499 *tail=0;
500 if (*path==0 || ((this=vde_findmenu(menuhead,path)) != NULL)) {
501 lwip_write(fd,okmsg,sizeof(okmsg));
502 lwip_printf(fd,
503 "<HTML><HEAD>\r\n"
504 "<TITLE>%s %s</TITLE>\r\n",
505 prompt, (*path==0)?"Home Page":path);
506 lwip_write(fd,css,sizeof(css));
507 lwip_printf(fd,
508 "</HEAD><BODY class=core>\r\n"
509 "<H1>%s %s</H1>\r\n"
510 "<TABLE BORDER=0><TD width=80 bgcolor=#aacbff valign=top class=sidebar>",
511 prompt, (*path==0)?"Home Page":this->descr);
512 web_menu_index(fd);
513 if (*path==0) {/* HOME PAGE */
514 int rv;
515 write(vdefd,"showinfo\r\n",10);
516 lwip_printf(fd,
517 "</TD><TD><PRE>\r\n");
518 rv=lwip_showout(fd,vdefd);
519 lwip_printf(fd,"</PRE>\r\n");
520 if (rv != 1000)
521 lwip_printf(fd,"<B>%s</B>\r\n",strerror(rv-1000));
522 } else {
523 lwip_printf(fd,
524 "</TD><TD><FORM action=\"%s.html\" method=post table-layout=fixed>\r\n<TABLE><THEAD><TR>\r\n"
525 "<TD><INPUT type=submit name=X style=\"visibility:hidden\" ></TD>\r\n"
526 "<TD><B>Syntax</B></TD><TD><B>Args</B>\r\n"
527 "</TD><TD><B>Description</B></TD></TR></THEAD>\r\n",path);
528 web_this_form(fd,this);
529 lwip_printf(fd,"</TABLE></FORM>\r\n");
530 if (postdata != NULL) {
531 postdata_parse(fd,vdefd,path,postdata);
534 lwip_printf(fd,
535 "</TD></TABLE>\r\n"
536 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
537 "</BODY></HTML>\r\n");
538 } else
539 lwip_write(fd,errmsg,sizeof(errmsg));
542 static char authmsg[]=
543 "HTTP/1.1 401 Authorization Required\r\n"
544 "WWW-Authenticate: Basic realm=\"";
546 //"Content-Length: 187\r\n"
547 //"Connection: close\r\n"
548 static char authmsg2[]= "\"\r\n"
549 "Content-Type: text/html\r\n"
550 "\r\n"
551 "<HTML><HEAD>\r\n"
552 "<TITLE>401 Authorization Required</TITLE>\r\n"
553 "</HEAD><BODY>\r\n"
554 "<H1>Authorization Required</H1>\r\n"
555 "Login and Password required\r\n"
556 "<hr>\r\nVDE 2.0 WEB MGMT INTERFACE\r\n"
557 "</BODY></HTML>\r\n";
560 int web_core(int fn,int fd,int vdefd)
562 struct webstat *st=status[fn];
563 //printf("CORE %s\n",st->linebuf);
564 if (st->op==WEB_OP_POSTDATA) {
565 //printf("POSTDATA %s\n",st->linebuf);
566 web_create_page(&(st->path[1]),fd,vdefd,st->linebuf);
567 return 1;
568 } else if (strncmp(st->linebuf,"GET",3) == 0) {
569 //printf("GET %s\n",st->linebuf);
570 sscanf(st->linebuf+4,"%s",st->path);
571 st->op=WEB_OP_GET;
572 return 0;
573 } else if (strncmp(st->linebuf,"POST",3) == 0) {
574 //printf("POST %s\n",st->linebuf);
575 sscanf(st->linebuf+5,"%s",st->path);
576 st->op=WEB_OP_POST;
577 return 0;
578 } else if (strncmp(st->linebuf,"Content-Length: ",16) == 0) {
579 st->bodylen=atoi(st->linebuf+16);
580 //printf("BODYLEN %d\n",st->bodylen);
581 return 0;
582 } else if (strncmp(st->linebuf,"Authorization: Basic",20) == 0) {
583 char passwd_buf[BUFSIZE];
584 char *passwd_buf_shift;
585 int len=strlen(st->linebuf);
586 int k=20;
587 while (st->linebuf[k] == ' ') k++;
588 while (st->linebuf[len-1] == '\n' ||
589 st->linebuf[len-1] == '\r' ||
590 st->linebuf[len-1] == ' ') {
591 len--;
592 st->linebuf[len]=0;
594 /* SHA1 */
595 decode64((st->linebuf + k), passwd_buf, strlen(st->linebuf + k));
596 passwd_buf_shift = (char *)(strchr(passwd_buf, ':') + 1);
597 if (sha1passwdok(passwd_buf_shift))
598 st->status=WEB_AUTHORIZED;
599 return 0;
600 } else if (st->linebuf[0]=='\n' || st->linebuf[0]=='\r') {
601 switch (st->status) {
602 case WEB_IDENTIFY:
603 lwip_write(fd,authmsg,sizeof(authmsg));
604 lwip_write(fd,prompt,strlen(prompt));
605 lwip_write(fd,authmsg2,sizeof(authmsg2));
606 return 1;
607 break;
608 case WEB_AUTHORIZED:
609 lowercase(st->path);
610 if (strcmp(st->path,"/index.html") == 0)
611 st->path[1]=0;
612 if (st->op == WEB_OP_GET) {
613 web_create_page(&(st->path[1]),fd,vdefd,NULL);
614 return 1;
615 } else {
616 st->op=WEB_OP_POSTDATA;
617 return 0;
619 default:
620 return 0;
622 } else
623 return 0;
626 void webdata(int fn,int fd,int vdefd)
628 char buf[BUFSIZE];
629 int n,i;
630 struct webstat *st=status[fn];
631 n=lwip_read(fd,buf,BUFSIZE);
632 if (n==0) {
633 web_close(fn,fd);
635 else if (n<0)
636 printlog(LOG_ERR,"web read err: %s",strerror(errno));
637 else {
638 for (i=0;i<n && st->bufindex<BUFSIZE;i++) {
639 st->linebuf[(st->bufindex)++]=buf[i];
640 if (buf[i]=='\n' || (st->op==WEB_OP_POSTDATA && st->bufindex==st->bodylen)) {
641 st->linebuf[(st->bufindex)]=0;
642 if (web_core(fn,fd,vdefd)) {
643 web_close(fn,fd);
644 break;
645 } else
646 st->bufindex=0;
652 void webaccept(int fn,int fd,int vdefd)
654 struct sockaddr_in cli_addr;
655 int newsockfd;
656 unsigned int clilen;
657 struct webstat *st;
658 int newfn;
660 clilen = sizeof(cli_addr);
661 newsockfd = lwip_accept(fd, (struct sockaddr *) &cli_addr, &clilen);
663 if (newsockfd < 0) {
664 printlog(LOG_ERR,"web accept err: %s",strerror(errno));
667 newfn=addpfd(newsockfd,webdata);
668 status[newfn]=st=malloc(sizeof(struct webstat));
669 st->status=WEB_IDENTIFY;
670 st->op=0;
671 st->bufindex=0;
674 void web_init(int vdefd)
676 int sockfd;
677 struct sockaddr_in serv_addr;
678 sockfd=lwip_socket(AF_INET, SOCK_STREAM, 0);
680 if (!sockfd) {
681 printlog(LOG_ERR,"web socket err: %s",strerror(errno));
684 bzero((char *) &serv_addr, sizeof(serv_addr));
685 serv_addr.sin_family = AF_INET;
686 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
687 serv_addr.sin_port = htons(WEB_TCP_PORT);
689 if (lwip_bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
690 printlog(LOG_ERR,"web bind err: %s",strerror(errno));
693 lwip_listen(sockfd, 5);
695 //createbase64passwd();
696 menuhead=vde_gethelp(vdefd);
697 addpfd(sockfd,webaccept);