11#include "server.h"
2+ #include <poll.h>
3+ #include <fcntl.h>
24
3- #define MAX_CLIENTS 50
4- #define REQSIZE (512 * 1024)
5+ #define HTTP_MAX_CLIENTS 50
6+ #define HTTP_MIN_BUF_SIZE 4096
7+ #define HTTP_MAX_BUF_SIZE (4 * 1024 * 1024)
58
69IMPORT_STR (.rodata , "../res/index.html" , indexhtml );
710extern const char indexhtml [];
@@ -21,14 +24,16 @@ typedef struct {
2124 int clntFd ;
2225 char * input , * method , * payload , * prot , * query , * uri ;
2326 int paysize , total ;
27+ size_t buf_size ;
28+ int header_len ;
2429} http_request_t ;
2530
2631struct {
2732 int sockFd ;
2833 enum StreamType type ;
2934 struct Mp4State mp4 ;
3035 unsigned int nalCnt ;
31- } client_fds [MAX_CLIENTS ];
36+ } client_fds [HTTP_MAX_CLIENTS ];
3237
3338typedef struct {
3439 char * name , * value ;
@@ -147,7 +152,7 @@ void send_h26x_to_client(char index, hal_vidstream *stream) {
147152 unsigned char * pack_data = pack -> data + pack -> offset ;
148153
149154 pthread_mutex_lock (& client_fds_mutex );
150- for (unsigned int i = 0 ; i < MAX_CLIENTS ; ++ i ) {
155+ for (unsigned int i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i ) {
151156 if (client_fds [i ].sockFd < 0 ) continue ;
152157 if (client_fds [i ].type != STREAM_H26X ) continue ;
153158
@@ -212,7 +217,7 @@ void send_mp4_to_client(char index, hal_vidstream *stream, char isH265) {
212217 static enum BufError err ;
213218 static char len_buf [50 ];
214219 pthread_mutex_lock (& client_fds_mutex );
215- for (unsigned int i = 0 ; i < MAX_CLIENTS ; ++ i ) {
220+ for (unsigned int i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i ) {
216221 if (client_fds [i ].sockFd < 0 ) continue ;
217222 if (client_fds [i ].type != STREAM_MP4 ) continue ;
218223
@@ -269,7 +274,7 @@ void send_mp4_to_client(char index, hal_vidstream *stream, char isH265) {
269274
270275void send_mp3_to_client (char * buf , ssize_t size ) {
271276 pthread_mutex_lock (& client_fds_mutex );
272- for (unsigned int i = 0 ; i < MAX_CLIENTS ; ++ i ) {
277+ for (unsigned int i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i ) {
273278 if (client_fds [i ].sockFd < 0 ) continue ;
274279 if (client_fds [i ].type != STREAM_MP3 ) continue ;
275280
@@ -287,7 +292,7 @@ void send_mp3_to_client(char *buf, ssize_t size) {
287292
288293void send_pcm_to_client (hal_audframe * frame ) {
289294 pthread_mutex_lock (& client_fds_mutex );
290- for (unsigned int i = 0 ; i < MAX_CLIENTS ; ++ i ) {
295+ for (unsigned int i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i ) {
291296 if (client_fds [i ].sockFd < 0 ) continue ;
292297 if (client_fds [i ].type != STREAM_PCM ) continue ;
293298
@@ -313,7 +318,7 @@ void send_mjpeg_to_client(char index, char *buf, ssize_t size) {
313318 buf [size ++ ] = '\n' ;
314319
315320 pthread_mutex_lock (& client_fds_mutex );
316- for (unsigned int i = 0 ; i < MAX_CLIENTS ; ++ i ) {
321+ for (unsigned int i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i ) {
317322 if (client_fds [i ].sockFd < 0 ) continue ;
318323 if (client_fds [i ].type != STREAM_MJPEG ) continue ;
319324
@@ -337,7 +342,7 @@ void send_jpeg_to_client(char index, char *buf, ssize_t size) {
337342 buf [size ++ ] = '\n' ;
338343
339344 pthread_mutex_lock (& client_fds_mutex );
340- for (unsigned int i = 0 ; i < MAX_CLIENTS ; ++ i ) {
345+ for (unsigned int i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i ) {
341346 if (client_fds [i ].sockFd < 0 ) continue ;
342347 if (client_fds [i ].type != STREAM_JPEG ) continue ;
343348
@@ -480,26 +485,24 @@ void parse_request(http_request_t *req) {
480485 if (ip_in_cidr (client_ip , app_config .web_whitelist [i ])) goto grant_access ;
481486 close_socket_fd (req -> clntFd );
482487 req -> clntFd = -1 ;
483- req -> total = 0 ;
484488 return ;
485489 }
486490
487491grant_access :
488- req -> total = 0 ;
489- int received = recv (req -> clntFd , req -> input , REQSIZE , 0 );
490- if (received < 0 )
491- HAL_WARNING ("server" , "Reading from client failed!\n" );
492- else if (!received )
493- HAL_WARNING ("server" , "Client disconnected unexpectedly!\n" );
494- req -> total += received ;
495-
496492 if (req -> total <= 0 ) return ;
497493
494+ req -> input [req -> total ] = '\0' ;
498495 char * state = NULL ;
499496 req -> method = strtok_r (req -> input , " \t\r\n" , & state );
500497 req -> uri = strtok_r (NULL , " \t" , & state );
501498 req -> prot = strtok_r (NULL , " \t\r\n" , & state );
502499
500+ if (!req -> method || !req -> uri || !req -> prot ) {
501+ close_socket_fd (req -> clntFd );
502+ req -> clntFd = -1 ;
503+ return ;
504+ }
505+
503506 HAL_INFO ("server" , "\x1b[32mNew request: (%s) %s\n"
504507 " Received from: %s\x1b[0m\n" ,
505508 req -> method , req -> uri , client_ip );
@@ -510,39 +513,25 @@ void parse_request(http_request_t *req) {
510513 req -> query = req -> uri - 1 ;
511514
512515 http_header_t * h = http_headers ;
513- char * l ;
514516 while (h < http_headers + 16 ) {
515517 char * k , * v , * e ;
516518 if (!(k = strtok_r (NULL , "\r\n: \t" , & state )))
517519 break ;
518520 v = strtok_r (NULL , "\r\n" , & state );
521+ if (!v ) break ;
519522 while (* v && * v == ' ' && v ++ );
520523 h -> name = k ;
521524 h ++ -> value = v ;
522525#ifdef DEBUG_HTTP
523526 fprintf (stderr , " (H) %s: %s\n" , k , v );
524527#endif
528+ if (state >= req -> input + req -> header_len ) break ;
525529 e = v + 1 + strlen (v );
526530 if (e [1 ] == '\r' && e [2 ] == '\n' )
527531 break ;
528532 }
529533
530- l = request_header ("Content-Length" );
531- req -> paysize = l ? atol (l ) : 0 ;
532-
533- while (l && req -> total < req -> paysize ) {
534- received = recv (req -> clntFd , req -> input + req -> total , REQSIZE - req -> total , 0 );
535- if (received < 0 ) {
536- HAL_WARNING ("server" , "Reading from client failed!\n" );
537- break ;
538- } else if (!received ) {
539- HAL_WARNING ("server" , "Client disconnected unexpectedly!\n" );
540- break ;
541- }
542- req -> total += received ;
543- }
544-
545- req -> payload = strtok_r (NULL , "\r\n" , & state );
534+ req -> payload = req -> input + req -> header_len ;
546535}
547536
548537void respond_request (http_request_t * req ) {
@@ -680,7 +669,7 @@ void respond_request(http_request_t *req) {
680669 "Connection: keep-alive\r\n\r\n" );
681670 send_to_fd (req -> clntFd , response , respLen );
682671 pthread_mutex_lock (& client_fds_mutex );
683- for (uint32_t i = 0 ; i < MAX_CLIENTS ; ++ i )
672+ for (uint32_t i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i )
684673 if (client_fds [i ].sockFd < 0 ) {
685674 client_fds [i ].sockFd = req -> clntFd ;
686675 client_fds [i ].type = STREAM_MP3 ;
@@ -698,7 +687,7 @@ void respond_request(http_request_t *req) {
698687 "Connection: keep-alive\r\n\r\n" );
699688 send_to_fd (req -> clntFd , response , respLen );
700689 pthread_mutex_lock (& client_fds_mutex );
701- for (uint32_t i = 0 ; i < MAX_CLIENTS ; ++ i )
690+ for (uint32_t i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i )
702691 if (client_fds [i ].sockFd < 0 ) {
703692 client_fds [i ].sockFd = req -> clntFd ;
704693 client_fds [i ].type = STREAM_PCM ;
@@ -718,7 +707,7 @@ void respond_request(http_request_t *req) {
718707 "Connection: keep-alive\r\n\r\n" );
719708 send_to_fd (req -> clntFd , response , respLen );
720709 pthread_mutex_lock (& client_fds_mutex );
721- for (uint32_t i = 0 ; i < MAX_CLIENTS ; ++ i )
710+ for (uint32_t i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i )
722711 if (client_fds [i ].sockFd < 0 ) {
723712 client_fds [i ].sockFd = req -> clntFd ;
724713 client_fds [i ].type = STREAM_H26X ;
@@ -738,7 +727,7 @@ void respond_request(http_request_t *req) {
738727 "Connection: keep-alive\r\n\r\n" );
739728 send_to_fd (req -> clntFd , response , respLen );
740729 pthread_mutex_lock (& client_fds_mutex );
741- for (uint32_t i = 0 ; i < MAX_CLIENTS ; ++ i )
730+ for (uint32_t i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i )
742731 if (client_fds [i ].sockFd < 0 ) {
743732 client_fds [i ].sockFd = req -> clntFd ;
744733 client_fds [i ].type = STREAM_MP4 ;
@@ -758,7 +747,7 @@ void respond_request(http_request_t *req) {
758747 "Content-Type: multipart/x-mixed-replace; boundary=boundarydonotcross\r\n\r\n" );
759748 send_to_fd (req -> clntFd , response , respLen );
760749 pthread_mutex_lock (& client_fds_mutex );
761- for (uint32_t i = 0 ; i < MAX_CLIENTS ; ++ i )
750+ for (uint32_t i = 0 ; i < HTTP_MAX_CLIENTS ; ++ i )
762751 if (client_fds [i ].sockFd < 0 ) {
763752 client_fds [i ].sockFd = req -> clntFd ;
764753 client_fds [i ].type = STREAM_MJPEG ;
@@ -1464,13 +1453,15 @@ void respond_request(http_request_t *req) {
14641453}
14651454
14661455void * server_thread (void * vargp ) {
1467- http_request_t req = {0 };
14681456 int ret , server_fd = * ((int * )vargp );
14691457 int enable = 1 ;
14701458 if (setsockopt (server_fd , SOL_SOCKET , SO_REUSEADDR , & enable , sizeof (int )) < 0 ) {
14711459 HAL_WARNING ("server" , "setsockopt(SO_REUSEADDR) failed" );
14721460 fflush (stdout );
14731461 }
1462+
1463+ fcntl (server_fd , F_SETFL , fcntl (server_fd , F_GETFL , 0 ) | O_NONBLOCK );
1464+
14741465 struct sockaddr_in client , server = {
14751466 .sin_family = AF_INET ,
14761467 .sin_port = htons (app_config .web_port ),
@@ -1484,27 +1475,141 @@ void *server_thread(void *vargp) {
14841475 }
14851476 listen (server_fd , 128 );
14861477
1487- req .input = malloc (REQSIZE );
1478+ struct pollfd fds [HTTP_MAX_CLIENTS + 1 ];
1479+ http_request_t reqs [HTTP_MAX_CLIENTS ];
1480+
1481+ for (int i = 0 ; i < HTTP_MAX_CLIENTS ; i ++ ) {
1482+ fds [i + 1 ].fd = -1 ;
1483+ reqs [i ].clntFd = -1 ;
1484+ reqs [i ].input = NULL ;
1485+ }
1486+
1487+ fds [0 ].fd = server_fd ;
1488+ fds [0 ].events = POLLIN ;
14881489
14891490 while (keepRunning ) {
1490- if ((req .clntFd = accept (server_fd , NULL , NULL )) == -1 )
1491+ int poll_count = poll (fds , HTTP_MAX_CLIENTS + 1 , 1000 );
1492+ if (poll_count < 0 ) {
1493+ if (errno == EINTR ) continue ;
14911494 break ;
1495+ }
1496+
1497+ if (fds [0 ].revents & POLLIN ) {
1498+ struct sockaddr_in client_sock ;
1499+ socklen_t client_sock_len = sizeof (client_sock );
1500+ int clntFd = accept (server_fd , (struct sockaddr * )& client_sock , & client_sock_len );
1501+ if (clntFd >= 0 ) {
1502+ fcntl (clntFd , F_SETFL , fcntl (clntFd , F_GETFL , 0 ) | O_NONBLOCK );
1503+ int i = 0 ;
1504+ for (i = 0 ; i < HTTP_MAX_CLIENTS ; i ++ ) {
1505+ if (fds [i + 1 ].fd == -1 ) {
1506+ fds [i + 1 ].fd = clntFd ;
1507+ fds [i + 1 ].events = POLLIN ;
1508+ reqs [i ].clntFd = clntFd ;
1509+ reqs [i ].total = 0 ;
1510+ reqs [i ].buf_size = HTTP_MIN_BUF_SIZE ;
1511+ reqs [i ].input = malloc (reqs [i ].buf_size + 1 );
1512+ reqs [i ].header_len = 0 ;
1513+ reqs [i ].paysize = 0 ;
1514+ break ;
1515+ }
1516+ }
1517+ if (i == HTTP_MAX_CLIENTS ) {
1518+ close_socket_fd (clntFd );
1519+ }
1520+ }
1521+ }
1522+
1523+ for (int i = 0 ; i < HTTP_MAX_CLIENTS ; i ++ ) {
1524+ if (fds [i + 1 ].fd != -1 ) {
1525+ if (fds [i + 1 ].revents & (POLLERR | POLLHUP | POLLNVAL )) {
1526+ close_socket_fd (fds [i + 1 ].fd );
1527+ fds [i + 1 ].fd = -1 ;
1528+ free (reqs [i ].input );
1529+ reqs [i ].input = NULL ;
1530+ continue ;
1531+ }
1532+ if (fds [i + 1 ].revents & POLLIN ) {
1533+ http_request_t * req = & reqs [i ];
1534+
1535+ if (req -> total == req -> buf_size ) {
1536+ req -> buf_size *= 2 ;
1537+ if (req -> buf_size > HTTP_MAX_BUF_SIZE ) {
1538+ close_socket_fd (req -> clntFd );
1539+ fds [i + 1 ].fd = -1 ;
1540+ free (req -> input );
1541+ req -> input = NULL ;
1542+ continue ;
1543+ }
1544+ req -> input = realloc (req -> input , req -> buf_size + 1 );
1545+ }
14921546
1493- parse_request (& req );
1547+ int received = recv (req -> clntFd , req -> input + req -> total , req -> buf_size - req -> total , 0 );
1548+ if (received < 0 ) {
1549+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR )
1550+ continue ;
1551+ close_socket_fd (req -> clntFd );
1552+ fds [i + 1 ].fd = -1 ;
1553+ free (req -> input );
1554+ req -> input = NULL ;
1555+ continue ;
1556+ } else if (received == 0 ) {
1557+ close_socket_fd (req -> clntFd );
1558+ fds [i + 1 ].fd = -1 ;
1559+ free (req -> input );
1560+ req -> input = NULL ;
1561+ continue ;
1562+ }
1563+ req -> total += received ;
1564+
1565+ if (req -> header_len == 0 ) {
1566+ char * hdr_end = memstr (req -> input , "\r\n\r\n" , req -> total , 4 );
1567+ if (hdr_end ) {
1568+ req -> header_len = (hdr_end + 4 ) - req -> input ;
1569+
1570+ char * cl = req -> input ;
1571+ req -> paysize = 0 ;
1572+ while (cl < hdr_end ) {
1573+ if (!strncasecmp (cl , "Content-Length:" , 15 )) {
1574+ req -> paysize = atoi (cl + 15 );
1575+ break ;
1576+ }
1577+ cl = strchr (cl , '\n' );
1578+ if (!cl ) break ;
1579+ cl ++ ;
1580+ }
1581+ }
1582+ }
14941583
1495- respond_request (& req );
1584+ if (req -> header_len > 0 && req -> total >= req -> header_len + req -> paysize ) {
1585+ parse_request (req );
1586+ if (req -> clntFd != -1 ) {
1587+ fcntl (req -> clntFd , F_SETFL , fcntl (req -> clntFd , F_GETFL , 0 ) & ~O_NONBLOCK );
1588+ respond_request (req );
1589+ }
1590+ fds [i + 1 ].fd = -1 ;
1591+ free (req -> input );
1592+ req -> input = NULL ;
1593+ }
1594+ }
1595+ }
1596+ }
14961597 }
14971598
1498- if (req .input )
1499- free (req .input );
1599+ for (int i = 0 ; i < HTTP_MAX_CLIENTS ; i ++ ) {
1600+ if (fds [i + 1 ].fd != -1 ) {
1601+ close_socket_fd (fds [i + 1 ].fd );
1602+ free (reqs [i ].input );
1603+ }
1604+ }
15001605
15011606 close_socket_fd (server_fd );
15021607 HAL_INFO ("server" , "Thread has exited\n" );
15031608 return NULL ;
15041609}
15051610
15061611int start_server () {
1507- for (unsigned int i = 0 ; i < MAX_CLIENTS ; i ++ ) {
1612+ for (int i = 0 ; i < HTTP_MAX_CLIENTS ; i ++ ) {
15081613 client_fds [i ].sockFd = -1 ;
15091614 client_fds [i ].type = -1 ;
15101615 }
@@ -1517,7 +1622,7 @@ int start_server() {
15171622 pthread_attr_init (& thread_attr );
15181623 size_t stacksize ;
15191624 pthread_attr_getstacksize (& thread_attr , & stacksize );
1520- size_t new_stacksize = app_config .web_server_thread_stack_size + REQSIZE ;
1625+ size_t new_stacksize = app_config .web_server_thread_stack_size ;
15211626 if (pthread_attr_setstacksize (& thread_attr , new_stacksize ))
15221627 HAL_WARNING ("server" , "Can't set stack size %zu\n" , new_stacksize );
15231628 if (pthread_create (
0 commit comments