1 /* HTTPSERV.C (c)Copyright Jan Jaeger, 2002-2009 */
2 /* HTTP Server */
3
4 /* This file contains all code required for the HTTP server, */
5 /* when the http_server thread is started it will listen on */
6 /* the HTTP port specified on the HTTPPORT config statement. */
7 /* */
8 /* When a request comes in a http_request thread is started, */
9 /* which will handle the request. */
10 /* */
11 /* When authentification is required (auth parm on the HTTPPORT */
12 /* statement) then the user will be authenticated based on the */
13 /* userid and password supplied on the HTTPPORT statement, if */
14 /* these where not supplied then the userid and password of the */
15 /* that hercules is running under will be used. In the latter case */
16 /* the root userid/password will also be accepted. */
17 /* */
18 /* If the request is for a /cgi-bin/ path, then the cgibin */
19 /* directory in cgibin.c will be searched, for any other request */
20 /* the sysblk.httproot (/usr/local/hercules) will be used as the */
21 /* root to find the specified file. */
22 /* */
23 /* As realpath() is used to verify that the files are from within */
24 /* the sysblk.httproot tree symbolic links that refer to files */
25 /* outside the sysblk.httproot tree are not supported. */
26 /* */
27 /* */
28 /* Jan Jaeger - 28/03/2002 */
29
30 #include "hstdinc.h"
31
32 #define _HTTPSERV_C_
33 #define _HENGINE_DLL_
34
35 #include "hercules.h"
36 #include "httpmisc.h"
37 #include "hostinfo.h"
38
39
40 #if defined(OPTION_HTTP_SERVER)
41
42 /* External reference to the cgi-bin directory in cgibin.c */
43 extern CGITAB cgidir[];
44
45
46 static MIMETAB mime_types[] = {
47 { NULL, NULL }, /* No suffix entry */
48 { "txt", "text/plain" },
49 { "jcl", "text/plain" },
50 { "gif", "image/gif" },
51 { "jpg", "image/jpeg" },
52 { "css", "text/css" },
53 { "html", "text/html" },
54 { "htm", "text/html" },
55 /* This one should be:
56 { "ico", "image/vnd.microsoft.icon" },
57 but Apache 2 sets it as: */
58 { "ico", "image/x-icon" },
59 /* so we'll go with what's actually in use. --JRM */
60 { NULL, NULL } }; /* Default suffix entry */
61
html_include(WEBBLK * webblk,char * filename)62 DLL_EXPORT int html_include(WEBBLK *webblk, char *filename)
63 {
64 FILE *inclfile;
65 char fullname[HTTP_PATH_LENGTH];
66 char buffer[HTTP_PATH_LENGTH];
67 int ret;
68
69 strlcpy( fullname, sysblk.httproot, sizeof(fullname) );
70 strlcat( fullname, filename, sizeof(fullname) );
71
72 inclfile = fopen(fullname,"rb");
73
74 if (!inclfile)
75 {
76 logmsg(_("HHCHT011E html_include: Cannot open %s: %s\n"),
77 fullname,strerror(errno));
78 hprintf(webblk->sock,_("ERROR: Cannot open %s: %s\n"),
79 filename,strerror(errno));
80 return FALSE;
81 }
82
83 while (!feof(inclfile))
84 {
85 ret = fread(buffer, 1, sizeof(buffer), inclfile);
86 if (ret <= 0) break;
87 hwrite(webblk->sock,buffer, ret);
88 }
89
90 fclose(inclfile);
91 return TRUE;
92 }
93
html_header(WEBBLK * webblk)94 DLL_EXPORT void html_header(WEBBLK *webblk)
95 {
96 if (webblk->request_type != REQTYPE_POST)
97 hprintf(webblk->sock,"Expires: 0\n");
98
99 hprintf(webblk->sock,"Content-type: text/html\n\n");
100
101 if (!html_include(webblk,HTML_HEADER))
102 hprintf(webblk->sock,"<HTML>\n<HEAD>\n<TITLE>Hercules</TITLE>\n</HEAD>\n<BODY>\n\n");
103 }
104
105
html_footer(WEBBLK * webblk)106 DLL_EXPORT void html_footer(WEBBLK *webblk)
107 {
108 if (!html_include(webblk,HTML_FOOTER))
109 hprintf(webblk->sock,"\n</BODY>\n</HTML>\n");
110 }
111
112
http_exit(WEBBLK * webblk)113 static void http_exit(WEBBLK *webblk)
114 {
115 CGIVAR *cgivar;
116 int rc;
117 if(webblk)
118 {
119 /* MS SDK docs state:
120
121 "To assure that all data is sent and received on a connected
122 socket before it is closed, an application should use shutdown
123 to close connection before calling closesocket. For example,
124 to initiate a graceful disconnect:
125
126 1, Call WSAAsyncSelect to register for FD_CLOSE notification.
127 2. Call shutdown with how=SD_SEND.
128 3. When FD_CLOSE received, call recv until zero returned,
129 or SOCKET_ERROR.
130 4. Call closesocket.
131
132 Note: The shutdown function does not block regardless of the
133 SO_LINGER setting on the socket."
134 */
135
136 // Notify other end of connection to not expect any more data from us.
137 // They should detect this via their own 'recv' returning zero bytes
138 // (thus letting them know they've thus received all the data from us
139 // they're ever going to receive). They should then do their own
140 // 'shutdown(s,SHUT_WR)' at their end letting US know we're also not
141 // going to be receiving any more data from THEM. This is called a
142 // "graceful close" of the connection...
143
144 shutdown( webblk->sock, SHUT_WR );
145
146 // Now wait for them to shudown THEIR end of the connection (i.e. wait
147 // for them to do their own 'shutdown(s,SHUT_WR)') by "hanging" on a
148 // 'recv' call until we either eventually detect they've shutdown their
149 // end of the connection (0 bytes received) or else an error occurs...
150
151 do
152 {
153 BYTE c;
154 rc = read_socket( webblk->sock, &c, 1 );
155 }
156 while ( rc > 0 );
157
158 // NOW we can SAFELY close the socket since we now KNOW for CERTAIN
159 // that they've received ALL of the data we previously sent to them...
160 // (otherwise they wouldn't have close their connection on us!)
161
162 close_socket( webblk->sock );
163
164 if(webblk->user) free(webblk->user);
165 if(webblk->request) free(webblk->request);
166 cgivar = webblk->cgivar;
167 while(cgivar)
168 {
169 CGIVAR *tmpvar = cgivar->next;
170 free(cgivar->name);
171 free(cgivar->value);
172 free(cgivar);
173 cgivar = tmpvar;
174 }
175 free(webblk);
176 }
177 exit_thread(NULL);
178 }
179
180
http_error(WEBBLK * webblk,char * err,char * header,char * info)181 static void http_error(WEBBLK *webblk, char *err, char *header, char *info)
182 {
183 hprintf(webblk->sock,"HTTP/1.0 %s\n%sConnection: close\n"
184 "Content-Type: text/html\n\n"
185 "<HTML><HEAD><TITLE>%s</TITLE></HEAD>"
186 "<BODY><H1>%s</H1><P>%s</BODY></HTML>\n\n",
187 err, header, err, err, info);
188 http_exit(webblk);
189 }
190
191
http_timestring(char * time_buff,int buff_size,time_t t)192 static char *http_timestring(char *time_buff,int buff_size, time_t t)
193 {
194 struct tm *tm = localtime(&t);
195 strftime(time_buff, buff_size, "%a, %d %b %Y %H:%M:%S %Z", tm);
196 return time_buff;
197 }
198
199
http_decode_base64(char * s)200 static void http_decode_base64(char *s)
201 {
202 char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
203 int bit_o, byte_o, idx, i, n;
204 unsigned char *d = (unsigned char *)s;
205 char *p;
206
207 n = i = 0;
208
209 while (*s && (p = strchr(b64, *s)))
210 {
211 idx = (int)(p - b64);
212 byte_o = (i*6)/8;
213 bit_o = (i*6)%8;
214 d[byte_o] &= ~((1<<(8-bit_o))-1);
215 if (bit_o < 3)
216 {
217 d[byte_o] |= (idx << (2-bit_o));
218 n = byte_o+1;
219 }
220 else
221 {
222 d[byte_o] |= (idx >> (bit_o-2));
223 d[byte_o+1] = 0;
224 d[byte_o+1] |= (idx << (8-(bit_o-2))) & 0xFF;
225 n = byte_o+2;
226 }
227 s++; i++;
228 }
229 /* null terminate */
230 d[n] = 0;
231 }
232
233
http_unescape(char * buffer)234 static char *http_unescape(char *buffer)
235 {
236 char *pointer = buffer;
237
238 while ( (pointer = strchr(pointer,'+')) )
239 *pointer = ' ';
240
241 pointer = buffer;
242
243 while (pointer && *pointer && (pointer = strchr(pointer,'%')))
244 {
245 int highnibble = pointer[1];
246 int lownibble = pointer[2];
247
248 if (highnibble >= '0' && highnibble <= '9')
249 highnibble = highnibble - '0';
250 else if (highnibble >= 'A' && highnibble <= 'F')
251 highnibble = 10 + highnibble - 'A';
252 else if (highnibble >= 'a' && highnibble <= 'f')
253 highnibble = 10 + highnibble - 'a';
254 else
255 {
256 pointer++;
257 continue;
258 }
259
260 if (lownibble >= '0' && lownibble <= '9')
261 lownibble = lownibble - '0';
262 else if (lownibble >= 'A' && lownibble <= 'F')
263 lownibble = 10 + lownibble - 'A';
264 else if (lownibble >= 'a' && lownibble <= 'f')
265 lownibble = 10 + lownibble - 'a';
266 else
267 {
268 pointer++;
269 continue;
270 }
271
272 *pointer = (highnibble<<4) | lownibble;
273
274 memmove(pointer+1, pointer+3, strlen(pointer+3)+1);
275
276 pointer++;
277 }
278
279 return buffer;
280 }
281
282
http_interpret_variable_string(WEBBLK * webblk,char * qstring,int type)283 static void http_interpret_variable_string(WEBBLK *webblk, char *qstring, int type)
284 {
285 char *name;
286 char *value;
287 char *strtok_str;
288 CGIVAR **cgivar;
289
290 for (cgivar = &(webblk->cgivar);
291 *cgivar;
292 cgivar = &((*cgivar)->next));
293
294 for (name = strtok_r(qstring,"&; ",&strtok_str);
295 name;
296 name = strtok_r(NULL,"&; ",&strtok_str))
297 {
298 if(!(value = strchr(name,'=')))
299 continue;
300
301 *value++ = '\0';
302
303 (*cgivar) = malloc(sizeof(CGIVAR));
304 (*cgivar)->next = NULL;
305 (*cgivar)->name = strdup(http_unescape(name));
306 (*cgivar)->value = strdup(http_unescape(value));
307 (*cgivar)->type = type;
308 cgivar = &((*cgivar)->next);
309 }
310 }
311
312
313 #if 0
314 static void http_dump_cgi_variables(WEBBLK *webblk)
315 {
316 CGIVAR *cv;
317 for(cv = webblk->cgivar; cv; cv = cv->next)
318 logmsg(_("HHCHT012I cgi_var_dump: pointer(%p) name(%s) value(%s) type(%d)\n"),
319 cv, cv->name, cv->value, cv->type);
320 }
321 #endif
322
323
http_variable(WEBBLK * webblk,char * name,int type)324 DLL_EXPORT char *http_variable(WEBBLK *webblk, char *name, int type)
325 {
326 CGIVAR *cv;
327 for(cv = webblk->cgivar; cv; cv = cv->next)
328 if((cv->type & type) && !strcmp(name,cv->name))
329 return cv->value;
330 return NULL;
331 }
332
333
http_verify_path(WEBBLK * webblk,char * path)334 static void http_verify_path(WEBBLK *webblk, char *path)
335 {
336 char resolved_path[HTTP_PATH_LENGTH];
337 #if 0
338 int i;
339
340 for (i = 0; path[i]; i++)
341 if (!isalnum((int)path[i]) && !strchr("/.-_", path[i]))
342 http_error(webblk, "404 File Not Found","",
343 "Illegal character in filename");
344 #endif
345
346 if (!realpath( path, resolved_path ))
347 http_error(webblk, "404 File Not Found","",
348 "Invalid pathname");
349
350 // The following verifies the specified file does not lie
351 // outside the specified httproot (Note: sysblk.httproot
352 // was previously resolved to an absolute path by config.c)
353
354 if (strncmp( sysblk.httproot, resolved_path, strlen(sysblk.httproot)))
355 http_error(webblk, "404 File Not Found","",
356 "Invalid pathname");
357 }
358
359
http_authenticate(WEBBLK * webblk,char * type,char * userpass)360 static int http_authenticate(WEBBLK *webblk, char *type, char *userpass)
361 {
362 char *pointer ,*user, *passwd;
363
364 if (!strcasecmp(type,"Basic"))
365 {
366 if(userpass)
367 {
368 http_decode_base64(userpass);
369
370 /* the format is now user:password */
371 if ((pointer = strchr(userpass,':')))
372 {
373 *pointer = 0;
374 user = userpass;
375 passwd = pointer+1;
376
377 /* Hardcoded userid and password in configuration file */
378 if(sysblk.httpuser && sysblk.httppass)
379 {
380 if(!strcmp(user,sysblk.httpuser)
381 && !strcmp(passwd,sysblk.httppass))
382 {
383 webblk->user = strdup(user);
384 return TRUE;
385 }
386 }
387 #if !defined(WIN32)
388 else
389 {
390 struct passwd *pass = NULL;
391
392 /* unix userid and password check, the userid
393 must be the same as that hercules is
394 currently running under */
395 // ZZ INCOMPLETE
396 // ZZ No password check is being performed yet...
397 if((pass = getpwnam(user))
398 &&
399 (pass->pw_uid == 0
400 || pass->pw_uid == getuid()))
401 {
402 webblk->user = strdup(user);
403 return TRUE;
404 }
405 }
406 #endif /*!defined(WIN32)*/
407 }
408 }
409 }
410
411 webblk->user = NULL;
412
413 return FALSE;
414 }
415
416
http_download(WEBBLK * webblk,char * filename)417 static void http_download(WEBBLK *webblk, char *filename)
418 {
419 char buffer[HTTP_PATH_LENGTH];
420 char tbuf[80];
421 int fd, length;
422 char *filetype;
423 char fullname[HTTP_PATH_LENGTH];
424 struct stat st;
425 MIMETAB *mime_type = mime_types;
426
427 strlcpy( fullname, sysblk.httproot, sizeof(fullname) );
428 strlcat( fullname, filename, sizeof(fullname) );
429
430 http_verify_path(webblk,fullname);
431
432 if(stat(fullname,&st))
433 http_error(webblk, "404 File Not Found","",
434 strerror(errno));
435
436 if(!S_ISREG(st.st_mode))
437 http_error(webblk, "404 File Not Found","",
438 "The requested file is not a regular file");
439
440 fd = hopen(fullname,O_RDONLY|O_BINARY,0);
441 if (fd == -1)
442 http_error(webblk, "404 File Not Found","",
443 strerror(errno));
444
445 hprintf(webblk->sock,"HTTP/1.0 200 OK\n");
446 if ((filetype = strrchr(filename,'.')))
447 for(mime_type++;mime_type->suffix
448 && strcasecmp(mime_type->suffix,filetype + 1);
449 mime_type++);
450 if(mime_type->type)
451 hprintf(webblk->sock,"Content-Type: %s\n", mime_type->type);
452
453 hprintf(webblk->sock,"Expires: %s\n",
454 http_timestring(tbuf,sizeof(tbuf),time(NULL)+HTML_STATIC_EXPIRY_TIME));
455
456 hprintf(webblk->sock,"Content-Length: %d\n\n", (int)st.st_size);
457 while ((length = read(fd, buffer, sizeof(buffer))) > 0)
458 hwrite(webblk->sock,buffer, length);
459 close(fd);
460 http_exit(webblk);
461 }
462
463
http_request(int sock)464 static void *http_request(int sock)
465 {
466 WEBBLK *webblk;
467 int authok = !sysblk.httpauth;
468 char line[HTTP_PATH_LENGTH];
469 char *url = NULL;
470 char *pointer;
471 char *strtok_str;
472 CGITAB *cgient;
473 int content_length = 0;
474
475 if(!(webblk = malloc(sizeof(WEBBLK))))
476 http_exit(webblk);
477
478 memset(webblk,0,sizeof(WEBBLK));
479 webblk->sock = sock;
480
481 while (hgets(line, sizeof(line), webblk->sock))
482 {
483 if (*line == '\r' || *line == '\n')
484 break;
485
486 if((pointer = strtok_r(line," \t\r\n",&strtok_str)))
487 {
488 if(!strcasecmp(pointer,"GET"))
489 {
490 if((pointer = strtok_r(NULL," \t\r\n",&strtok_str)))
491 {
492 webblk->request_type = REQTYPE_GET;
493 url = strdup(pointer);
494 }
495 }
496 else
497 if(!strcasecmp(pointer,"POST"))
498 {
499 if((pointer = strtok_r(NULL," \t\r\n",&strtok_str)))
500 {
501 webblk->request_type = REQTYPE_POST;
502 url = strdup(pointer);
503 }
504 }
505 else
506 if(!strcasecmp(pointer,"PUT"))
507 {
508 http_error(webblk,"400 Bad Request", "",
509 "This server does not accept PUT requests");
510 }
511 else
512 if(!strcasecmp(pointer,"Authorization:"))
513 {
514 if((pointer = strtok_r(NULL," \t\r\n",&strtok_str)))
515 authok = http_authenticate(webblk,pointer,
516 strtok_r(NULL," \t\r\n",&strtok_str));
517 }
518 else
519 if(!strcasecmp(pointer,"Cookie:"))
520 {
521 if((pointer = strtok_r(NULL,"\r\n",&strtok_str)))
522 http_interpret_variable_string(webblk, pointer, VARTYPE_COOKIE);
523 }
524 else
525 if(!strcasecmp(pointer,"Content-Length:"))
526 {
527 if((pointer = strtok_r(NULL," \t\r\n",&strtok_str)))
528 content_length = atoi(pointer);
529 }
530 }
531 }
532 webblk->request = url;
533
534 if(webblk->request_type == REQTYPE_POST
535 && content_length != 0)
536 {
537 char *post_arg;
538 if((pointer = post_arg = malloc(content_length + 1)))
539 {
540 int i;
541 for(i = 0; i < content_length; i++)
542 {
543 *pointer = hgetc(webblk->sock);
544 if(*pointer != '\n' && *pointer != '\r')
545 pointer++;
546 }
547 *pointer = '\0';
548 http_interpret_variable_string(webblk, post_arg, VARTYPE_POST);
549 free(post_arg);
550 }
551 }
552
553 if (!authok)
554 http_error(webblk, "401 Authorization Required",
555 "WWW-Authenticate: Basic realm=\"HERCULES\"\n",
556 "You must be authenticated to use this service");
557
558 if (!url)
559 http_error(webblk,"400 Bad Request", "",
560 "You must specify a GET or POST request");
561
562 /* anything following a ? in the URL is part of the get arguments */
563 if ((pointer=strchr(url,'?'))) {
564 *pointer++ = 0;
565 http_interpret_variable_string(webblk, pointer, VARTYPE_GET);
566 }
567
568 while(url[0] == '/' && url[1] == '/')
569 url++;
570
571 webblk->baseurl = url;
572
573 if(!strcasecmp("/",url))
574 url = HTTP_WELCOME;
575
576 if(strncasecmp("/cgi-bin/",url,9))
577 http_download(webblk,url);
578 else
579 url += 9;
580
581 while(*url == '/')
582 url++;
583
584 #if 0
585 http_dump_cgi_variables(webblk);
586 #endif
587
588 for(cgient = cgidir; cgient->path; cgient++)
589 {
590 if(!strcmp(cgient->path, url))
591 {
592 char tbuf[80];
593 hprintf(webblk->sock,"HTTP/1.0 200 OK\nConnection: close\n");
594 hprintf(webblk->sock,"Date: %s\n",
595 http_timestring(tbuf,sizeof(tbuf),time(NULL)));
596 (cgient->cgibin) (webblk);
597 http_exit(webblk);
598 }
599 }
600
601 #if defined(OPTION_DYNAMIC_LOAD)
602 {
603 zz_cgibin dyncgi;
604
605 if( (dyncgi = HDL_FINDSYM(webblk->baseurl)) )
606 {
607 char tbuf[80];
608 hprintf(webblk->sock,"HTTP/1.0 200 OK\nConnection: close\n");
609 hprintf(webblk->sock,"Date: %s\n",
610 http_timestring(tbuf,sizeof(tbuf),time(NULL)));
611 dyncgi(webblk);
612 http_exit(webblk);
613 }
614 }
615 #endif /*defined(OPTION_DYNAMIC_LOAD)*/
616
617 http_error(webblk, "404 File Not Found","",
618 "The requested file was not found");
619
620 return NULL;
621 }
622
623
http_server(void * arg)624 void *http_server (void *arg)
625 {
626 int rc; /* Return code */
627 int lsock; /* Socket for listening */
628 int csock; /* Socket for conversation */
629 struct sockaddr_in server; /* Server address structure */
630 fd_set selset; /* Read bit map for select */
631 int optval; /* Argument for setsockopt */
632 TID httptid; /* Negotiation thread id */
633
634 UNREFERENCED(arg);
635
636 /* Display thread started message on control panel */
637 logmsg (_("HHCHT001I HTTP listener thread started: "
638 "tid="TIDPAT", pid=%d\n"),
639 thread_id(), getpid());
640
641
642 /* If the HTTP root directory is not specified,
643 use a reasonable default */
644 if (!sysblk.httproot)
645 {
646 #if defined(_MSVC_)
647 char process_dir[HTTP_PATH_LENGTH];
648 if (get_process_directory(process_dir,HTTP_PATH_LENGTH) > 0)
649 {
650 strlcat(process_dir,"\\html",HTTP_PATH_LENGTH);
651 sysblk.httproot = strdup(process_dir);
652 }
653 else
654 #endif /*defined(WIN32)*/
655 sysblk.httproot = strdup(HTTP_ROOT);
656 }
657
658 /* Convert the specified HTTPROOT value to an absolute path
659 ending with a '/' and save in sysblk.httproot. */
660 {
661 char absolute_httproot_path[HTTP_PATH_LENGTH];
662 int rc;
663 #if defined(_MSVC_)
664 /* Expand any embedded %var% environ vars */
665 rc = expand_environ_vars( sysblk.httproot, absolute_httproot_path,
666 sizeof(absolute_httproot_path) );
667 if (rc == 0)
668 {
669 free(sysblk.httproot);
670 sysblk.httproot = strdup(absolute_httproot_path);
671 }
672 #endif /* defined(_MSVC_) */
673 /* Convert to absolute path */
674 if (!realpath(sysblk.httproot,absolute_httproot_path))
675 {
676 logmsg( _("HHCCF066E Invalid HTTPROOT: \"%s\": %s\n"),
677 sysblk.httproot, strerror(errno));
678 return NULL;
679 }
680 /* Verify that the absolute path is valid */
681 // mode: 0 = exist only, 2 = write, 4 = read, 6 = read/write
682 // rc: 0 = success, -1 = error (errno = cause)
683 // ENOENT = File name or path not found.
684 if (access( absolute_httproot_path, R_OK ) != 0)
685 {
686 logmsg( _("HHCCF066E Invalid HTTPROOT: \"%s\": %s\n"),
687 absolute_httproot_path, strerror(errno));
688 return NULL;
689 }
690 /* Append trailing [back]slash, but only if needed */
691 rc = strlen(absolute_httproot_path);
692 if (absolute_httproot_path[rc-1] != *HTTP_PS)
693 strlcat(absolute_httproot_path,HTTP_PS,sizeof(absolute_httproot_path));
694 /* Save the absolute path */
695 free(sysblk.httproot);
696 sysblk.httproot = strdup(absolute_httproot_path);
697 logmsg(_("HHCHT013I Using HTTPROOT directory \"%s\"\n"),sysblk.httproot);
698 }
699
700 /* Obtain a socket */
701 lsock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
702
703 if (lsock < 0)
704 {
705 logmsg(_("HHCHT002E socket: %s\n"), strerror(HSO_errno));
706 return NULL;
707 }
708
709 /* Allow previous instance of socket to be reused */
710 optval = 1;
711 setsockopt (lsock, SOL_SOCKET, SO_REUSEADDR,
712 (void*)&optval, sizeof(optval));
713
714 /* Prepare the sockaddr structure for the bind */
715 memset (&server, 0, sizeof(server));
716 server.sin_family = AF_INET;
717 server.sin_addr.s_addr = INADDR_ANY;
718 server.sin_port = sysblk.httpport;
719 server.sin_port = htons(server.sin_port);
720
721 /* Attempt to bind the socket to the port */
722 while (TRUE)
723 {
724 rc = bind (lsock, (struct sockaddr *)&server, sizeof(server));
725
726 if (rc == 0 || HSO_errno != HSO_EADDRINUSE) break;
727
728 logmsg (_("HHCHT003W Waiting for port %u to become free\n"),
729 sysblk.httpport);
730 SLEEP(10);
731 } /* end while */
732
733 if (rc != 0)
734 {
735 logmsg(_("HHCHT004E bind: %s\n"), strerror(HSO_errno));
736 return NULL;
737 }
738
739 /* Put the socket into listening state */
740 rc = listen (lsock, 32);
741
742 if (rc < 0)
743 {
744 logmsg(_("HHCHT005E listen: %s\n"), strerror(HSO_errno));
745 return NULL;
746 }
747
748 logmsg(_("HHCHT006I Waiting for HTTP requests on port %u\n"),
749 sysblk.httpport);
750
751 /* Handle http requests */
752 while (sysblk.httpport) {
753
754 /* Initialize the select parameters */
755 FD_ZERO (&selset);
756 FD_SET (lsock, &selset);
757
758 /* Wait for a file descriptor to become ready */
759 rc = select ( lsock+1, &selset, NULL, NULL, NULL );
760
761 if (rc == 0) continue;
762
763 if (rc < 0 )
764 {
765 if (HSO_errno == HSO_EINTR) continue;
766 logmsg(_("HHCHT007E select: %s\n"), strerror(HSO_errno));
767 break;
768 }
769
770 /* If a http request has arrived then accept it */
771 if (FD_ISSET(lsock, &selset))
772 {
773 /* Accept the connection and create conversation socket */
774 csock = accept (lsock, NULL, NULL);
775
776 if (csock < 0)
777 {
778 logmsg(_("HHCHT008E accept: %s\n"), strerror(HSO_errno));
779 continue;
780 }
781
782 /* Create a thread to execute the http request */
783 if ( create_thread (&httptid, DETACHED,
784 http_request, (void *)(uintptr_t)csock,
785 "http_request")
786 )
787 {
788 logmsg(_("HHCHT010E http_request create_thread: %s\n"),
789 strerror(errno));
790 close_socket (csock);
791 }
792
793 } /* end if(lsock) */
794
795 } /* end while */
796
797 /* Close the listening socket */
798 close_socket (lsock);
799
800 /* Display thread started message on control panel */
801 logmsg (_("HHCHT009I HTTP listener thread ended: "
802 "tid="TIDPAT", pid=%d\n"),
803 thread_id(), getpid());
804
805 sysblk.httptid = 0;
806
807 return NULL;
808
809 } /* end function http_server */
810
811 #endif /*defined(OPTION_HTTP_SERVER)*/
812