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.
32 #include <sys/types.h>
33 #include <sys/socket.h>
35 #include <sys/ioctl.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
41 #include "vdetelweb.h"
44 #define WEB_TCP_PORT 80
45 #define WEB_IDENTIFY 0x0
46 #define WEB_AUTHORIZED 0x1
47 #define WEB_UNAUTHORIZED 0x2
48 #define WEB_OP_GET 0x0
49 #define WEB_OP_POST 0x1
50 #define WEB_OP_POSTDATA 0x2
52 static char base64ab
[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
53 static char *base64passwd
;
54 typedef void (*voidfun
)();
59 char linebuf
[BUFSIZE
];
65 static void lowercase(char *s
)
73 static convert2base64(char *from
,char *to
,int tosize
)
77 while (n
>0 && tosize
>3) {
81 if (n
>0) convbuf
|=*from
;
84 if (n
>0) convbuf
|=*from
;
86 *(to
++)=base64ab
[convbuf
>>18];
87 *(to
++)=base64ab
[convbuf
>>12 & 0x3f];
88 *(to
++)=(n
<-1)?'=':base64ab
[convbuf
>>6 & 0x3f];
89 *(to
++)=(n
<0)?'=':base64ab
[convbuf
& 0x3f];
95 static void createbase64passwd()
98 char buf64
[BUFSIZE
*4/3];
99 snprintf(buf
,BUFSIZE
,"admin:%s",passwd
);
100 convert2base64(buf
,buf64
,BUFSIZE
*4/3);
101 base64passwd
=strdup(buf64
);
104 static void lwip_printf(int fd
, const char *format
, ...)
106 char outbuf
[BUFSIZE
];
108 va_start (arg
, format
);
109 vsnprintf(outbuf
,BUFSIZE
,format
,arg
);
110 lwip_write(fd
,outbuf
,strlen(outbuf
));
113 static void web_close(int fn
,int fd
)
115 //printf("web_close %d %d\n",fn,fd);
121 static int vde_getanswer(voidfun f
,void *arg
,int vdefd
)
124 char linebuf
[BUFSIZE
+1];
125 int n
=0,ib
=0,il
=0,indata
=0,eoa
=0;
127 n
=read(vdefd
,buf
,BUFSIZE
);
130 linebuf
[il
++]=buf
[ib
];
131 if (buf
[ib
] == '\n') {
137 if (linebuf
[0]=='.' && linebuf
[1]=='\r')
140 f(arg
,linebuf
,il
,indata
,0);
141 } else if (strncmp(linebuf
,"0000",4)==0)
144 if(linebuf
[0]=='1' &&
145 linebuf
[1] >= '0' && linebuf
[1] <= '9' &&
146 linebuf
[2] >= '0' && linebuf
[2] <= '9' &&
147 linebuf
[3] >= '0' && linebuf
[3] <= '9') {
148 f(arg
,linebuf
+5,il
-5,0,atoi(linebuf
));
170 struct vdemenu
*next
;
173 static struct vdemenu
*menuhead
;
175 static struct vdemenu
*vde_findmenu(struct vdemenu
*head
,char *name
)
180 if (strcmp(head
->name
,name
)==0)
183 return vde_findmenu(head
->next
,name
);
186 static void vde_addsub(struct vdesub
**headp
,char *name
,char *syntax
,char *help
)
188 if (*headp
== NULL
) {
189 *headp
=malloc(sizeof(struct vdesub
));
190 if (*headp
!= NULL
) {
192 (*headp
)->descr
=help
;
193 (*headp
)->syntax
=syntax
;
197 vde_addsub(&((*headp
)->next
),name
,syntax
,help
);
200 static void vde_addcmd(struct vdemenu
*head
,char *menu
,char *name
,char *syntax
,char *help
)
203 if (strcmp(head
->name
,menu
) == 0)
204 vde_addsub(&(head
->sub
),name
,syntax
,help
);
206 vde_addcmd(head
->next
,menu
,name
,syntax
,help
);
210 static void vde_addmenu(struct vdemenu
**headp
,char *name
,char *help
)
212 if (*headp
== NULL
) {
213 *headp
=malloc(sizeof(struct vdemenu
));
214 if (*headp
!= NULL
) {
216 (*headp
)->descr
=help
;
221 vde_addmenu(&((*headp
)->next
),name
,help
);
224 static void vde_helpline(struct vdemenu
**headp
,char *buf
,int len
,int indata
,int rv
)
227 static int syntaxpos
,helppos
;
231 for (i
=0;i
<len
&& buf
[i
]=='-';i
++) ;
232 for (;i
<len
&& buf
[i
]==' ';i
++) ;
234 for (;i
<len
&& buf
[i
]=='-';i
++) ;
235 for (;i
<len
&& buf
[i
]==' ';i
++) ;
238 else if (nl
> 2 && indata
) {
244 for (namelen
=0;namelen
<syntaxpos
&& buf
[namelen
]!=' ';namelen
++) ;
245 if (strncmp(buf
+syntaxpos
,"======",5) ==0) {
247 name
=strndup(buf
,namelen
);
248 help
=strndup(buf
+helppos
,len
-helppos
-2);
249 vde_addmenu(headp
,name
,help
);
252 for (slash
=0;slash
<namelen
&& buf
[slash
]!='/';slash
++) ;
255 buf
[slash
]=0;slash
++;
257 for (synlen
=helppos
-syntaxpos
; synlen
>0 && buf
[syntaxpos
+synlen
-1]==' ';synlen
--) ;
258 name
=strndup(buf
+slash
,namelen
);
260 syntax
=strndup(buf
+syntaxpos
,synlen
);
263 help
=strndup(buf
+helppos
,len
-helppos
-2);
264 vde_addcmd(*headp
,buf
,name
,syntax
,help
);
270 static struct vdemenu
*vde_gethelp(int vdefd
)
272 struct vdemenu
*head
=NULL
;
273 write(vdefd
,"help\n",5);
274 vde_getanswer(vde_helpline
,&head
,vdefd
);
278 static void lwip_showline(int *fdp
,char *buf
,int len
,int indata
,int rv
)
281 lwip_write(*fdp
,buf
,len
);
284 static int lwip_showout(int fd
, int vdefd
)
286 return vde_getanswer(lwip_showline
,&fd
,vdefd
);
289 static int hex2num(int c
)
298 static char *uriconv(char *in
)
302 while ((*t
=*s
) != 0) {
306 *t
=(hex2num(*(s
+1))<<4)+hex2num(*(s
+2));
314 static void postdata_parse(int fd
,int vdefd
,char *menu
,char *postdata
)
316 char cmdbuf
[BUFSIZE
];
317 int cmdlen
,arglen
,rv
;
318 char *postcmd
,*cmd
,*endcmd
,*arg
=NULL
;
319 /*printf("PD **%s**\n",postdata);*/
320 if ((postcmd
=strstr(postdata
,"X="))!=NULL
) {
321 /* enter in a text field (catched through the hidden button) */
325 char *token
=strsep(&postdata
,"&");
327 char *targ
=index(token
,'=');
328 if(strncmp("X=",token
,2) != 0) {
329 if (targ
+1 < token
+l
)
332 if ((point
=strstr(token
,".arg")) != NULL
)
340 if(cmd
!=NULL
&& *cmd
!= 0) {
341 strncpy(cmdbuf
,menu
,BUFSIZE
);
342 strncat(cmdbuf
,"/",BUFSIZE
);
343 strncat(cmdbuf
,cmd
,BUFSIZE
);
344 strncat(cmdbuf
," ",BUFSIZE
);
345 strncat(cmdbuf
,uriconv(arg
),BUFSIZE
);
346 write(vdefd
,cmdbuf
,strlen(cmdbuf
));
347 lwip_printf(fd
,"<P> </P><B>%s %s</B><PRE>",prompt
,cmdbuf
);
348 rv
=lwip_showout(fd
,vdefd
);
349 lwip_printf(fd
,"</PRE><B>Result: %s</B>\r\n",strerror(rv
-1000));
352 else if ((postcmd
=strstr(postdata
,"COMMAND="))!=NULL
) {
355 for(cmdlen
=0;postcmd
[cmdlen
] != '&' && postcmd
[cmdlen
] != 0; cmdlen
++)
357 strncpy(cmdbuf
,menu
,BUFSIZE
);
358 strncat(cmdbuf
,"/",BUFSIZE
);
359 cmd
=cmdbuf
+strlen(cmdbuf
);
360 strncat(cmdbuf
,postcmd
,(BUFSIZE
<cmdlen
)?BUFSIZE
:cmdlen
);
361 endcmd
=cmdbuf
+strlen(cmdbuf
);
362 strncat(cmdbuf
,".arg",BUFSIZE
);
363 if ((arg
=strstr(postdata
,cmd
))!=NULL
) {
365 for(arglen
=0;arg
[arglen
] != '&' && arg
[arglen
] != 0; arglen
++)
370 strncat(cmdbuf
," ",BUFSIZE
);
371 strncat(cmdbuf
,uriconv(arg
),BUFSIZE
);
375 write(vdefd
,cmdbuf
,strlen(cmdbuf
));
376 lwip_printf(fd
,"<P> </P><B>%s %s</B><PRE>",prompt
,cmdbuf
);
377 rv
=lwip_showout(fd
,vdefd
);
378 lwip_printf(fd
,"</PRE><B>Result: %s</B>\r\n",strerror(rv
-1000));
383 "<style type=\"text/CSS\"\r\n"
386 "font-family: Helvetica;\r\n"
387 "color: #0000FF;\r\n"
388 "background-color: #FFFFFF;\r\n"
389 "text-align: justify;\r\n"
390 "margin-left: 5pt;\r\n"
391 "margin-top: 5pt;\r\n"
392 "margin-right: 5pt;\r\n"
393 "margin-bottom: 5pt;\r\n"
396 "font-family: Helvetica;\r\n"
397 "font-size: 12px;\r\n"
398 "color: #ff0000;\r\n"
404 "HTTP/1.1 200 OK\r\n"
405 "Content-Type: text/html\r\n"
408 static char errmsg
[]=
409 "HTTP/1.1 404 Not Found\r\n"
410 "Content-Type: text/html\r\n"
413 "<TITLE>404 Not Found</TITLE>\r\n"
415 "<H1>Not Found</H1>\r\n"
416 "The requested URL was not found on this server.\r\n"
417 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
418 "</BODY></HTML>\r\n";
420 static void web_this_form(int fd
,struct vdemenu
*this)
423 for (sub
=this->sub
;sub
!=NULL
;sub
=sub
->next
) {
424 if (*(sub
->syntax
) == 0) {
426 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
427 "<TD width=100></TD>\r\n"
428 "<TD width=100></TD>\r\n"
429 "<TD width=300>%s</TD></TR>\r\n",
430 "COMMAND",sub
->name
,sub
->descr
);
433 "<TR><TD width=50><INPUT type=submit size=100 name=\"%s\" value=\"%s\"></TD>\r\n"
434 "<TD width=100>%s</TD>\r\n"
435 "<TD width=100><INPUT type=text name=\"%s.arg\"></TD>\r\n"
436 "<TD width=300>%s</TD></TR>\r\n",
437 "COMMAND",sub
->name
,sub
->syntax
,sub
->name
,sub
->descr
);
442 static void web_menu_index(int fd
)
444 struct vdemenu
*this;
445 lwip_printf(fd
,"<P><A HREF=\"index.html\">Home Page</A></P>\r\n");
446 for (this=menuhead
;this!=NULL
;this=this->next
)
447 lwip_printf(fd
,"<P><A HREF=\"%s.html\">%s</A></P>\r\n",this->name
,this->name
);
450 static void web_create_page(char *path
,int fd
,int vdefd
,char *postdata
)
452 struct vdemenu
*this;
454 if ((tail
=strstr(path
,".html")) != NULL
)
456 if (*path
==0 || ((this=vde_findmenu(menuhead
,path
)) != NULL
)) {
457 lwip_write(fd
,okmsg
,sizeof(okmsg
));
460 "<TITLE>%s %s</TITLE>\r\n",
461 prompt
, (*path
==0)?"Home Page":path
);
462 lwip_write(fd
,css
,sizeof(css
));
464 "</HEAD><BODY class=core>\r\n"
466 "<TABLE BORDER=0><TD width=80 bgcolor=#aacbff valign=top class=sidebar>",
467 prompt
, (*path
==0)?"Home Page":this->descr
);
469 if (*path
==0) {/* HOME PAGE */
471 write(vdefd
,"showinfo\r\n",10);
473 "</TD><TD><PRE>\r\n");
474 rv
=lwip_showout(fd
,vdefd
);
475 lwip_printf(fd
,"</PRE>\r\n");
477 lwip_printf(fd
,"<B>%s</B>\r\n",strerror(rv
-1000));
480 "</TD><TD><FORM action=\"%s.html\" method=post table-layout=fixed>\r\n<TABLE><THEAD><TR>\r\n"
481 "<TD><INPUT type=submit name=X style=\"visibility:hidden\" ></TD>\r\n"
482 "<TD><B>Syntax</B></TD><TD><B>Args</B>\r\n"
483 "</TD><TD><B>Description</B></TD></TR></THEAD>\r\n",path
);
484 web_this_form(fd
,this);
485 lwip_printf(fd
,"</TABLE></FORM>\r\n");
486 if (postdata
!= NULL
) {
487 postdata_parse(fd
,vdefd
,path
,postdata
);
492 "<hr>VDE 2.0 WEB MGMT INTERFACE\r\n"
493 "</BODY></HTML>\r\n");
495 lwip_write(fd
,errmsg
,sizeof(errmsg
));
498 static char authmsg
[]=
499 "HTTP/1.1 401 Authorization Required\r\n"
500 "WWW-Authenticate: Basic realm=\"";
502 //"Content-Length: 187\r\n"
503 //"Connection: close\r\n"
504 static char authmsg2
[]= "\"\r\n"
505 "Content-Type: text/html\r\n"
508 "<TITLE>401 Authorization Required</TITLE>\r\n"
510 "<H1>Authorization Required</H1>\r\n"
511 "Login and Password required\r\n"
512 "<hr>\r\nVDE 2.0 WEB MGMT INTERFACE</H1>\r\n"
513 "</BODY></HTML>\r\n";
516 int web_core(int fn
,int fd
,int vdefd
)
518 struct webstat
*st
=status
[fn
];
519 //printf("CORE %s\n",st->linebuf);
520 if (st
->op
==WEB_OP_POSTDATA
) {
521 //printf("POSTDATA %s\n",st->linebuf);
522 web_create_page(&(st
->path
[1]),fd
,vdefd
,st
->linebuf
);
524 } else if (strncmp(st
->linebuf
,"GET",3) == 0) {
525 //printf("GET %s\n",st->linebuf);
526 sscanf(st
->linebuf
+4,"%s",st
->path
);
529 } else if (strncmp(st
->linebuf
,"POST",3) == 0) {
530 //printf("POST %s\n",st->linebuf);
531 sscanf(st
->linebuf
+5,"%s",st
->path
);
534 } else if (strncmp(st
->linebuf
,"Content-Length: ",16) == 0) {
535 st
->bodylen
=atoi(st
->linebuf
+16);
536 //printf("BODYLEN %d\n",st->bodylen);
538 } else if (strncmp(st
->linebuf
,"Authorization: Basic",20) == 0) {
540 while (st
->linebuf
[k
] == ' ') k
++;
541 if (strncmp(st
->linebuf
+k
,base64passwd
,strlen(base64passwd
))==0)
542 st
->status
=WEB_AUTHORIZED
;
544 } else if (st
->linebuf
[0]=='\n' || st
->linebuf
[0]=='\r') {
545 switch (st
->status
) {
547 lwip_write(fd
,authmsg
,sizeof(authmsg
));
548 lwip_write(fd
,prompt
,strlen(prompt
));
549 lwip_write(fd
,authmsg2
,sizeof(authmsg2
));
554 if (strcmp(st
->path
,"/index.html") == 0)
556 if (st
->op
== WEB_OP_GET
) {
557 web_create_page(&(st
->path
[1]),fd
,vdefd
,NULL
);
560 st
->op
=WEB_OP_POSTDATA
;
568 int webdata(int fn
,int fd
,int vdefd
)
572 struct webstat
*st
=status
[fn
];
573 n
=lwip_read(fd
,buf
,BUFSIZE
);
578 printlog(LOG_ERR
,"web read err: %s",strerror(errno
));
580 for (i
=0;i
<n
&& st
->bufindex
<BUFSIZE
;i
++) {
581 st
->linebuf
[(st
->bufindex
)++]=buf
[i
];
582 if (buf
[i
]=='\n' || (st
->op
==WEB_OP_POSTDATA
&& st
->bufindex
==st
->bodylen
)) {
583 st
->linebuf
[(st
->bufindex
)]=0;
584 if (web_core(fn
,fd
,vdefd
)) {
594 int webaccept(int fn
,int fd
,int vdefd
)
596 struct sockaddr_in cli_addr
;
602 clilen
= sizeof(cli_addr
);
603 newsockfd
= lwip_accept(fd
, (struct sockaddr
*) &cli_addr
, &clilen
);
606 printlog(LOG_ERR
,"web accept err: %s",strerror(errno
));
609 newfn
=addpfd(newsockfd
,webdata
);
610 status
[newfn
]=st
=malloc(sizeof(struct webstat
));
611 st
->status
=WEB_IDENTIFY
;
617 void web_init(int vdefd
)
621 struct sockaddr_in serv_addr
;
622 sockfd
=lwip_socket(AF_INET
, SOCK_STREAM
, 0);
625 printlog(LOG_ERR
,"web socket err: %s",strerror(errno
));
627 if(setsockopt(sockfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
629 printlog(LOG_ERR
,"web setsockopt: %s",strerror(errno
));
632 if(fcntl(sockfd
, F_SETFL
, O_NONBLOCK
) < 0){
633 printlog(LOG_ERR
,"Setting O_NONBLOCK web: %s",strerror(errno
));
637 bzero((char *) &serv_addr
, sizeof(serv_addr
));
638 serv_addr
.sin_family
= AF_INET
;
639 serv_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
640 serv_addr
.sin_port
= htons(WEB_TCP_PORT
);
642 if (lwip_bind(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
)) < 0) {
643 printlog(LOG_ERR
,"web bind err: %s",strerror(errno
));
646 lwip_listen(sockfd
, 5);
648 createbase64passwd();
649 menuhead
=vde_gethelp(vdefd
);
650 addpfd(sockfd
,webaccept
);