LCOV - code coverage report
Current view: top level - ballet/http - fuzz_httpserver.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 9 441 2.0 %
Date: 2025-01-08 12:08:44 Functions: 1 22 4.5 %

          Line data    Source code
       1             : #if !FD_HAS_HOSTED
       2             : #error "This target requires FD_HAS_HOSTED"
       3             : #endif
       4             : 
       5             : #include <assert.h>
       6             : #include <stdio.h>
       7             : #include <stdlib.h>
       8             : #include <unistd.h>
       9             : #include <arpa/inet.h>
      10             : #include <netinet/in.h>
      11             : #include <pthread.h>
      12             : #include <poll.h>
      13             : #include <errno.h>
      14             : 
      15             : #include "../../util/fd_util.h"
      16             : #include "../../util/sanitize/fd_fuzz.h"
      17             : #include "fd_http_server_private.h"
      18             : #include "fd_http_server.h"
      19             : 
      20           0 : #define FD_HTTP_SERVER_GUI_MAX_CONNS             4
      21             : #define FD_HTTP_SERVER_GUI_MAX_REQUEST_LEN       2048
      22           0 : #define FD_HTTP_SERVER_GUI_MAX_WS_CONNS          4
      23             : #define FD_HTTP_SERVER_GUI_MAX_WS_RECV_FRAME_LEN 2048
      24             : #define FD_HTTP_SERVER_GUI_MAX_WS_SEND_FRAME_CNT 8192
      25             : #define FD_HTTP_SERVER_GUI_OUTGOING_BUFFER_SZ    (1UL<<28UL) /* 256MiB reserved for buffering GUI websockets */
      26             : 
      27             : const fd_http_server_params_t PARAMS = {
      28             :   .max_connection_cnt    = FD_HTTP_SERVER_GUI_MAX_CONNS,
      29             :   .max_ws_connection_cnt = FD_HTTP_SERVER_GUI_MAX_WS_CONNS,
      30             :   .max_request_len       = FD_HTTP_SERVER_GUI_MAX_REQUEST_LEN,
      31             :   .max_ws_recv_frame_len = FD_HTTP_SERVER_GUI_MAX_WS_RECV_FRAME_LEN,
      32             :   .max_ws_send_frame_cnt = FD_HTTP_SERVER_GUI_MAX_WS_SEND_FRAME_CNT,
      33             :   .outgoing_buffer_sz    = FD_HTTP_SERVER_GUI_OUTGOING_BUFFER_SZ,
      34             : };
      35             : 
      36             : struct Unstructured {
      37             :     uchar const *data;
      38             :     ulong size;
      39             :     ulong used;
      40             : };
      41             : 
      42           0 : uchar rand_uchar(struct Unstructured *u) {
      43           0 :     if (sizeof(uchar) + u->used < u->size) {
      44           0 :         uchar v = *(uchar *)(u->data + u->used);
      45           0 :         u->used += sizeof(uchar);
      46           0 :         return v;
      47           0 :     }
      48           0 :     return (uchar) rand();
      49           0 : }
      50             : 
      51           0 : uint rand_uint(struct Unstructured *u) {
      52           0 :     if (sizeof(uint) + u->used < u->size) {
      53           0 :         uint v = *(uint *)(u->data + u->used);
      54           0 :         u->used += sizeof(uint);
      55           0 :         return v;
      56           0 :     }
      57           0 :     return (uint) rand();
      58           0 : }
      59             : 
      60           0 : ulong rand_ulong(struct Unstructured *u) {
      61           0 :     if (sizeof(ulong) + u->used < u->size) {
      62           0 :         ulong v = *(ulong *)(u->data + u->used);
      63           0 :         u->used += sizeof(ulong);
      64           0 :         return v;
      65           0 :     }
      66           0 :     return ((ulong)rand()) << 32 | ((ulong)rand());
      67           0 : }
      68             : 
      69           0 : void rand_bytes(struct Unstructured *u, size_t len, uchar *p) {
      70           0 :     if (len + u->used < u->size) {
      71           0 :         memcpy(p, u->data + u->used, len);
      72           0 :         u->used += len;
      73           0 :     } else {
      74           0 :         for (ulong i = 0; i < len; ++i) {
      75           0 :             p[i] = (uchar) rand();
      76           0 :         }
      77           0 :     }
      78           0 : }
      79             : 
      80             : void build_http_req(struct Unstructured *u, uchar *buf, int *len, int *use_websocket);
      81             : void build_ws_req(struct Unstructured *u, uchar *buf, int *len);
      82             : 
      83             : static fd_http_server_t *http_server = NULL;
      84             : uint16_t port = 0;
      85             : static int clients_fd[FD_HTTP_SERVER_GUI_MAX_CONNS * 2] = {-1};
      86             : static char clients_ws_fd[FD_HTTP_SERVER_GUI_MAX_CONNS * 2] = {0};
      87             : static uint clients_fd_cnt = 0;
      88             : 
      89           0 : void reset_clients_fd(void) {
      90           0 :   clients_fd_cnt = 0;
      91           0 :   for (ulong i = 0; i < FD_HTTP_SERVER_GUI_MAX_CONNS * 2; ++i) {
      92           0 :     clients_fd[i] = -1;
      93           0 :     clients_ws_fd[i] = 0;
      94           0 :   }
      95           0 : }
      96             : 
      97             : int
      98             : LLVMFuzzerInitialize( int  *   argc,
      99          18 :                       char *** argv ) {
     100             :   /* Set up shell without signal handlers */
     101          18 :   putenv( "FD_LOG_BACKTRACE=0" );
     102          18 :   fd_boot( argc, argv );
     103          18 :   atexit( fd_halt );
     104          18 :   fd_log_level_core_set(3); /* crash on warning log */
     105             : 
     106             :   /* Disable parsing error logging */
     107          18 :   fd_log_level_stderr_set(4);
     108             : 
     109          18 :   reset_clients_fd();
     110             : 
     111          18 :   return 0;
     112          18 : }
     113             : 
     114             : typedef struct {
     115             :     uint32_t state;
     116             : } Xorshift;
     117             : 
     118           0 : void xorshift_init(Xorshift* x, uint32_t seed) {
     119           0 :     x->state = seed ? seed : 1;
     120           0 : }
     121             : 
     122           0 : uint32_t xorshift_next(Xorshift* x) {
     123           0 :     uint32_t s = x->state;
     124           0 :     s ^= s << 13;
     125           0 :     s ^= s >> 17;
     126           0 :     s ^= s << 5;
     127           0 :     x->state = s;
     128           0 :     return s;
     129           0 : }
     130             : 
     131             : static Xorshift poll_rng;
     132             : 
     133             : void
     134             : fd_http_server_close( fd_http_server_t * http,
     135             :                       ulong              conn_id,
     136             :                       int                reason );
     137             : 
     138             : void
     139             : fd_http_server_ws_close( fd_http_server_t * http,
     140             :                          ulong              ws_conn_id,
     141             :                          int                reason );
     142             : int
     143             : fd_http_server_ws_send( fd_http_server_t * http,
     144             :                         ulong              ws_conn_id );
     145             : 
     146             : int
     147             : fd_http_server_ws_broadcast( fd_http_server_t * http );
     148             : 
     149             : void
     150             : fd_http_server_printf( fd_http_server_t * http,
     151             :                        char const *       fmt,
     152             :                        ... );
     153             : 
     154             : void
     155             : fd_http_server_memcpy( fd_http_server_t * http,
     156             :                        uchar const *      data,
     157             :                        ulong              data_len );
     158             : 
     159             : void
     160             : fd_http_server_stage_trunc( fd_http_server_t * http,
     161             :                              ulong len );
     162             : 
     163             : void
     164             : fd_http_server_unstage( fd_http_server_t * http );
     165             : 
     166             : int
     167             : fd_http_server_stage_body( fd_http_server_t *          http,
     168             :                            fd_http_server_response_t * response );
     169             : 
     170           0 : void random_api_call(Xorshift *u) {
     171           0 :     switch(xorshift_next(u) % 4) {
     172           0 :         case 0:
     173           0 :         {
     174           0 :             ulong pos = xorshift_next(u) % (FD_HTTP_SERVER_GUI_MAX_WS_CONNS);
     175           0 :             if (http_server->pollfds[ pos + http_server->max_conns ].fd != -1)
     176           0 :                 fd_http_server_ws_send(http_server, pos);
     177           0 :         }
     178           0 :         break;
     179           0 :         case 1:
     180           0 :         {
     181           0 :             fd_http_server_ws_broadcast(http_server);
     182           0 :         }
     183           0 :         break;
     184           0 :         case 2:
     185           0 :         {
     186           0 :             char data[128];
     187           0 :             uint len = xorshift_next(u) % 128;
     188           0 :             memset(data, 0xcc, len);
     189           0 :             fd_http_server_memcpy(http_server, (uchar *)data, len);
     190           0 :         }
     191           0 :         break;
     192           0 :         case 3:
     193           0 :         {
     194           0 :             char data[128];
     195           0 :             uint len = xorshift_next(u) % 128;
     196           0 :             memset(data, 0xcc, len);
     197           0 :             fd_http_server_printf(http_server, "%s", data);
     198           0 :         }
     199           0 :         break;
     200           0 :     }
     201           0 : }
     202             : 
     203           0 : void open_callback( ulong conn_id, int sockfd, void * ctx ) {
     204           0 :     (void)conn_id;
     205           0 :     (void)sockfd;
     206           0 :     (void)ctx;
     207             : 
     208           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     209           0 :         random_api_call(&poll_rng);
     210           0 :     }
     211           0 : }
     212             : 
     213           0 : void close_callback( ulong conn_id, int reason, void * ctx ) {
     214           0 :     (void)conn_id;
     215           0 :     (void)reason;
     216           0 :     (void)ctx;
     217             : 
     218           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     219           0 :         random_api_call(&poll_rng);
     220           0 :     }
     221           0 : }
     222             : 
     223           0 : fd_http_server_response_t request_callback( fd_http_server_request_t const * request ) {
     224           0 :     (void)request;
     225             : 
     226           0 :     fd_http_server_response_t resp;
     227           0 :     memset(&resp, 0, sizeof(fd_http_server_response_t));
     228             : 
     229           0 :     switch(xorshift_next(&poll_rng) % 7) {
     230           0 :         case 0:
     231           0 :         {
     232           0 :             resp.status = 200;
     233           0 :             resp.upgrade_websocket = xorshift_next(&poll_rng) % 2;
     234           0 :         }
     235           0 :         break;
     236           0 :         case 1:
     237           0 :         {
     238           0 :             resp.status = 204;
     239           0 :         }
     240           0 :         break;
     241           0 :         case 2:
     242           0 :         {
     243           0 :             resp.status = 400;
     244           0 :         }
     245           0 :         break;
     246           0 :         case 3:
     247           0 :         {
     248           0 :             resp.status = 404;
     249           0 :         }
     250           0 :         break;
     251           0 :         case 4:
     252           0 :         {
     253           0 :             resp.status = 405;
     254           0 :         }
     255           0 :         break;
     256           0 :         case 5:
     257           0 :         {
     258           0 :             resp.status = 500;
     259           0 :         }
     260           0 :         break;
     261           0 :         default:
     262           0 :         {
     263           0 :             resp.status = xorshift_next(&poll_rng);
     264           0 :         }
     265           0 :         break;
     266           0 :     }
     267             : 
     268           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     269           0 :         resp.content_type = "Any content_type";
     270           0 :     }
     271             : 
     272           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     273           0 :         resp.cache_control = "Any cache_control";
     274           0 :     }
     275             : 
     276           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     277           0 :         resp.content_encoding = "Any content_encoding";
     278           0 :     }
     279             : 
     280           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     281           0 :         resp.access_control_allow_origin = "Any access_control_allow_origin";
     282           0 :     }
     283             : 
     284           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     285           0 :         resp.access_control_allow_methods = "Any access_control_allow_methods";
     286           0 :     }
     287             : 
     288           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     289           0 :         resp.access_control_allow_headers = "Any access_control_allow_headers";
     290           0 :     }
     291             : 
     292           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     293           0 :         resp.access_control_max_age = ((ulong)(&poll_rng) << 32) | (ulong)xorshift_next(&poll_rng);
     294           0 :     }
     295             : 
     296           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     297           0 :         resp.static_body = (const uchar *) "resp_body";
     298           0 :         resp.static_body_len = 9;
     299           0 :     }
     300             : 
     301           0 :     if (request->headers.upgrade_websocket && (xorshift_next(&poll_rng) % 100) > 0) {
     302           0 :         resp.status = 200;
     303           0 :         resp.upgrade_websocket = 1;
     304           0 :     }
     305             : 
     306           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     307           0 :         random_api_call(&poll_rng);
     308           0 :     }
     309             : 
     310           0 :     return resp;
     311           0 : }
     312             : 
     313           0 : void ws_open_callback( ulong ws_conn_id, void * ctx ) {
     314           0 :     (void) ws_conn_id;
     315           0 :     (void) ctx;
     316             : 
     317           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     318           0 :         random_api_call(&poll_rng);
     319           0 :     }
     320           0 : }
     321             : 
     322           0 : void ws_close_callback( ulong ws_conn_id, int reason, void * ctx ) {
     323           0 :     (void) ws_conn_id;
     324           0 :     (void) reason;
     325           0 :     (void) ctx;
     326             : 
     327           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     328           0 :         random_api_call(&poll_rng);
     329           0 :     }
     330           0 : }
     331             : 
     332           0 : void ws_message_callback( ulong ws_conn_id, uchar const * data, ulong data_len, void * ctx ) {
     333           0 :     (void) ws_conn_id;
     334           0 :     (void) data;
     335           0 :     (void) data_len;
     336           0 :     (void) ctx;
     337             : 
     338           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     339           0 :         random_api_call(&poll_rng);
     340           0 :     }
     341           0 : }
     342             : 
     343           0 : void close_reset_clients_fd(fd_http_server_t * http) {
     344           0 :   for (ulong i = 0; i < clients_fd_cnt; ++i) {
     345           0 :     if (clients_fd[i] != -1) {
     346           0 :         close(clients_fd[i]);
     347           0 :         clients_fd[i] = -1;
     348           0 :         clients_ws_fd[i] = 0;
     349           0 :     }
     350           0 :   }
     351           0 :   clients_fd_cnt = 0;
     352             : 
     353           0 :   for (ulong conn_idx = 0; conn_idx < (PARAMS.max_connection_cnt + PARAMS.max_ws_connection_cnt); ++conn_idx) {
     354           0 :     if (http->pollfds[ conn_idx ].fd != -1) {
     355           0 :         close(http->pollfds[ conn_idx ].fd);
     356           0 :     }
     357           0 :   }
     358           0 : }
     359             : 
     360           0 : int *reserve_client_fd(void) {
     361           0 :     if (clients_fd_cnt >= (FD_HTTP_SERVER_GUI_MAX_CONNS * 2)) {
     362           0 :         return NULL;
     363           0 :     }
     364           0 :     return &clients_fd[clients_fd_cnt++];
     365           0 : }
     366             : 
     367           0 : int build_http_header(struct Unstructured *u, char *buf, int max_len, int *use_web_socket) {
     368           0 :     if (max_len <= 0) return 0;
     369             : 
     370           0 :     int used = 0;
     371             : 
     372           0 :     switch (rand_uchar(u) % 5) {
     373             :         // Content-type
     374           0 :         case 0:
     375           0 :         {
     376           0 :             const char *CONTENT_TYPES[] = {"text/plain", "text/html", "application/json", "application/xml", "application/x-www-form-urlencoded", "multipart/form-data", "application/octet-stream", "image/png", "image/jpeg", "audio/mpeg", "video/mp4", "application/pdf"};
     377           0 :             const char *CHARSET = "; charset=UTF-8";
     378           0 :             const char *content_type = CONTENT_TYPES[rand_uchar(u) % 12];
     379           0 :             if (rand_uchar(u) % 2 == 0) {
     380           0 :                 used = snprintf(buf, (size_t) max_len, "Content-Type: %s\r\n", content_type);
     381           0 :             } else {
     382           0 :                 used = snprintf(buf, (size_t)max_len, "Content-Type: %s%s\r\n", content_type, CHARSET);
     383           0 :             }
     384           0 :         }
     385           0 :         break;
     386             :         // Accept-encoding
     387           0 :         case 1:
     388           0 :         {
     389           0 :             const char *ACCEPT_ENCODINGS[] = {"gzip", "compress", "deflate", "br", "identity", "*"};
     390           0 :             char accept_encoding[64];
     391           0 :             memset(accept_encoding, 0, 64);
     392           0 :             char *cur_encoding_pos = &accept_encoding[0];
     393           0 :             int rem = 64;
     394             : 
     395           0 :             for (int i = 0; i < (1 + (rand_uchar(u) % 6)); ++i) {
     396           0 :                 int size = snprintf(cur_encoding_pos, (size_t) rem, "%s, ", ACCEPT_ENCODINGS[rand_uchar(u) % 6]);
     397           0 :                 cur_encoding_pos += size;
     398           0 :                 rem -= size;
     399           0 :             }
     400             : 
     401           0 :             accept_encoding[strlen(accept_encoding)-2] = 0; // remove ", "
     402             :             
     403           0 :             used = snprintf(buf, (size_t)max_len, "Accept-Encoding: %s\r\n", accept_encoding);
     404           0 :         }
     405           0 :         break;
     406             :         // websocket
     407           0 :         case 2:
     408           0 :         {
     409           0 :             used = snprintf(buf, (size_t)max_len, "Upgrade: websocket\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n");
     410           0 :             *use_web_socket = 1;
     411           0 :         }
     412           0 :         break;
     413           0 :     }
     414             : 
     415           0 :     if (used >= max_len) {
     416           0 :         buf[0] = 0;
     417           0 :         used = 0;
     418           0 :     }
     419             : 
     420           0 :     return used;
     421           0 : }
     422             : 
     423           0 : void build_http_req(struct Unstructured *u, uchar *buf, int *len, int *use_websocket) {
     424           0 :     int max_size = *len;
     425           0 :     int size = 0;
     426           0 :     memset((char *)buf, 0, (size_t)*len);
     427             : 
     428           0 :     const char *METHODS[] = {"GET", "POST", "OPTIONS"};
     429           0 :     const char *method = METHODS[rand_uchar(u) % 3];
     430           0 :     int is_post = strlen(method) == 4 && strcmp(method, "POST") == 0 ? 1 : 0;
     431           0 :     const char *uri = "/home";
     432             : 
     433           0 :     const char *version = "HTTP/1.1";
     434             : 
     435           0 :     char headers[256];
     436           0 :     memset(headers, 0, 256);
     437           0 :     uint n_headers = 0;
     438           0 :     char *cur_header_pos = &headers[0];
     439           0 :     int rem = 256;
     440           0 :     if (is_post) {
     441           0 :         int used = snprintf(cur_header_pos, (size_t) rem, "Content-Length: 4\r\n");
     442           0 :         if (used >= rem) return;
     443           0 :         cur_header_pos += used;
     444           0 :         rem -= used;
     445           0 :         n_headers++;
     446           0 :     }
     447             : 
     448           0 :     while (n_headers < (rand_uint(u) % 32)) {
     449           0 :         int used = build_http_header(u, cur_header_pos, rem, use_websocket);
     450           0 :         cur_header_pos += used;
     451           0 :         rem -= used;
     452           0 :         n_headers++;
     453           0 :     }
     454             : 
     455           0 :     size = (uchar) snprintf((char *)buf, (size_t) max_size, "%s %s %s\r\n%s\r\n", method, uri, version, headers);
     456           0 :     if (size >= max_size) return;
     457             : 
     458           0 :     if (is_post) {
     459           0 :         int _size = snprintf((char *)buf + size, (size_t) (max_size-size), "body");
     460           0 :         if (_size <= max_size-size) return;
     461           0 :         size += _size;
     462           0 :     }
     463             : 
     464           0 :     *len = size;
     465           0 : }
     466             : 
     467           0 : void build_ws_req(struct Unstructured *u, uchar *buf, int *len) {
     468           0 :     uchar *cur_pos = buf;
     469             : 
     470           0 :     const uchar OPCODES[] = {0x0, 0x1, 0x2, 0x8, 0x9, 0xA};
     471           0 :     uchar opcode = OPCODES[rand_uchar(u) % 6] & 0x0F;
     472           0 :     *cur_pos = opcode;
     473           0 :     if (rand_uchar(u) % 2 == 0) {
     474           0 :         *cur_pos |= (1 << 7);
     475           0 :     }
     476             : 
     477           0 :     ++cur_pos;
     478             : 
     479           0 :     uint payload_len = (uchar) rand_uint(u);
     480           0 :     if (opcode == 0x8 || opcode == 0x9 || opcode == 0xA || *len < 140) {
     481           0 :         payload_len %= 126;
     482           0 :     } else {
     483           0 :         payload_len %= 256;
     484           0 :     }
     485             : 
     486           0 :     if (payload_len < 126) {
     487           0 :         *cur_pos = (uchar) payload_len;
     488           0 :     } else if (rand_uchar(u) % 2 == 0) {
     489           0 :         *cur_pos = 126;
     490           0 :     } else {
     491           0 :         *cur_pos = 127;
     492           0 :     }
     493             : 
     494           0 :     int payload_len_choice = *cur_pos;
     495             : 
     496           0 :     *cur_pos |= (1 << 7);
     497             : 
     498           0 :     ++cur_pos;
     499           0 :     if (payload_len_choice == 126) {
     500           0 :         *(ushort *)cur_pos = (ushort) payload_len;
     501           0 :         cur_pos += sizeof(ushort);
     502           0 :     } else if (payload_len_choice == 127) {
     503           0 :         *(ulong *)cur_pos = (ulong) payload_len;
     504           0 :         cur_pos += sizeof(ulong);
     505           0 :     }
     506             :     
     507           0 :     *(ulong *)cur_pos = 0;
     508           0 :     cur_pos += sizeof(ulong);
     509             : 
     510           0 :     for (uint i = 0; i < payload_len; ++i) {
     511           0 :         cur_pos[i] = rand_uchar(u);
     512           0 :     }
     513             : 
     514           0 :     *len = (int) (cur_pos - buf);
     515           0 : }
     516             : 
     517             : static ulong stem_iters = 0;
     518             : static int stop = 0;
     519           0 : void* stem_thread(void* arg) {
     520           0 :     (void) arg;
     521           0 :     stem_iters = 0;
     522             : 
     523           0 :     while (1) {
     524           0 :         for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     525           0 :             random_api_call(&poll_rng);
     526           0 :         }
     527             : 
     528           0 :         fd_http_server_poll(http_server);
     529             : 
     530           0 :         for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     531           0 :             random_api_call(&poll_rng);
     532           0 :         }
     533             : 
     534           0 :         ++stem_iters;
     535             : 
     536           0 :         if (stop) break;
     537           0 :         sched_yield();
     538           0 :     }
     539           0 :     return NULL;
     540           0 : }
     541             : 
     542             : enum Action {
     543             :     HttpOpen = 0,
     544             :     Close,
     545             :     Send,
     546             :     ActionEnd,
     547             : };
     548             : 
     549           0 : void do_action(struct Unstructured *u) {
     550           0 :     switch(rand_uchar(u) % ActionEnd) {
     551           0 :         case HttpOpen:
     552           0 :         {
     553           0 :             int *client_fd = reserve_client_fd();
     554           0 :             if (!client_fd) return;
     555             : 
     556           0 :             struct sockaddr_in server_addr;
     557           0 :             *client_fd = socket(AF_INET, SOCK_STREAM, 0);
     558             : 
     559           0 :             memset(&server_addr, 0, sizeof(server_addr));
     560           0 :             server_addr.sin_family = AF_INET;
     561           0 :             server_addr.sin_port = htons(port);
     562             : 
     563           0 :             if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) != 1) {
     564           0 :                 close(*client_fd);
     565           0 :                 *client_fd = -1;
     566           0 :                 clients_fd_cnt--;
     567           0 :                 return;
     568           0 :             }
     569             : 
     570           0 :             struct sockaddr sa;
     571           0 :             memcpy(&sa, &server_addr, sizeof(struct sockaddr));
     572             : 
     573           0 :             if (connect(*client_fd, &sa, sizeof(server_addr)) < 0) {
     574           0 :                 close(*client_fd);
     575           0 :                 *client_fd = -1;
     576           0 :                 clients_fd_cnt--;
     577           0 :             }
     578           0 :         }
     579           0 :         break;
     580           0 :         case Close:
     581           0 :         {
     582           0 :             if (clients_fd_cnt > 0) {
     583           0 :                 uchar pos = rand_uchar(u) % ((uchar) clients_fd_cnt);
     584           0 :                 if (clients_fd[pos] != -1) {
     585           0 :                     close(clients_fd[pos]);
     586           0 :                     clients_fd[pos] = -1;
     587           0 :                     clients_ws_fd[pos] = 0;
     588           0 :                 }
     589           0 :             }
     590           0 :         }
     591           0 :         break;
     592           0 :         case Send:
     593           0 :         {
     594           0 :             if (clients_fd_cnt > 0) {
     595           0 :                 int len = 1024;
     596           0 :                 uchar buf[1024];
     597           0 :                 int use_websocket = 0;
     598           0 :                 uchar pos = rand_uchar(u) % ((uchar) clients_fd_cnt);
     599             : 
     600           0 :                 if (clients_fd[pos] != -1 && clients_ws_fd[pos] == 0) {
     601           0 :                     build_http_req(u, buf, &len, &use_websocket);
     602           0 :                     if (rand_uchar(u) % 5 == 0) { 
     603           0 :                         LLVMFuzzerMutate(buf, (ulong)len, (ulong)len);
     604           0 :                     }
     605           0 :                     send(clients_fd[pos], buf, (size_t)len, MSG_NOSIGNAL);
     606           0 :                     if (use_websocket) {
     607           0 :                         clients_ws_fd[pos] = 1;
     608           0 :                     }
     609           0 :                 }
     610             : 
     611           0 :                 else if (clients_fd[pos] != -1 && clients_ws_fd[pos] == 1) {
     612           0 :                     build_ws_req(u, buf, &len);
     613             : 
     614             :                     // add up to 2 messages
     615           0 :                     for (ulong i = 0; i < rand_uchar(u) % 3 && len < 1024; ++i) {
     616           0 :                         int len2 = 1024 - len;
     617           0 :                         build_ws_req(u, buf + len, &len2);
     618           0 :                         len += len2;
     619           0 :                     }
     620             : 
     621           0 :                     if (rand_uchar(u) % 5 == 0) { 
     622           0 :                         LLVMFuzzerMutate(buf, (ulong)len, (ulong)len);
     623           0 :                     }
     624             : 
     625           0 :                     send(clients_fd[pos], buf, (size_t)len, MSG_NOSIGNAL);
     626           0 :                 }
     627           0 :             }
     628           0 :         }
     629           0 :         break;
     630           0 :     }
     631           0 : }
     632             : 
     633             : int
     634             : LLVMFuzzerTestOneInput( uchar const * data,
     635             :                         ulong         size ) {
     636             : 
     637             :   if (size >= sizeof(int)) {
     638             :     const fd_valloc_t valloc = fd_libc_alloc_virtual();
     639             :     struct Unstructured u = {
     640             :         .data = data,
     641             :         .size = size,
     642             :         .used = 0
     643             :     };
     644             :     pthread_t thread;
     645             :     uint32_t ip_as_int;
     646             :     inet_pton(AF_INET, "0.0.0.0", &ip_as_int);
     647             : 
     648             :     srand( rand_uint(&u));
     649             : 
     650             :     void *shmem = fd_valloc_malloc(valloc, fd_http_server_align(), fd_http_server_footprint( PARAMS ));
     651             : 
     652             :     fd_http_server_callbacks_t gui_callbacks = {
     653             :         .open = open_callback,
     654             :         .close = close_callback,
     655             :         .request = request_callback,
     656             :         .ws_open = ws_open_callback,
     657             :         .ws_close = ws_close_callback,
     658             :         .ws_message = ws_message_callback,
     659             :     };
     660             : 
     661             :     http_server = fd_http_server_join( fd_http_server_new( shmem, PARAMS, gui_callbacks, NULL ) );
     662             :     http_server = fd_http_server_listen( http_server, ip_as_int, 0 );
     663             : 
     664             :     struct sockaddr_in addr;
     665             :     socklen_t addr_len = sizeof(addr);
     666             :     struct sockaddr sock_addr;
     667             :     memset(&addr, 0, sizeof(addr));
     668             :     memset(&sock_addr, 0, sizeof(sock_addr));
     669             :     memcpy(&sock_addr, &addr, sizeof(addr));
     670             : 
     671             :     if (getsockname(http_server->socket_fd, &sock_addr, &addr_len) == -1) {
     672             :         printf( "bind failed (%i-%s)", errno, strerror( errno ) );
     673             :         abort();
     674             :     }
     675             : 
     676             :     port = ntohs(addr.sin_port);
     677             : 
     678             :     xorshift_init(&poll_rng, (uint32_t) rand_uint(&u));
     679             : 
     680             :     stop = 0;
     681             :     pthread_create(&thread, NULL, stem_thread, NULL);
     682             : 
     683             :     uchar n_actions = (uchar) rand_uchar(&u) % 32;
     684             :     for (uchar i = 0; i < n_actions; ++i) {
     685             :         do_action(&u);
     686             : 
     687             :         ulong iters = stem_iters;
     688             :         do { sched_yield(); } while (stem_iters < iters + 1);
     689             :     }
     690             :     
     691             :     stop = 1;
     692             :     pthread_join(thread, NULL);
     693             : 
     694             :     close_reset_clients_fd(http_server);
     695             :     close(fd_http_server_fd(http_server));
     696             :     fd_http_server_delete(fd_http_server_leave(http_server));
     697             :     fd_valloc_free(valloc, shmem);
     698             :   }
     699             : 
     700             :   return 0;
     701             : }

Generated by: LCOV version 1.14