2 * VDETELWEB: VDE telnet and WEB interface
4 * web.c: http micro server for vde mgmt
6 * Copyright 2005 Renzo Davoli University of Bologna - Italy
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <sys/types.h>
34 #include <sys/socket.h>
36 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
42 #include "vdetelweb.h"
45 #define WEB_TCP_PORT 80
46 #define WEB_IDENTIFY 0x0
47 #define WEB_AUTHORIZED 0x1
48 #define WEB_UNAUTHORIZED 0x2
49 #define WEB_OP_GET 0x0
50 #define WEB_OP_POST 0x1
51 #define WEB_OP_POSTDATA 0x2
53 static char base64ab
[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
54 static char *base64passwd
;
55 typedef void (*voidfun
)();
60 char linebuf
[BUFSIZE
];
66 static void lowercase(char *s
)
74 static convert2base64(char *from
,char *to
,int tosize
)
78 while (n
>0 && tosize
>3) {
82 if (n
>0) convbuf
|=*from
;
85 if (n
>0) convbuf
|=*from
;
87 *(to
++)=base64ab
[convbuf
>>18];
88 *(to
++)=base64ab
[convbuf
>>12 & 0x3f];
89 *(to
++)=(n
<-1)?'=':base64ab
[convbuf
>>6 & 0x3f];
90 *(to
++)=(n
<0)?'=':base64ab
[convbuf
& 0x3f];
96 static void createbase64passwd()
99 char buf64
[BUFSIZE
*4/3];
100 snprintf(buf
,BUFSIZE
,"admin:%s",passwd
);
101 convert2base64(buf
,buf64
,BUFSIZE
*4/3);
102 base64passwd
=strdup(buf64
);
105 static void lwip_printf(int fd
, const char *format
, ...)
107 char outbuf
[BUFSIZE
];
109 va_start (arg
, format
);
110 vsnprintf(outbuf
,BUFSIZE
,format
,arg
);
111 lwip_write(fd
,outbuf
,strlen(outbuf
));
114 static void web_close(int fn
,int fd
)
116 //printf("web_close %d %d\n",fn,fd);
122 static int vde_getanswer(voidfun f
,void *arg
,int vdefd
)
125 char linebuf
[BUFSIZE
+1];
126 int n
=0,ib
=0,il
=0,indata
=0,eoa
=0;
128 n
=read(vdefd
,buf
,BUFSIZE
);
131 linebuf
[il
++]=buf
[ib
];
132 if (buf
[ib
] == '\n') {
138 if (linebuf
[0]=='.' && linebuf
[1]=='\r')
141 f(arg
,linebuf
,il
,indata
,0);
142 } else if (strncmp(linebuf
,"0000",4)==0)
145 if(linebuf
[0]=='1' &&
146 linebuf
[1] >= '0' && linebuf
[1] <= '9' &&
147 linebuf
[2] >= '0' && linebuf
[2] <= '9' &&
148 linebuf
[3] >= '0' && linebuf
[3] <= '9') {
149 f(arg
,linebuf
+5,il
-5,0,atoi(linebuf
));
171 struct vdemenu
*next
;
174 static struct vdemenu
*menuhead
;
176 static struct vdemenu
*vde_findmenu(struct vdemenu
*head
,char *name
)
181 if (strcmp(head
->name
,name
)==0)
184 return vde_findmenu(head
->next
,name
);
187 static void vde_addsub(struct vdesub
**headp
,char *name
,char *syntax
,char *help
)
189 if (*headp
== NULL
) {
190 *headp
=malloc(sizeof(struct vdesub
));
191 if (*headp
!= NULL
) {
193 (*headp
)->descr
=help
;
194 (*headp
)->syntax
=syntax
;
198 vde_addsub(&((*headp
)->next
),name
,syntax
,help
);
201 static void vde_addcmd(struct vdemenu
*head
,char *menu
,char *name
,char *syntax
,char *help
)
204 if (strcmp(head
->name
,menu
) == 0)
205 vde_addsub(&(head
->sub
),name
,syntax
,help
);
207 vde_addcmd(head
->next
,menu
,name
,syntax
,help
);
211 static void vde_addmenu(struct vdemenu
**headp
,char *name
,char *help
)
213 if (*headp
== NULL
) {
214 *headp
=malloc(sizeof(struct vdemenu
));
215 if (*headp
!= NULL
) {
217 (*headp
)->descr
=help
;
222 vde_addmenu(&((*headp
)->next
),name
,help
);
225 static void vde_helpline(struct vdemenu
**headp
,char *buf
,int len
,int indata
,int rv
)
228 static int syntaxpos
,helppos
;
232 for (i
=0;i
<len
&& buf
[i
]=='-';i
++) ;
233 for (;i
<len
&& buf
[i
]==' ';i
++) ;
235 for (;i
<len
&& buf
[i
]=='-';i
++) ;
236 for (;i
<len
&& buf
[i
]==' ';i
++) ;
239 else if (nl
> 2 && indata
&& (strncmp(buf
,"debug",5) !=0 )) {
245 for (namelen
=0;namelen
<syntaxpos
&& buf
[namelen
]!=' ';namelen
++) ;
246 if (strncmp(buf
+syntaxpos
,"======",5) ==0) {
248 name
=strndup(buf
,namelen
);
249 help
=strndup(buf
+helppos
,len
-helppos
-2);
250 vde_addmenu(headp
,name
,help
);
253 for (slash
=0;slash
<namelen
&& buf
[slash
]!='/';slash
++) ;
256 buf
[slash
]=0;slash
++;
258 for (synlen
=helppos
-syntaxpos
; synlen
>0 && buf
[syntaxpos
+synlen
-1]==' ';synlen
--) ;
259 name
=strndup(buf
+slash
,namelen
);
261 syntax
=strndup(buf
+syntaxpos
,synlen
);
264 help
=strndup(buf
+helppos
,len
-helppos
-2);
265 vde_addcmd(*headp
,buf
,name
,syntax
,help
);
271 static struct vdemenu
*vde_gethelp(int vdefd
)
273 struct vdemenu
*head
=NULL
;
274 write(vdefd
,"help\n",5);
275 vde_getanswer(vde_helpline
,&head
,vdefd
);
279 static void lwip_showline(int *fdp
,char *buf
,int len
,int indata
,int rv
)
282 lwip_write(*fdp
,buf
,len
);
285 static int lwip_showout(int fd
, int vdefd
)
287 return vde_getanswer(lwip_showline
,&fd
,vdefd
);
290 static int hex2num(int c
)
299 static char *uriconv(char *in
)
303 while ((*t
=*s
) != 0) {
307 *t
=(hex2num(*(s
+1))<<4)+hex2num(*(s
+2));
315 static void postdata_parse(int fd
,int vdefd
,char *menu
,char *postdata
)
317 char cmdbuf
[BUFSIZE
];
318 int cmdlen
,arglen
,rv
;
319 char *postcmd
,*cmd
,*endcmd
,*arg
=NULL
;
320 /*printf("PD **%s**\n",postdata);*/
321 if ((postcmd
=strstr(postdata
,"X="))!=NULL
) {
322 /* enter in a text field (catched through the hidden button) */
326 char *token
=strsep(&postdata
,"&");
328 char *targ
=index(token
,'=');
329 if(strncmp("X=",token
,2) != 0) {
330 if (targ
+1 < token
+l
)
333 if ((point
=strstr(token
,".arg")) != NULL
)
341 if(cmd
!=NULL
&& *cmd
!= 0) {
342 strncpy(cmdbuf
,menu
,BUFSIZE
);
343 strncat(cmdbuf
,"/",BUFSIZE
);
344 strncat(cmdbuf
,cmd
,BUFSIZE
);
345 strncat(cmdbuf
," ",BUFSIZE
);
346 strncat(cmdbuf
,uriconv(arg
),BUFSIZE
);
347 write(vdefd
,cmdbuf
,strlen(cmdbuf
));
348 lwip_printf(fd
,"<P> </P><B>%s %s</B><PRE>",prompt
,cmdbuf
);
349 rv
=lwip_showout(fd
,vdefd
);
350 lwip_printf(fd
,"</PRE><B>Result: %s</B>\r\n",strerror(rv
-1000));
353 else if ((postcmd
=strstr(postdata
,"COMMAND="))!=NULL
) {
356 for(cmdlen
=0;postcmd
[cmdlen
] != '&' && postcmd
[cmdlen
] != 0; cmdlen
++)
358 strncpy(cmdbuf
,menu
,BUFSIZE
);
359 strncat(cmdbuf
,"/",BUFSIZE
);
360 cmd
=cmdbuf
+strlen(cmdbuf
);
361 strncat(cmdbuf
,postcmd
,(BUFSIZE
<cmdlen
)?BUFSIZE
:cmdlen
);
362 endcmd
=cmdbuf
+strlen(cmdbuf
);
363 strncat(cmdbuf
,".arg",BUFSIZE
);
364 if ((arg
=strstr(postdata
,cmd
))!=NULL
) {
366 for(arglen
=0;arg
[arglen
] != '&' && arg
[arglen
] != 0; arglen
++)
371 strncat(cmdbuf
," ",BUFSIZE
);
372 strncat(cmdbuf
,uriconv(arg
),BUFSIZE
);
376 write(vdefd
,cmdbuf
,strlen(cmdbuf
));
377 lwip_printf(fd
,"<P> </P><B>%s %s</B><PRE>",prompt
,cmdbuf
);
378 rv
=lwip_showout(fd
,vdefd
);
379 lwip_printf(fd
,"</PRE><B>Result: %s</B>\r\n",strerror(rv
-1000));
384 "<style type=\"text/CSS\"\r\n"
387 "font-family: Helvetica;\r\n"
388 "color: #0000FF;\r\n"
389 "background-color: #FFFFFF;\r\n"
390 "text-align: justify;\r\n"
391 "margin-left: 5pt;\r\n"
392 "margin-top: 5pt;\r\n"
393 "margin-right: 5pt;\r\n"
394 "margin-bottom: 5pt;\r\n"
397 "font-family: Helvetica;\r\n"
398 "font-size: 12px;\r\n"
399 "color: #ff0000;\r\n"
405 "HTTP/1.1 200 OK\r\n"
406 "Content-Type: text/html\r\n"
409 static char errmsg
[]=
410 "HTTP/1.1 404 Not Found\r\n"
411 "Content-Type: text/html\r\n"
414 "<TITLE>404 Not Found</TITLE>\r\n"
416 "<H1>Not Found</H1>\r\n"
417 "The requested URL was not found on this server.\r\n"
418 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
419 "</BODY></HTML>\r\n";
421 static void web_this_form(int fd
,struct vdemenu
*this)
424 for (sub
=this->sub
;sub
!=NULL
;sub
=sub
->next
) {
425 if (*(sub
->syntax
) == 0) {
427 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
428 "<TD width=100></TD>\r\n"
429 "<TD width=100></TD>\r\n"
430 "<TD width=300>%s</TD></TR>\r\n",
431 "COMMAND",sub
->name
,sub
->descr
);
434 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
435 "<TD width=100>%s</TD>\r\n"
436 "<TD width=100><INPUT type=text name=\"%s.arg\"></TD>\r\n"
437 "<TD width=300>%s</TD></TR>\r\n",
438 "COMMAND",sub
->name
,sub
->syntax
,sub
->name
,sub
->descr
);
443 static void web_menu_index(int fd
)
445 struct vdemenu
*this;
446 lwip_printf(fd
,"<P><A HREF=\"index.html\">Home Page</A></P>\r\n");
447 for (this=menuhead
;this!=NULL
;this=this->next
)
448 lwip_printf(fd
,"<P><A HREF=\"%s.html\">%s</A></P>\r\n",this->name
,this->name
);
451 static void web_create_page(char *path
,int fd
,int vdefd
,char *postdata
)
453 struct vdemenu
*this;
455 if ((tail
=strstr(path
,".html")) != NULL
)
457 if (*path
==0 || ((this=vde_findmenu(menuhead
,path
)) != NULL
)) {
458 lwip_write(fd
,okmsg
,sizeof(okmsg
));
461 "<TITLE>%s %s</TITLE>\r\n",
462 prompt
, (*path
==0)?"Home Page":path
);
463 lwip_write(fd
,css
,sizeof(css
));
465 "</HEAD><BODY class=core>\r\n"
467 "<TABLE BORDER=0><TD width=80 bgcolor=#aacbff valign=top class=sidebar>",
468 prompt
, (*path
==0)?"Home Page":this->descr
);
470 if (*path
==0) {/* HOME PAGE */
472 write(vdefd
,"showinfo\r\n",10);
474 "</TD><TD><PRE>\r\n");
475 rv
=lwip_showout(fd
,vdefd
);
476 lwip_printf(fd
,"</PRE>\r\n");
478 lwip_printf(fd
,"<B>%s</B>\r\n",strerror(rv
-1000));
481 "</TD><TD><FORM action=\"%s.html\" method=post table-layout=fixed>\r\n<TABLE><THEAD><TR>\r\n"
482 "<TD><INPUT type=submit name=X style=\"visibility:hidden\" ></TD>\r\n"
483 "<TD><B>Syntax</B></TD><TD><B>Args</B>\r\n"
484 "</TD><TD><B>Description</B></TD></TR></THEAD>\r\n",path
);
485 web_this_form(fd
,this);
486 lwip_printf(fd
,"</TABLE></FORM>\r\n");
487 if (postdata
!= NULL
) {
488 postdata_parse(fd
,vdefd
,path
,postdata
);
493 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
494 "</BODY></HTML>\r\n");
496 lwip_write(fd
,errmsg
,sizeof(errmsg
));
499 static char authmsg
[]=
500 "HTTP/1.1 401 Authorization Required\r\n"
501 "WWW-Authenticate: Basic realm=\"";
503 //"Content-Length: 187\r\n"
504 //"Connection: close\r\n"
505 static char authmsg2
[]= "\"\r\n"
506 "Content-Type: text/html\r\n"
509 "<TITLE>401 Authorization Required</TITLE>\r\n"
511 "<H1>Authorization Required</H1>\r\n"
512 "Login and Password required\r\n"
513 "<hr>\r\nVDE 2.0 WEB MGMT INTERFACE</H1>\r\n"
514 "</BODY></HTML>\r\n";
517 int web_core(int fn
,int fd
,int vdefd
)
519 struct webstat
*st
=status
[fn
];
520 //printf("CORE %s\n",st->linebuf);
521 if (st
->op
==WEB_OP_POSTDATA
) {
522 //printf("POSTDATA %s\n",st->linebuf);
523 web_create_page(&(st
->path
[1]),fd
,vdefd
,st
->linebuf
);
525 } else if (strncmp(st
->linebuf
,"GET",3) == 0) {
526 //printf("GET %s\n",st->linebuf);
527 sscanf(st
->linebuf
+4,"%s",st
->path
);
530 } else if (strncmp(st
->linebuf
,"POST",3) == 0) {
531 //printf("POST %s\n",st->linebuf);
532 sscanf(st
->linebuf
+5,"%s",st
->path
);
535 } else if (strncmp(st
->linebuf
,"Content-Length: ",16) == 0) {
536 st
->bodylen
=atoi(st
->linebuf
+16);
537 //printf("BODYLEN %d\n",st->bodylen);
539 } else if (strncmp(st
->linebuf
,"Authorization: Basic",20) == 0) {
541 while (st
->linebuf
[k
] == ' ') k
++;
542 if (strncmp(st
->linebuf
+k
,base64passwd
,strlen(base64passwd
))==0)
543 st
->status
=WEB_AUTHORIZED
;
545 } else if (st
->linebuf
[0]=='\n' || st
->linebuf
[0]=='\r') {
546 switch (st
->status
) {
548 lwip_write(fd
,authmsg
,sizeof(authmsg
));
549 lwip_write(fd
,prompt
,strlen(prompt
));
550 lwip_write(fd
,authmsg2
,sizeof(authmsg2
));
555 if (strcmp(st
->path
,"/index.html") == 0)
557 if (st
->op
== WEB_OP_GET
) {
558 web_create_page(&(st
->path
[1]),fd
,vdefd
,NULL
);
561 st
->op
=WEB_OP_POSTDATA
;
569 int webdata(int fn
,int fd
,int vdefd
)
573 struct webstat
*st
=status
[fn
];
574 n
=lwip_read(fd
,buf
,BUFSIZE
);
579 printlog(LOG_ERR
,"web read err: %s",strerror(errno
));
581 for (i
=0;i
<n
&& st
->bufindex
<BUFSIZE
;i
++) {
582 st
->linebuf
[(st
->bufindex
)++]=buf
[i
];
583 if (buf
[i
]=='\n' || (st
->op
==WEB_OP_POSTDATA
&& st
->bufindex
==st
->bodylen
)) {
584 st
->linebuf
[(st
->bufindex
)]=0;
585 if (web_core(fn
,fd
,vdefd
)) {
595 int webaccept(int fn
,int fd
,int vdefd
)
597 struct sockaddr_in cli_addr
;
603 clilen
= sizeof(cli_addr
);
604 newsockfd
= lwip_accept(fd
, (struct sockaddr
*) &cli_addr
, &clilen
);
607 printlog(LOG_ERR
,"web accept err: %s",strerror(errno
));
610 newfn
=addpfd(newsockfd
,webdata
);
611 status
[newfn
]=st
=malloc(sizeof(struct webstat
));
612 st
->status
=WEB_IDENTIFY
;
618 void web_init(int vdefd
)
622 struct sockaddr_in serv_addr
;
623 sockfd
=lwip_socket(AF_INET
, SOCK_STREAM
, 0);
626 printlog(LOG_ERR
,"web socket err: %s",strerror(errno
));
628 if(setsockopt(sockfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
630 printlog(LOG_ERR
,"web setsockopt: %s",strerror(errno
));
633 if(fcntl(sockfd
, F_SETFL
, O_NONBLOCK
) < 0){
634 printlog(LOG_ERR
,"Setting O_NONBLOCK web: %s",strerror(errno
));
638 bzero((char *) &serv_addr
, sizeof(serv_addr
));
639 serv_addr
.sin_family
= AF_INET
;
640 serv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
641 serv_addr
.sin_port
= htons(WEB_TCP_PORT
);
643 if (lwip_bind(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
)) < 0) {
644 printlog(LOG_ERR
,"web bind err: %s",strerror(errno
));
647 lwip_listen(sockfd
, 5);
649 createbase64passwd();
650 menuhead
=vde_gethelp(vdefd
);
651 addpfd(sockfd
,webaccept
);