OSDN Git Service

Ver.1.4.10: Change parameter's name and value in config file.
[opengate/opengate.git] / opengate / opengatesrv / watch-client.c
1 /*************************************************
2 Opengate server
3   module for communication with client program (java/javascript) 
4
5 Copyright (C) 1999 Opengate Project Team
6 Written by Yoshiaki Watanabe 1999-2006
7 Modified Katsuhiko Eguchi, 2005 
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 Email: watanaby@is.saga-u.ac.jp
24 **************************************************/
25
26 #include        "opengatesrv.h"
27
28 void GetPeerAddr(int sockfd, char *peerAddr);
29 void SendTerminateReply(void);
30 void ReadHttpHeaders(void);
31 void SendReplyToGetHello(void);
32 void SendHttpKeepPage(char *userid, char *sessionId, char *language, int port);
33 int SelectAccept(void);
34 void AcceptHttpReConnect(void);
35 int MacAddrCheck(int ipStatus,char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6);
36 int IsRightKey(char *pNowKey, char *sessionId);
37 void SendHttpReply(char *reply);
38 void CheckAjaxAbility(char *buff, char *sessionId);
39
40 void OnUsageTimeLimitAlarm(int signo);
41 void OnCheckBasicAlarm(int signo);
42 void OnCheckJavaAlarm(int signo);
43 void OnCheckHttpAlarm(int signo);
44 void OnReadWaitAlarm(int signo);
45 void OnAjaxWaitAlarm(int signo);
46
47 extern char ruleNumber4[WORDMAXLN];  /* ipfw rule number in string form  */
48 extern char ruleNumber6[WORDMAXLN];  /* ip6fw rule number in string form */
49 extern char language[WORDMAXLN]; /* message language */
50
51 int ipType=IPV4;                     /* using IP type */
52 int listenfd[2]; /* file descriptor for listen port */
53 int connfd;   /* file descriptor for connection port */
54 int connectMode = NOCONNECT; /* the TCP connection mode */
55
56 struct AlarmArg{          /* arguments used in on-alarm functions */
57   struct clientAddr *pClientAddr;
58   char *clientAddr4;
59   char *macAddr4;
60   char *clientAddr6;
61   char *macAddr6;
62   char *userid;
63   char *userProperty;
64   int ipStatus;                    /* ipv4 ipv6 or dual */
65   int checkInterval;
66   int noPacketInterval;
67 } alarmArg;
68
69 int helloWait=FALSE;  /* hello reply waiting mode */
70 int readHelloTime=0;  /* the time of reading hello */
71 int sendHelloTime=0;  /* the time of sending hello */
72 int noReplyCount=0; /* count up the no reply to hello message */
73
74
75 /***************************************/
76 /* get temp listen port of this server */
77 /***************************************/
78 int getListenPort(void)
79 {
80   struct sockaddr_in servaddr4;
81   struct sockaddr_in6 servaddr6;
82   extern const struct in6_addr in6addr_any;
83
84   int portNo;
85   int portmin;
86   int portmax;
87   
88   bzero(&servaddr4, sizeof(servaddr4));
89   bzero(&servaddr6, sizeof(servaddr6));
90
91   servaddr4.sin_family=AF_INET;
92   servaddr4.sin_addr.s_addr=htonl(INADDR_ANY);
93   
94   servaddr6.sin6_family=AF_INET6;
95   servaddr6.sin6_addr=in6addr_any;
96
97   /* get port range from config file */
98   portmin=atoi(GetConfValue("ListenPort/Min"));
99   portmax=atoi(GetConfValue("ListenPort/Max"));
100   
101   /* search unused port between PORTMIN and PORTMAX */
102   for(portNo=portmin; portNo<=portmax; portNo++){
103     servaddr4.sin_port=htons(portNo);
104     servaddr6.sin6_port=htons(portNo);
105
106     listenfd[0]=Socket(AF_INET, SOCK_STREAM, 0);
107     listenfd[1]=Socket(AF_INET6, SOCK_STREAM, 0);
108
109     if(listenfd[0]<0 || listenfd[1]<0){ /* if error, return */
110       return -1;
111     }
112
113     if(listenfd[0]>=FD_SETSIZE && listenfd[1]>=FD_SETSIZE){
114       return -1;
115     }
116
117     if((bind(listenfd[0], (SA *)&servaddr4, sizeof(servaddr4))==0) &&
118        (bind(listenfd[1], (SA *)&servaddr6, sizeof(servaddr6))==0) ){
119       break;
120     }
121        
122     Close(listenfd[0]);
123     Close(listenfd[1]);
124   }
125
126   if(portNo>portmax) return -1;  /* cannot get unused port */
127   
128   if(Listen(listenfd[0], LISTENQ)<0) return -1; /* if error, return */
129   if(Listen(listenfd[1], LISTENQ)<0) return -1;
130   
131   return portNo;
132 }
133
134 /************************************/
135 /* wait for connection of client side program */
136 /************************************/
137 int waitClientConnect(char *userid, char *userProperty, char *sessionId, char *clientAddr4, char *clientAddr6, int duration, char *macAddr4, char *macAddr6, int ipStatus, struct clientAddr *pClientAddr, char *language, int port, int pid)
138 {
139   char buff[BUFFMAXLN];             /* read in buffer */
140   char connectAddr[ADDRMAXLN];      /* connected client address */
141   char httpStr[BUFFMAXLN];          /* HTTP GET string at terminate */
142   char useridAndSessionId[BUFFMAXLN]; /* comcat userid and sessionid */
143
144   /* set alarm function arguments */
145   alarmArg.pClientAddr=pClientAddr;
146   alarmArg.clientAddr4=clientAddr4;
147   alarmArg.clientAddr6=clientAddr6;
148   alarmArg.macAddr4=macAddr4;
149   alarmArg.macAddr6=macAddr6;
150   alarmArg.userid=userid;
151   alarmArg.userProperty=userProperty;
152   alarmArg.ipStatus=ipStatus;
153   alarmArg.checkInterval=atoi(GetConfValue("ActiveCheckInterval"));
154   alarmArg.noPacketInterval=atoi(GetConfValue("NoPacketInterval"));  
155
156   /* set no conection initially */
157   connectMode=NOCONNECT;
158
159   /* set the alarm for usage time limit */
160   AddAlarm("UsageTimeLimitAlarm",duration,FALSE,OnUsageTimeLimitAlarm);
161
162   /* set the alarm for periodic keep alive check */
163   AddAlarm("CheckBasicAlarm", alarmArg.checkInterval, FALSE, OnCheckBasicAlarm);
164
165   /* loop until accepting correct user */
166   while(connectMode == NOCONNECT){
167
168     /* start alarms */
169     EnableAlarm();
170
171     /* connection wait */
172     connfd = SelectAccept();
173
174     /*at abnormal connect */
175     if(connfd < 0) continue;
176
177     /* at normal connection */
178     /* stop alarm interupt between checking */
179     DisableAlarm();
180     
181     /* is it from the correct client addr */
182     /* the check is skipped for IPv6 */
183     if(ipType==IPV4 && ipStatus!=IPV6ONLY){
184       GetPeerAddr(connfd, connectAddr);
185       if(isNull(connectAddr)||strcmp(connectAddr, clientAddr4)!=0){
186         connectMode=NOCONNECT;
187         Close(connfd);
188         continue;
189       }
190     }
191  
192     /* set read wait alarm */
193     AddAlarm("ReadWaitAlarm",atoi(GetConfValue("CommWaitTimeout")),
194              TRUE, OnReadWaitAlarm); 
195     EnableAlarm();
196     /* get string from connection */
197     if(readln(connfd, buff, BUFFMAXLN) <0){
198       /* if abnormal, wait next request */
199       connectMode=NOCONNECT;
200       Close(connfd);
201       continue;
202     }
203     RemoveAlarm("ReadWaitAlarm");
204
205     /* is it the correct userid from java applet */
206     /* the request is [<userid>:<sessionId>] */
207     snprintf(useridAndSessionId, BUFFMAXLN, "%s-%s", userid,sessionId);
208     if(strcmp(buff, useridAndSessionId)==0){
209
210       /* enter to the Java watch mode on the connection */
211       connectMode=JAVACONNECT;
212       break;
213     }
214
215     /* is it the httpkeep page download request */
216     /* the request is [GET /httpkeep.html ....] */
217     snprintf(httpStr, BUFFMAXLN, "GET /httpkeep-%s-%s", userid,sessionId);
218     
219     if(strstr(buff, httpStr)==buff){
220       
221       /* page download request found */
222       /* read out the remained headers and send the page */
223       ReadHttpHeaders();
224       SendHttpKeepPage(userid, sessionId, language, port);
225
226       /* to check ajax ability, wait XMLHttpRequest for a while */
227       CheckAjaxAbility(buff, sessionId);
228
229       break;
230     }
231
232     /* is it the terminate request */
233     /* the request is [GET /terminate-<pid> ..] */
234     snprintf(httpStr, BUFFMAXLN, "GET /terminate-%d", pid);
235     if(strstr(buff, httpStr)==buff){
236       /* terminate request found */
237       SendTerminateReply();
238       connectMode=ENDCONNECT;
239       Close(connfd);
240       break;
241     }
242
243     /* some other unknown request */    
244     err_msg("ERR at %s#%d: unknown request [%s] sent from client",
245             __FILE__,__LINE__,buff);
246     connectMode=NOCONNECT;
247     Close(connfd);
248     
249     continue;
250   }
251
252   /* stop all alarms */
253   RemoveAlarm(NULL);
254     
255   return connectMode;
256 }
257
258 /***************************************/
259 /* check ajax ability                  */
260 /* read hello sent by XMLhttpRequest   */
261 /*  (reply is delayed)                 */
262 /* check result is set in connectMode  */ 
263 /***************************************/ 
264 void checkAjaxAbility(char *buff, char *sessionId)
265 {
266
267   /* to check the ajax ablility of the client, wait ajax request */
268   AddAlarm("AjaxWaitAlarm",atoi(GetConfValue("CommWaitTimeout")), 
269            TRUE, OnAjaxWaitAlarm); 
270   EnableAlarm();
271
272   /* read wait for ajax request in the connection */
273   while(1){
274     if(readln(connfd, buff, BUFFMAXLN) <0){
275       
276       /* if timeout, no ajax ability */
277       /* java might be connected */
278       connectMode=NOCONNECT;    
279       Close(connfd);
280       break;
281     }
282     
283     /* recieved normal request */
284     RemoveAlarm("AjaxWaitAlarm");
285     ReadHttpHeaders();
286     
287     /* usually, hello request is recieve */
288     if(strstr(buff, "GET /hello-")==buff){
289       
290       /* if received hello-key is incorrect, exit */
291       /* [GET /hello-key1-key2 ..] */
292       if( IsRightKey(buff+strlen("GET /hello-"), sessionId)==FALSE){
293         connectMode=ENDCONNECT;
294         Close(connfd);
295         break;
296       }
297       
298       /* enter to the Http watch mode on the connection */
299       connectMode=HTTPCONNECT;
300       break;
301     }
302     /* or some request might be inserted. eg:[GET /favicon.ico] */
303     /* ignore it */
304     else{
305       SendHttpReply("");
306       continue;
307     }
308   }
309 }
310
311 /****************************/
312 /* wait for TCP connection  */
313 /****************************/
314 int selectAccept(void)
315 {
316   int connfd = -1;
317   int smax;                         /* select max descliptor */
318   fd_set rfd0;                      /* fd_set for select */
319   int n;                            /* counter */
320   struct sockaddr_storage cliaddr;  /* client IP adddress */
321   socklen_t len = sizeof(cliaddr);
322
323   /* select socket */
324   FD_ZERO(&rfd0);
325   FD_SET(listenfd[0], &rfd0);
326   FD_SET(listenfd[1], &rfd0);
327
328   if(listenfd[0]>listenfd[1]) smax=listenfd[0]+1;
329   else smax=listenfd[1]+1;
330
331   if((n = select(smax, &rfd0, NULL, NULL, NULL)) > 0){
332     /* wait connection */
333
334     if(FD_ISSET(listenfd[0], &rfd0)){
335
336       if((connfd=accept(listenfd[0], (struct sockaddr *)&cliaddr, &len)) >= 0){
337
338         /* connect by ipv4 */
339         ipType=IPV4;
340       }
341     }
342     if(FD_ISSET(listenfd[1], &rfd0)){
343
344       if((connfd=accept(listenfd[1], (struct sockaddr *)&cliaddr, &len)) >= 0){
345
346         /* connect by ipv6 */
347         ipType=IPV6;
348       }
349     }
350   }
351   return connfd;
352 }
353
354 /***************************************/
355 /* called at usage time limit          */
356 /***************************************/
357 void onUsageTimeLimitAlarm(int signo)
358 {
359   connectMode=ENDCONNECT;
360   err_msg("ERR at %s#%d: no connection from client",__FILE__,__LINE__);
361 }
362
363 /***************************************/
364 /* called at read wait time limit       */
365 /***************************************/
366 void onReadWaitAlarm(int signo)
367 {
368   connectMode=ENDCONNECT;
369 }
370
371 /***************************************/
372 /* called at ajax request wait timeout */
373 /***************************************/
374 void onAjaxWaitAlarm(int signo)
375 {
376   connectMode=NOCONNECT;
377 }
378
379  /***************************************/
380 /* called at periodic alive basic check */
381 /***************************************/
382 void onCheckBasicAlarm(int signo)
383 {
384   static int packetCountPrev=0;  /* packet count at previous check */
385   int packetCountNow=0;   /* packet count at now */
386   static   int noPacketPeriod=0; /* no packet period count in check loop */
387
388   /* search new IPv6 addresses */
389   ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
390              alarmArg.macAddr6, alarmArg.userProperty);
391
392   /* mac address check */
393   if(MacAddrCheck(alarmArg.ipStatus, 
394                   alarmArg.clientAddr4, alarmArg.clientAddr6, 
395                   alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
396     connectMode=ENDCONNECT;
397     return;
398   }  
399
400   /* packet flow check */
401   packetCountNow=GetPacketCount(alarmArg.pClientAddr);
402   if(packetCountNow==packetCountPrev){  /* no packet between checks */
403     noPacketPeriod++;
404   }else{
405     noPacketPeriod=0;
406     packetCountPrev=packetCountNow;
407   }
408   
409   if(noPacketPeriod*alarmArg.checkInterval 
410      >= alarmArg.noPacketInterval){
411     err_msg("ERR at %s#%d: no packet passed for the client",
412             __FILE__,__LINE__);
413     connectMode=ENDCONNECT;
414     return;
415   }
416   /* set the alarm for next periodic keep alive check */
417   AddAlarm("CheckBasicAlarm", alarmArg.checkInterval, FALSE, OnCheckBasicAlarm);  /* EnableAlarm is called automatically in alarm function */
418 }
419
420 /***************************************/
421 /* check mac address change            */
422 /***************************************/
423 int macAddrCheck(int ipStatus, char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6) 
424
425   char macAddrNow[ADDRMAXLN];       /* MAC address at now */
426
427   if(ipStatus!=IPV6ONLY){
428     /* check mac address from arp */
429     GetMacAddrFromArp(clientAddr4, macAddrNow);
430     if(*macAddrNow!='?' && strcmp(macAddr4, macAddrNow)!=0){
431       err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
432       connectMode=ENDCONNECT;
433       return FALSE;
434     }
435   }else{
436     /* check mac address from ndp */
437     GetMacAddrFromNdp(clientAddr6, macAddrNow);
438     if(*macAddrNow!='?' && strcmp(macAddr6, macAddrNow)!=0){
439       err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
440       connectMode=ENDCONNECT;
441       return FALSE;
442     }
443   }
444   return TRUE;
445 }
446
447 /***************************************/
448 /* get addr of connected remote site   */
449 /***************************************/
450 void getPeerAddr(int sockfd, char *peerAddr)
451 {
452   struct sockaddr *cliaddr;
453   socklen_t len;
454   char *pAddr;
455
456   *peerAddr='\0'; /* set null string */
457
458   if((cliaddr=Malloc(ADDRMAXLN))==NULL) return; /* if error, return */
459
460   len=ADDRMAXLN;
461   if(Getpeername(sockfd, cliaddr, &len)<0) return; /* if error, return */
462     
463   pAddr=Sock_ntop_host(cliaddr, len);
464   if(pAddr!=NULL) strncpy(peerAddr, pAddr, ADDRMAXLN);
465   
466   free(cliaddr);
467   
468   return;
469 }
470
471 /***************************************************/
472 /* wait for close connection of java               */
473 /***************************************************/
474 void waitJavaClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus)
475 {
476   char buff[BUFFMAXLN];
477   int ret;
478
479   /* set alarm function arguments */
480   alarmArg.pClientAddr=pClientAddr;
481   alarmArg.macAddr4=macAddr4;
482   alarmArg.macAddr6=macAddr6;
483   alarmArg.userid=userid;
484   alarmArg.userProperty=userProperty;
485   alarmArg.ipStatus=ipStatus;
486
487   Writefmt(connfd,"accept\r\n");
488   
489   /* TCP read/write loop */
490   /* this loop implement following logic */
491   /*   repeat until receiving 'quit' or EOF from client         */
492   /*      say 'hello' to client                                 */
493   /*      receive 'hello' from client. if no reply, then quit.  */
494   /*      get packet count for client after short delay.        */
495   /*      long interval                                         */
496   /*      get packet count again. if no packet, then quit.      */
497   
498   /* set the alarm for periodic check */
499   AddAlarm("CheckJavaAlarm", alarmArg.checkInterval, FALSE, OnCheckJavaAlarm);
500   EnableAlarm();
501   
502   while(1){
503     /* set default to terminate */
504     connectMode=ENDCONNECT;
505     ret=readln(connfd, buff, BUFFMAXLN);
506
507     /* stop alarm */
508     DisableAlarm();
509
510     if(ret>=0){
511       /* normal read */
512       connectMode=JAVACONNECT;
513       /* read quit, then quit */
514       if(strstr(buff,"quit") != NULL){
515         break;
516       }
517       
518       /* read hello reply to the hello message in periodic check */
519       /* see onCheckJavaAlarm for timeout alarm setting */
520       else if((helloWait)&&(strstr(buff,"hello") !=NULL)){
521         helloWait=FALSE;
522         RemoveAlarm("ReplyTimeoutAlarm");
523       }
524       /* read other string */
525       else{
526       }
527     }
528
529     /* connection terminated */
530     if(connectMode==ENDCONNECT) break;
531
532     /* restart alarm */
533     EnableAlarm();
534   }
535
536   /* reset alarm */
537   RemoveAlarm(NULL);
538     
539   SendQuitClient();
540   
541   return;
542   }
543
544
545 /***************************************/
546 /* called at periodic java alive check */
547 /***************************************/
548 void onReplyTimeoutAlarm(int signo)
549 {
550   /* no reply */
551   err_msg("ERR at %s#%d: no reply to hello",__FILE__,__LINE__);
552   connectMode=ENDCONNECT;
553 }
554         
555 /***************************************/
556 /* called at periodic java alive check */
557 /***************************************/
558 void onCheckJavaAlarm(int signo)
559 {
560   /* search new IPv6 addresses */
561   ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
562              alarmArg.macAddr6, alarmArg.userProperty);
563
564   /* send hello and wait the reply */
565   Writefmt(connfd,"hello\r\n");
566   helloWait=TRUE;
567
568   /* mac address check */
569   if(MacAddrCheck(alarmArg.ipStatus, 
570                   alarmArg.clientAddr4, alarmArg.clientAddr6, 
571                   alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
572     connectMode=ENDCONNECT;
573     return;
574   }
575
576   /* set the alarm for next periodic check */
577   AddAlarm("CheckJavaAlarm", alarmArg.checkInterval, FALSE, OnCheckJavaAlarm);
578   /* EnableAlarm is called automatically in alarm function */
579
580   connectMode=JAVACONNECT;
581   return;
582 }
583
584 /***************************************************/
585 /* send reply to terminate access via connfd(not stdout) */
586 /***************************************************/
587 void sendTerminateReply(void)
588 {
589   Writefmt(connfd,"<META HTTP-EQUIV=Pragma CONTENT=no-cache>");
590   Writefmt(connfd,"<HTML><BODY> Network is closed. </BODY></HTML> \r\n\r\n");
591   Close(connfd);
592 }
593
594 /***************************************************/
595 /* send quit to client and close connection        */
596 /***************************************************/
597 void sendQuitClient(void)
598 {
599   Writefmt(connfd,"quit\r\n");
600   Close(connfd);
601 }
602
603
604 /***************************************************/
605 /* wait for close connection of HTTP connection    */
606 /***************************************************/
607 void waitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus, char *sessionId, int port)
608 {
609   char buff[BUFFMAXLN];
610   int ret;
611
612   /* set alarm function arguments */
613   alarmArg.pClientAddr=pClientAddr;
614   alarmArg.macAddr4=macAddr4;
615   alarmArg.macAddr6=macAddr6;
616   alarmArg.userid=userid;
617   alarmArg.userProperty=userProperty;
618   alarmArg.ipStatus=ipStatus;
619
620   /* save time to read hello */
621   readHelloTime = time(NULL);
622
623   /* send first reply to hello */
624   SendReplyToGetHello();
625   sendHelloTime = time(NULL);
626
627   /* set the hello wait mode ON */
628   helloWait=TRUE;
629   
630   /* TCP read/write loop */
631   /* this loop implement following logic */
632   /*  repeat until receiving 'GET /terminate' or EOF from client */
633   /*      wait request from client.                */
634   /*      if wait timeout,  then quit              */
635   /*      if 'GET /hello' request, then send reply */
636   /*      if 'GET /terminate' request,  then quit  */
637   /*      if connection closed, then quit          */
638   
639   /* set the alarm for periodic client check */
640   AddAlarm("checkHttpAlarm", alarmArg.checkInterval, FALSE, OnCheckHttpAlarm);
641   EnableAlarm();
642   
643   while(1){
644
645     /* set default to terminate */
646     connectMode=ENDCONNECT;
647
648     /* read in wait for client request */
649     ret=readln(connfd, buff, BUFFMAXLN);
650
651     /* at some request, stop alarm between readin check*/
652     DisableAlarm();
653
654     if(ret>=0){
655       /* normal read */
656       connectMode=HTTPCONNECT;
657
658       /* read [GET /hello] */
659       if(strstr(buff,"GET /hello") == buff){
660         
661         /* save time to read hello */
662         readHelloTime = time(NULL);
663
664         ReadHttpHeaders();
665
666         /* if received key is not match, exit */
667         if(IsRightKey(buff+strlen("GET /hello-"), sessionId)==FALSE){
668           connectMode=ENDCONNECT;
669           break;
670         }
671         
672         /* set the hello wait mode OFF */
673         helloWait=FALSE;
674       }
675       
676       /* read other string */
677       else{
678       }
679     }
680     else{
681       /*abnormal read */
682       /* some alarm is ringed or connecion is closed */
683       /*  connectionMode might be modified in onAlarm */
684
685       if(connectMode==ENDCONNECT){
686
687         /* wait short time to accept reconnection */
688         /* (to permit occasional disconnection at exchanging hello) */
689         if(helloWait==TRUE &&
690            (time(NULL)-sendHelloTime)<=atoi(GetConfValue("ReconnectTimeout"))){
691           AcceptHttpReConnect();
692         }
693
694         /* no reconnection, then terminate */
695         if(connectMode==ENDCONNECT){
696           break;
697         }
698       }
699     }
700
701     /* restart alarm */
702     EnableAlarm();
703   }
704
705   /* reset alarm */
706    RemoveAlarm(NULL);
707
708   Close(connfd);
709   
710   return;
711 }
712
713 /*************************/
714 /* accept http reconnect */
715 /*************************/
716 void acceptHttpReConnect(void){
717
718   int startTime; 
719
720   startTime=time(NULL);
721
722   /* wait a short time */
723   AddAlarm("ReadWaitAlarm",atoi(GetConfValue("ReconnectTimeout")),
724            TRUE, OnReadWaitAlarm); 
725   EnableAlarm();
726
727   /* connection wait */
728   connfd = SelectAccept();
729
730   if(connfd<0){
731     /* abnormal return from selectAccept */
732     if(errno==EINTR){ /* timeout interupt */
733       err_msg("ERR at %s#%d: http reconnect timeout",
734               __FILE__,__LINE__);
735       connectMode=ENDCONNECT;
736     }else{           /* other errors */
737       err_msg("ERR: http reconnect error [%s]",strerror(errno)); 
738       connectMode=ENDCONNECT;
739     }
740
741   }else{
742     /* normal return from selectAccept */
743     if(debug>0)err_msg("INFO: http reconnect after %d seconds",
744                        time(NULL)-startTime); 
745     connectMode=HTTPCONNECT;
746   }
747
748   /* receive request */
749   RemoveAlarm("ReadWaitAlarm");
750 }
751
752 /*****************************************************************/
753 /* Is the sent client key correct                                */
754 /*  request string is as follows                                 */
755 /*  GET /hello-11111111111111111111-2222222222222222222 HTTP...  */
756 /*              MD5digest(32chars)   MD5digest(32chars)          */
757 /*                nowKey               nextKey                   */
758 /*                                                               */
759 /*         client                            server              */
760 /*       save sid     <-------------------     sid               */
761 /* md5(sid)+md5(md5(rand1)+sid)  ---------> check nowkey         */
762 /*                                          save nextKey         */
763 /* md5(rand1)+md5(md5(rand2)+sid)---------> check nowkey         */
764 /*                                          save nextKey         */
765 /* md5(rand2)+md5(md5(rand3)+sid)---------> check nowkey         */
766 /*                                          save nextKey         */
767 /*****************************************************************/
768 int isRightKey(char *arg, char *sessionId)
769 {
770   static char savedKey[33]=""; /* saved MD5 string */
771   char tempbuff[BUFFMAXLN];    /* work area */
772   char md5work[33]      ;      /* md5 work */
773   char *pNowKey;
774   char *pNextKey;
775
776   /* initial value of savedKey is md5(md5(sessionId)+sessionId) */
777   if(isNull(savedKey)){
778     md5hex(tempbuff, 33, sessionId);
779     strncat(tempbuff, sessionId, BUFFMAXLN);
780     md5hex(savedKey, 33, tempbuff);
781   }
782
783   /* split NowKey and NextKey in argument */
784   /* 32 is the length of MD5 result */
785   pNowKey=arg;
786   *(pNowKey+32)='\0';
787   pNextKey=pNowKey+33;
788   *(pNextKey+32)='\0';
789
790   /* make string [nowKey+sessionId] */
791   strncpy(tempbuff, pNowKey, BUFFMAXLN);
792   strncat(tempbuff, sessionId, BUFFMAXLN);
793
794   /* compare savedKey and md5(nowKey+sessionId) */
795   if(strcmp(savedKey, md5hex(md5work, 33, tempbuff))==0){
796
797     /* save nextKey for next check */
798     strncpy(savedKey, pNextKey, 33);
799     return TRUE;
800   }
801   else{
802     err_msg("ERR at %s#%d: incorrect client key",
803             __FILE__,__LINE__);
804     return FALSE;
805   }
806 }
807
808 /***************************************/
809 /* called at periodic http alive check */
810 /***************************************/
811 void onCheckHttpAlarm(int signo)
812 {
813   /* at this timing, hello request might be received */
814   /* if in hello wait mode, it is abnormal */
815   if(helloWait==TRUE){
816     connectMode=ENDCONNECT;
817     return;
818   }
819
820   /* send delayed reply to hello request */
821   SendReplyToGetHello();
822
823   /* save time to send hello */
824   sendHelloTime = time(NULL);  
825
826   /* set the hello wait mode ON */
827   helloWait=TRUE;
828
829   /* search new IPv6 addresses */
830   ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
831              alarmArg.macAddr6, alarmArg.userProperty);
832
833   /* mac address check */
834   if(MacAddrCheck(alarmArg.ipStatus, 
835                   alarmArg.clientAddr4, alarmArg.clientAddr6, 
836                   alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
837     connectMode=ENDCONNECT;
838     return;
839   }
840
841   /* set the alarm for next periodic check */
842   AddAlarm("CheckHttpAlarm", alarmArg.checkInterval, FALSE, OnCheckHttpAlarm);
843   /* EnableAlarm is called automatically in alarm function */
844
845   /* normal return */
846   connectMode = HTTPCONNECT;
847   return;
848 }
849
850 /***************************************************/
851 /* read skip Http headers ended by null line       */
852 /***************************************************/
853 void readHttpHeaders(void)
854 {
855   char buff[BUFFMAXLN];             /* read in buffer */
856   int n;
857
858   /* read until null line (only CRLF code) */
859   while((n=readln(connfd, buff, BUFFMAXLN))>0){
860     ;
861   }
862 }
863
864 /********************************************************/
865 /* send hello to client for replying GET /hello request */
866 /********************************************************/
867 void sendReplyToGetHello(void)
868 {
869   /* send HTTP headers */
870   Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
871   Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
872   Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
873   Writefmt(connfd,"Connection: Keep-Alive\r\n");
874   Writefmt(connfd,"Content-Type: text/html\r\n");
875   Writefmt(connfd,"\r\n");
876
877   /* send reply to hello */
878   Writefmt(connfd,"5\r\n");
879   Writefmt(connfd,"hello\r\n"); 
880
881   /* send end of chunk */
882   Writefmt(connfd,"0\r\n");
883   Writefmt(connfd,"\r\n");
884 }
885
886 /***************************************************/
887 /* send httpkeep page to client via connfd         */
888 /***************************************************/
889 void sendHttpKeepPage(char *userid, char *sessionId, char *language, int port)
890 {
891   char buff[BUFFMAXLN];             /* read in buffer */
892   FILE *fp;
893   char httpKeepDoc[BUFFMAXLN];
894   char httpHelloUrl[BUFFMAXLN];
895   char terminateUrl[BUFFMAXLN];
896   char acceptDoc2Url[BUFFMAXLN];
897   char httpkeepJsUrl[BUFFMAXLN];
898   char md5JsUrl[BUFFMAXLN];
899   char *startPageUrl=GetConfValue("StartPage/Url");
900   int startPageType=atoi(GetConfValue("StartPage/Type"));
901   char opengateDir[BUFFMAXLN];
902   char portStr[WORDMAXLN];
903
904
905   /* create path to accept2 doc */
906   snprintf(acceptDoc2Url, BUFFMAXLN, 
907           "http://%s%s/%s/%s",GetConfValue("OpengateServerName"),
908           GetConfValue("OpengateDir"),language,GetConfValue("AcceptDoc2"));
909
910   /* create terminate url [http://<servaddr>:<port>/terminate-<pid>] */
911   snprintf(terminateUrl, BUFFMAXLN, "http://%s:%d/terminate-%d", 
912           GetConfValue("OpengateServerName"), port, getpid());
913
914   /* create httphello url [http://<servaddr>:<port>/hello] */
915   snprintf(httpHelloUrl, BUFFMAXLN, "http://%s:%d/hello", 
916           GetConfValue("OpengateServerName"), port);
917
918   /* create httpkeep.js url[http://<serveraddr>/opengate/httpkeep.js] */
919   snprintf(httpkeepJsUrl, BUFFMAXLN, "http://%s%s/%s", 
920            GetConfValue("OpengateServerName"),
921            GetConfValue("OpengateDir"),GetConfValue("HttpKeepJS"));
922
923   /* create md5.js url[http://<serveraddr>/opengate/md5.js] */
924   snprintf(md5JsUrl, BUFFMAXLN, "http://%s%s/%s", 
925            GetConfValue("OpengateServerName"),
926            GetConfValue("OpengateDir"),GetConfValue("Md5JS"));
927
928   /* create path to httpkeep doc */
929   snprintf(httpKeepDoc,BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
930           GetConfValue("OpengateDir"),language,GetConfValue("HttpKeepDoc"));
931
932   /* create port string */
933   snprintf(portStr, WORDMAXLN, "%d", port);
934
935   /* create absolute url to opengateDir[http://<serveraddr>/opengate] */
936   snprintf(opengateDir, BUFFMAXLN, "http://%s%s", 
937            GetConfValue("OpengateServerName"), GetConfValue("OpengateDir"));
938
939   /* open httpkeepdoc */
940   if((fp=fopen(httpKeepDoc, "r"))==NULL){
941     err_msg("ERR at %s#%d: cannot open %s",__FILE__,__LINE__,httpKeepDoc);
942     PutClientMsg("Cannot find html document");
943     return;
944   }
945
946   /* send HTTP headers */
947   Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
948   Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
949   Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
950   Writefmt(connfd,"Connection: Keep-Alive\r\n");
951   Writefmt(connfd,"Content-Type: text/html\r\n");
952   Writefmt(connfd,"\r\n");
953
954   while(fgets(buff, BUFFMAXLN, fp)!=NULL){
955
956     /* length check */
957     if(strlen(buff)>=BUFFMAXLN-1){
958       err_msg("ERR at %s#%d: too long line in %s",__FILE__,__LINE__,httpKeepDoc);
959     }
960
961     /* replace mark */
962     htmlReplace(buff, "%%HTTPHELLOURL%%", httpHelloUrl);
963     htmlReplace(buff, "%%USERID%%", userid);
964     htmlReplace(buff, "%%SESSIONID%%", sessionId);
965     htmlReplace(buff, "%%TERMINATEURL%%", terminateUrl);
966     htmlReplace(buff, "%%HTTPKEEPJSURL%%", httpkeepJsUrl);
967     htmlReplace(buff, "%%MD5JSURL%%", md5JsUrl);
968
969     htmlReplace(buff, "%%OPENGATEDIR%%", opengateDir);
970     htmlReplace(buff, "%%OPENGATEPORT%%", portStr);
971     htmlReplace(buff, "%%LANGUAGE%%", language);
972
973     /* replace start url mark */
974     if( startPageType==1 ){
975       htmlReplace(buff, "%%STARTURL%%", startPageUrl);
976     }else{
977       htmlReplace(buff, "%%STARTURL%%", acceptDoc2Url);
978     }
979
980     /* length of chunk in hex */
981     Writefmt(connfd, "%x\r\n", strlen(buff));
982     /* the chunk content */
983     Writefmt(connfd, "%s\r\n", buff);
984   }
985   
986   /* chunk end */
987   Writefmt(connfd,"0\r\n");
988   Writefmt(connfd,"\r\n");
989
990   fclose(fp);
991 }
992
993
994 /*************************************************************/
995 /* send reply to unknown http request eg:[GET /favico.ico..] */
996 /*************************************************************/
997 void sendHttpReply(char *reply)
998 {
999   /* send HTTP headers */
1000   Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
1001   Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
1002   Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
1003   Writefmt(connfd,"Connection: Keep-Alive\r\n");
1004   Writefmt(connfd,"Content-Type: text/html\r\n");
1005   Writefmt(connfd,"\r\n");
1006   
1007   if(!isNull(reply)){
1008     /* length of chunk in hex */
1009     Writefmt(connfd, "%x\r\n", strlen(reply));
1010     /* the chunk content */
1011     Writefmt(connfd, "%s\r\n", reply);
1012   }
1013
1014   /* chunk end */
1015   Writefmt(connfd,"0\r\n");
1016   Writefmt(connfd,"\r\n");
1017 }
1018
1019 /***************************************************/
1020 /***************************************************/
1021 void GetPeerAddr(int sockfd, char *peerAddr)
1022 {
1023   if(debug>1) err_msg("DEBUG:=>getPeerAddr( )"); 
1024   getPeerAddr(sockfd,peerAddr);
1025   if(debug>1) err_msg("DEBUG:<=getPeerAddr(,%s)",peerAddr);
1026 }
1027
1028
1029 int GetListenPort(void)
1030 {
1031   int ret;
1032
1033   if(debug>1) err_msg("DEBUG:=>getListenPort( )");
1034   ret=getListenPort();
1035   if(debug>1) err_msg("DEBUG:(%d)<=getListenPort( )",ret);
1036
1037   return ret;
1038 }
1039
1040 int WaitClientConnect(char *userid, char *userProperty, char *sessionId, char *clientAddr4, char *clientAddr6, int duration, char *macAddr4, char *macAddr6, int ipStatus, struct clientAddr *pClientAddr, char *language, int port, int pid)
1041 {
1042   int ret;
1043
1044   if(debug>1) err_msg("DEBUG:=>waitClientConnect(%s,%s,%s,%s,%s,%d,%s,%s,%d,%s,%d,%d)",userid,userProperty,sessionId,clientAddr4,clientAddr6,duration,macAddr4,macAddr6,ipStatus,language,port,pid);
1045   ret=waitClientConnect(userid,userProperty,sessionId,clientAddr4,clientAddr6,duration,macAddr4,macAddr6,ipStatus,pClientAddr,language,port,pid);
1046   if(debug>1) err_msg("DEBUG:(%d)<=waitClientConnect( )",ret);
1047
1048   return ret;
1049 }
1050
1051 void WaitJavaClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus)
1052 {
1053   if(debug>1) err_msg("DEBUG:=>waitJavaClose(%p,%s,userProperty,%s,%s,%d)",pClientAddr,userid,macAddr4,macAddr6,ipStatus);
1054   waitJavaClose(pClientAddr,userid,userProperty,macAddr4,macAddr6,ipStatus);
1055   if(debug>1) err_msg("DEBUG:<=waitJavaClose( )");
1056 }
1057
1058 void SendQuitClient(void)
1059 {
1060   if(debug>1) err_msg("DEBUG:=>sendQuitClient( )");
1061   sendQuitClient();
1062   if(debug>1) err_msg("DEBUG:<=sendQuitClient( )");
1063 }
1064
1065 void SendTerminateReply(void)
1066 {
1067   if(debug>1) err_msg("DEBUG:=>sendTerminateReply( )");
1068   sendTerminateReply();
1069   if(debug>1) err_msg("DEBUG:<=sendTerminateReply( )");
1070 }
1071
1072 void WaitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus, char *sessionid, int port)
1073 {
1074   if(debug>1) err_msg("DEBUG:=>waitHttpClose(%p,%s,userProperty,%s,%s,%d,%s,%d)",pClientAddr,userid,macAddr4,macAddr6,ipStatus, sessionid, port);
1075   waitHttpClose(pClientAddr,userid,userProperty,macAddr4,macAddr6,ipStatus, sessionid, port);
1076   if(debug>1) err_msg("DEBUG:<=waitHttpClose( )");
1077
1078 }
1079
1080 void ReadHttpHeaders(void)
1081 {
1082   if(debug>1) err_msg("DEBUG:=>readHttpHeaders( )");
1083   readHttpHeaders();
1084   if(debug>1) err_msg("DEBUG:<=readHttpHeaders( )");
1085 }
1086
1087 void SendReplyToGetHello(void)
1088 {
1089   if(debug>1) err_msg("DEBUG:=>sendReplyToGetHello( )");
1090   sendReplyToGetHello();
1091   if(debug>1) err_msg("DEBUG:<=sendReplyToGetHello( )");
1092 }
1093
1094 void SendHttpKeepPage(char *userid, char *sessionId, char *language, int port)
1095 {
1096   if(debug>1) err_msg("DEBUG:=>sendHttpKeepPage(%s,%s,%s,%d)", userid, sessionId, language, port);
1097   sendHttpKeepPage(userid, sessionId, language, port);
1098   if(debug>1) err_msg("DEBUG:<=sendHttpKeepPage( )");
1099
1100 }
1101
1102 void OnUsageTimeLimitAlarm(int signo){
1103
1104   if(debug>1) err_msg("DEBUG:=>onUsageTimeLimitAlarm()");
1105   onUsageTimeLimitAlarm(signo);
1106   if(debug>1) err_msg("DEBUG:<=onUsageTimeLimitAlarm()");
1107 }
1108
1109 void OnCheckBasicAlarm(int signo){
1110
1111   if(debug>1) err_msg("DEBUG:=>onCheckBasicAlarm()");
1112   onCheckBasicAlarm(signo);
1113   if(debug>1) err_msg("DEBUG:<=onCheckBasicAlarm()");
1114 }
1115
1116 void OnCheckJavaAlarm(int signo){
1117
1118   if(debug>1) err_msg("DEBUG:=>onCheckJavaAlarm()");
1119   onCheckJavaAlarm(signo);
1120   if(debug>1) err_msg("DEBUG:<=onCheckJavaAlarm()");
1121 }
1122
1123 void OnCheckHttpAlarm(int signo){
1124
1125   if(debug>1) err_msg("DEBUG:=>onCheckHttpAlarm()");
1126   onCheckHttpAlarm(signo);
1127   if(debug>1) err_msg("DEBUG:<=onCheckHttpAlarm()");
1128 }
1129
1130 void OnReadWaitAlarm(int signo){
1131
1132   if(debug>1) err_msg("DEBUG:=>onReadWaitAlarm()");
1133   onReadWaitAlarm(signo);
1134   if(debug>1) err_msg("DEBUG:<=onReadWaitAlarm()");
1135 }
1136
1137 void OnAjaxWaitAlarm(int signo){
1138
1139   if(debug>1) err_msg("DEBUG:=>onAjaxWaitAlarm()");
1140   onAjaxWaitAlarm(signo);
1141   if(debug>1) err_msg("DEBUG:<=onAjaxWaitAlarm()");
1142 }
1143
1144 int SelectAccept(void){
1145   int ret;
1146
1147   if(debug>1) err_msg("DEBUG:=>selectAccept()");
1148   ret=selectAccept();
1149   if(debug>1) err_msg("DEBUG:(%d)<=selectAccept()",ret);
1150
1151   return ret;
1152 }
1153
1154 void AcceptHttpReConnect(void){
1155   if(debug>1) err_msg("DEBUG:=>acceptHttpReConnect()");
1156   acceptHttpReConnect();
1157   if(debug>1) err_msg("DEBUG:<=acceptHttpReConnect()");
1158 }
1159
1160 int MacAddrCheck(int ipStatus, char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6) {
1161   int ret;
1162
1163   if(debug>1) err_msg("DEBUG:=>macAddrCheck(%d,%s,%s,%s,%s)", 
1164                       ipStatus, clientAddr4, clientAddr6, macAddr4, macAddr6);
1165   ret=macAddrCheck(ipStatus, clientAddr4, clientAddr6, macAddr4, macAddr6);
1166   if(debug>1) err_msg("DEBUG:(%d)<=macAddrCheck()",ret);
1167
1168   return ret;
1169 }
1170
1171 int IsRightKey(char *pNowKey, char *sessionId){
1172   int ret;
1173
1174   if(debug>1) err_msg("DEBUG:=>isRightKey(%s,%s)", pNowKey, sessionId);
1175   ret=isRightKey(pNowKey, sessionId);
1176   if(debug>1) err_msg("DEBUG:(%d)<=isRightKey()",ret);
1177
1178   return ret;
1179 }
1180
1181 void SendHttpReply(char *reply){
1182   if(debug>1) err_msg("DEBUG:=>sendHttpRepy(%s)", reply);
1183   sendHttpReply(reply);
1184   if(debug>1) err_msg("DEBUG:<=sendHttpReply()");
1185 }
1186
1187 void CheckAjaxAbility(char *buff, char *sessionId){
1188   if(debug>1) err_msg("DEBUG:=>checkAjaxAbility(%s,%s)",buff,sessionId);
1189   checkAjaxAbility(buff,sessionId);
1190   if(debug>1) err_msg("DEBUG:<=checkAjaxAbility()");
1191 }