LCOV - code coverage report
Current view: top level - waltz/http - fuzz_httpserver.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 9 440 2.0 %
Date: 2025-10-14 04:31: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          12 :                       char *** argv ) {
     100             :   /* Set up shell without signal handlers */
     101          12 :   putenv( "FD_LOG_BACKTRACE=0" );
     102          12 :   fd_boot( argc, argv );
     103          12 :   atexit( fd_halt );
     104          12 :   fd_log_level_core_set(3); /* crash on warning log */
     105             : 
     106             :   /* Disable parsing error logging */
     107          12 :   fd_log_level_stderr_set(4);
     108             : 
     109          12 :   reset_clients_fd();
     110             : 
     111          12 :   return 0;
     112          12 : }
     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 :     fd_http_server_response_t resp;
     225           0 :     memset(&resp, 0, sizeof(fd_http_server_response_t));
     226             : 
     227           0 :     switch(xorshift_next(&poll_rng) % 7) {
     228           0 :         case 0:
     229           0 :         {
     230           0 :             resp.status = 200;
     231           0 :             resp.upgrade_websocket = xorshift_next(&poll_rng) % 2;
     232           0 :             resp.compress_websocket = xorshift_next(&poll_rng) % 2;
     233           0 :         }
     234           0 :         break;
     235           0 :         case 1:
     236           0 :         {
     237           0 :             resp.status = 204;
     238           0 :         }
     239           0 :         break;
     240           0 :         case 2:
     241           0 :         {
     242           0 :             resp.status = 400;
     243           0 :         }
     244           0 :         break;
     245           0 :         case 3:
     246           0 :         {
     247           0 :             resp.status = 404;
     248           0 :         }
     249           0 :         break;
     250           0 :         case 4:
     251           0 :         {
     252           0 :             resp.status = 405;
     253           0 :         }
     254           0 :         break;
     255           0 :         case 5:
     256           0 :         {
     257           0 :             resp.status = 500;
     258           0 :         }
     259           0 :         break;
     260           0 :         default:
     261           0 :         {
     262           0 :             resp.status = xorshift_next(&poll_rng);
     263           0 :         }
     264           0 :         break;
     265           0 :     }
     266             : 
     267           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     268           0 :         resp.content_type = "Any content_type";
     269           0 :     }
     270             : 
     271           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     272           0 :         resp.cache_control = "Any cache_control";
     273           0 :     }
     274             : 
     275           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     276           0 :         resp.content_encoding = "Any content_encoding";
     277           0 :     }
     278             : 
     279           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     280           0 :         resp.access_control_allow_origin = "Any access_control_allow_origin";
     281           0 :     }
     282             : 
     283           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     284           0 :         resp.access_control_allow_methods = "Any access_control_allow_methods";
     285           0 :     }
     286             : 
     287           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     288           0 :         resp.access_control_allow_headers = "Any access_control_allow_headers";
     289           0 :     }
     290             : 
     291           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     292           0 :         resp.access_control_max_age = ((ulong)(&poll_rng) << 32) | (ulong)xorshift_next(&poll_rng);
     293           0 :     }
     294             : 
     295           0 :     if (xorshift_next(&poll_rng) % 2 == 0) {
     296           0 :         resp.static_body = (const uchar *) "resp_body";
     297           0 :         resp.static_body_len = 9;
     298           0 :     }
     299             : 
     300           0 :     if (request->headers.upgrade_websocket && (xorshift_next(&poll_rng) % 100) > 0) {
     301           0 :         resp.status = 200;
     302           0 :         resp.upgrade_websocket = 1;
     303           0 :     }
     304             : 
     305           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     306           0 :         random_api_call(&poll_rng);
     307           0 :     }
     308             : 
     309           0 :     return resp;
     310           0 : }
     311             : 
     312           0 : void ws_open_callback( ulong ws_conn_id, void * ctx ) {
     313           0 :     (void) ws_conn_id;
     314           0 :     (void) ctx;
     315             : 
     316           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     317           0 :         random_api_call(&poll_rng);
     318           0 :     }
     319           0 : }
     320             : 
     321           0 : void ws_close_callback( ulong ws_conn_id, int reason, void * ctx ) {
     322           0 :     (void) ws_conn_id;
     323           0 :     (void) reason;
     324           0 :     (void) ctx;
     325             : 
     326           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     327           0 :         random_api_call(&poll_rng);
     328           0 :     }
     329           0 : }
     330             : 
     331           0 : void ws_message_callback( ulong ws_conn_id, uchar const * data, ulong data_len, void * ctx ) {
     332           0 :     (void) ws_conn_id;
     333           0 :     (void) data;
     334           0 :     (void) data_len;
     335           0 :     (void) ctx;
     336             : 
     337           0 :     for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     338           0 :         random_api_call(&poll_rng);
     339           0 :     }
     340           0 : }
     341             : 
     342           0 : void close_reset_clients_fd(fd_http_server_t * http) {
     343           0 :   for (ulong i = 0; i < clients_fd_cnt; ++i) {
     344           0 :     if (clients_fd[i] != -1) {
     345           0 :         close(clients_fd[i]);
     346           0 :         clients_fd[i] = -1;
     347           0 :         clients_ws_fd[i] = 0;
     348           0 :     }
     349           0 :   }
     350           0 :   clients_fd_cnt = 0;
     351             : 
     352           0 :   for (ulong conn_idx = 0; conn_idx < (PARAMS.max_connection_cnt + PARAMS.max_ws_connection_cnt); ++conn_idx) {
     353           0 :     if (http->pollfds[ conn_idx ].fd != -1) {
     354           0 :         close(http->pollfds[ conn_idx ].fd);
     355           0 :     }
     356           0 :   }
     357           0 : }
     358             : 
     359           0 : int *reserve_client_fd(void) {
     360           0 :     if (clients_fd_cnt >= (FD_HTTP_SERVER_GUI_MAX_CONNS * 2)) {
     361           0 :         return NULL;
     362           0 :     }
     363           0 :     return &clients_fd[clients_fd_cnt++];
     364           0 : }
     365             : 
     366           0 : int build_http_header(struct Unstructured *u, char *buf, int max_len, int *use_web_socket) {
     367           0 :     if (max_len <= 0) return 0;
     368             : 
     369           0 :     int used = 0;
     370             : 
     371           0 :     switch (rand_uchar(u) % 5) {
     372             :         // Content-type
     373           0 :         case 0:
     374           0 :         {
     375           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"};
     376           0 :             const char *CHARSET = "; charset=UTF-8";
     377           0 :             const char *content_type = CONTENT_TYPES[rand_uchar(u) % 12];
     378           0 :             if (rand_uchar(u) % 2 == 0) {
     379           0 :                 used = snprintf(buf, (size_t) max_len, "Content-Type: %s\r\n", content_type);
     380           0 :             } else {
     381           0 :                 used = snprintf(buf, (size_t)max_len, "Content-Type: %s%s\r\n", content_type, CHARSET);
     382           0 :             }
     383           0 :         }
     384           0 :         break;
     385             :         // Accept-encoding
     386           0 :         case 1:
     387           0 :         {
     388           0 :             const char *ACCEPT_ENCODINGS[] = {"gzip", "compress", "deflate", "br", "identity", "*"};
     389           0 :             char accept_encoding[64];
     390           0 :             memset(accept_encoding, 0, 64);
     391           0 :             char *cur_encoding_pos = &accept_encoding[0];
     392           0 :             int rem = 64;
     393             : 
     394           0 :             for (int i = 0; i < (1 + (rand_uchar(u) % 6)); ++i) {
     395           0 :                 int size = snprintf(cur_encoding_pos, (size_t) rem, "%s, ", ACCEPT_ENCODINGS[rand_uchar(u) % 6]);
     396           0 :                 cur_encoding_pos += size;
     397           0 :                 rem -= size;
     398           0 :             }
     399             : 
     400           0 :             accept_encoding[strlen(accept_encoding)-2] = 0; // remove ", "
     401             : 
     402           0 :             used = snprintf(buf, (size_t)max_len, "Accept-Encoding: %s\r\n", accept_encoding);
     403           0 :         }
     404           0 :         break;
     405             :         // websocket
     406           0 :         case 2:
     407           0 :         {
     408           0 :             used = snprintf(buf, (size_t)max_len, "Upgrade: websocket\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n");
     409           0 :             *use_web_socket = 1;
     410           0 :         }
     411           0 :         break;
     412           0 :     }
     413             : 
     414           0 :     if (used >= max_len) {
     415           0 :         buf[0] = 0;
     416           0 :         used = 0;
     417           0 :     }
     418             : 
     419           0 :     return used;
     420           0 : }
     421             : 
     422           0 : void build_http_req(struct Unstructured *u, uchar *buf, int *len, int *use_websocket) {
     423           0 :     int max_size = *len;
     424           0 :     int size = 0;
     425           0 :     memset((char *)buf, 0, (size_t)*len);
     426             : 
     427           0 :     const char *METHODS[] = {"GET", "POST", "OPTIONS"};
     428           0 :     const char *method = METHODS[rand_uchar(u) % 3];
     429           0 :     int is_post = strlen(method) == 4 && strcmp(method, "POST") == 0 ? 1 : 0;
     430           0 :     const char *uri = "/home";
     431             : 
     432           0 :     const char *version = "HTTP/1.1";
     433             : 
     434           0 :     char headers[256];
     435           0 :     memset(headers, 0, 256);
     436           0 :     uint n_headers = 0;
     437           0 :     char *cur_header_pos = &headers[0];
     438           0 :     int rem = 256;
     439           0 :     if (is_post) {
     440           0 :         int used = snprintf(cur_header_pos, (size_t) rem, "Content-Length: 4\r\n");
     441           0 :         if (used >= rem) return;
     442           0 :         cur_header_pos += used;
     443           0 :         rem -= used;
     444           0 :         n_headers++;
     445           0 :     }
     446             : 
     447           0 :     while (n_headers < (rand_uint(u) % 32)) {
     448           0 :         int used = build_http_header(u, cur_header_pos, rem, use_websocket);
     449           0 :         cur_header_pos += used;
     450           0 :         rem -= used;
     451           0 :         n_headers++;
     452           0 :     }
     453             : 
     454           0 :     size = (uchar) snprintf((char *)buf, (size_t) max_size, "%s %s %s\r\n%s\r\n", method, uri, version, headers);
     455           0 :     if (size >= max_size) return;
     456             : 
     457           0 :     if (is_post) {
     458           0 :         int _size = snprintf((char *)buf + size, (size_t) (max_size-size), "body");
     459           0 :         if (_size <= max_size-size) return;
     460           0 :         size += _size;
     461           0 :     }
     462             : 
     463           0 :     *len = size;
     464           0 : }
     465             : 
     466           0 : void build_ws_req(struct Unstructured *u, uchar *buf, int *len) {
     467           0 :     uchar *cur_pos = buf;
     468             : 
     469           0 :     const uchar OPCODES[] = {0x0, 0x1, 0x2, 0x8, 0x9, 0xA};
     470           0 :     uchar opcode = OPCODES[rand_uchar(u) % 6] & 0x0F;
     471           0 :     *cur_pos = opcode;
     472           0 :     if (rand_uchar(u) % 2 == 0) {
     473           0 :         *cur_pos |= (1 << 7);
     474           0 :     }
     475             : 
     476           0 :     ++cur_pos;
     477             : 
     478           0 :     uint payload_len = (uchar) rand_uint(u);
     479           0 :     if (opcode == 0x8 || opcode == 0x9 || opcode == 0xA || *len < 140) {
     480           0 :         payload_len %= 126;
     481           0 :     } else {
     482           0 :         payload_len %= 256;
     483           0 :     }
     484             : 
     485           0 :     if (payload_len < 126) {
     486           0 :         *cur_pos = (uchar) payload_len;
     487           0 :     } else if (rand_uchar(u) % 2 == 0) {
     488           0 :         *cur_pos = 126;
     489           0 :     } else {
     490           0 :         *cur_pos = 127;
     491           0 :     }
     492             : 
     493           0 :     int payload_len_choice = *cur_pos;
     494             : 
     495           0 :     *cur_pos |= (1 << 7);
     496             : 
     497           0 :     ++cur_pos;
     498           0 :     if (payload_len_choice == 126) {
     499           0 :         *(ushort *)cur_pos = (ushort) payload_len;
     500           0 :         cur_pos += sizeof(ushort);
     501           0 :     } else if (payload_len_choice == 127) {
     502           0 :         *(ulong *)cur_pos = (ulong) payload_len;
     503           0 :         cur_pos += sizeof(ulong);
     504           0 :     }
     505             : 
     506           0 :     *(ulong *)cur_pos = 0;
     507           0 :     cur_pos += sizeof(ulong);
     508             : 
     509           0 :     for (uint i = 0; i < payload_len; ++i) {
     510           0 :         cur_pos[i] = rand_uchar(u);
     511           0 :     }
     512             : 
     513           0 :     *len = (int) (cur_pos - buf);
     514           0 : }
     515             : 
     516             : static ulong stem_iters = 0;
     517             : static int stop = 0;
     518           0 : void* stem_thread(void* arg) {
     519           0 :     (void) arg;
     520           0 :     stem_iters = 0;
     521             : 
     522           0 :     while (1) {
     523           0 :         for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     524           0 :             random_api_call(&poll_rng);
     525           0 :         }
     526             : 
     527           0 :         fd_http_server_poll(http_server, 0);
     528             : 
     529           0 :         for (uint i = 0; i < xorshift_next(&poll_rng) % 3; ++i) {
     530           0 :             random_api_call(&poll_rng);
     531           0 :         }
     532             : 
     533           0 :         ++stem_iters;
     534             : 
     535           0 :         if (stop) break;
     536           0 :         sched_yield();
     537           0 :     }
     538           0 :     return NULL;
     539           0 : }
     540             : 
     541             : enum Action {
     542             :     HttpOpen = 0,
     543             :     Close,
     544             :     Send,
     545             :     ActionEnd,
     546             : };
     547             : 
     548           0 : void do_action(struct Unstructured *u) {
     549           0 :     switch(rand_uchar(u) % ActionEnd) {
     550           0 :         case HttpOpen:
     551           0 :         {
     552           0 :             int *client_fd = reserve_client_fd();
     553           0 :             if (!client_fd) return;
     554             : 
     555           0 :             struct sockaddr_in server_addr;
     556           0 :             *client_fd = socket(AF_INET, SOCK_STREAM, 0);
     557             : 
     558           0 :             memset(&server_addr, 0, sizeof(server_addr));
     559           0 :             server_addr.sin_family = AF_INET;
     560           0 :             server_addr.sin_port = htons(port);
     561             : 
     562           0 :             if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) != 1) {
     563           0 :                 close(*client_fd);
     564           0 :                 *client_fd = -1;
     565           0 :                 clients_fd_cnt--;
     566           0 :                 return;
     567           0 :             }
     568             : 
     569           0 :             struct sockaddr sa;
     570           0 :             memcpy(&sa, &server_addr, sizeof(struct sockaddr));
     571             : 
     572           0 :             if (connect(*client_fd, &sa, sizeof(server_addr)) < 0) {
     573           0 :                 close(*client_fd);
     574           0 :                 *client_fd = -1;
     575           0 :                 clients_fd_cnt--;
     576           0 :             }
     577           0 :         }
     578           0 :         break;
     579           0 :         case Close:
     580           0 :         {
     581           0 :             if (clients_fd_cnt > 0) {
     582           0 :                 uchar pos = rand_uchar(u) % ((uchar) clients_fd_cnt);
     583           0 :                 if (clients_fd[pos] != -1) {
     584           0 :                     close(clients_fd[pos]);
     585           0 :                     clients_fd[pos] = -1;
     586           0 :                     clients_ws_fd[pos] = 0;
     587           0 :                 }
     588           0 :             }
     589           0 :         }
     590           0 :         break;
     591           0 :         case Send:
     592           0 :         {
     593           0 :             if (clients_fd_cnt > 0) {
     594           0 :                 int len = 1024;
     595           0 :                 uchar buf[1024];
     596           0 :                 int use_websocket = 0;
     597           0 :                 uchar pos = rand_uchar(u) % ((uchar) clients_fd_cnt);
     598             : 
     599           0 :                 if (clients_fd[pos] != -1 && clients_ws_fd[pos] == 0) {
     600           0 :                     build_http_req(u, buf, &len, &use_websocket);
     601           0 :                     if (rand_uchar(u) % 5 == 0) {
     602           0 :                         LLVMFuzzerMutate(buf, (ulong)len, (ulong)len);
     603           0 :                     }
     604           0 :                     send(clients_fd[pos], buf, (size_t)len, MSG_NOSIGNAL);
     605           0 :                     if (use_websocket) {
     606           0 :                         clients_ws_fd[pos] = 1;
     607           0 :                     }
     608           0 :                 }
     609             : 
     610           0 :                 else if (clients_fd[pos] != -1 && clients_ws_fd[pos] == 1) {
     611           0 :                     build_ws_req(u, buf, &len);
     612             : 
     613             :                     // add up to 2 messages
     614           0 :                     for (ulong i = 0; i < rand_uchar(u) % 3 && len < 1024; ++i) {
     615           0 :                         int len2 = 1024 - len;
     616           0 :                         build_ws_req(u, buf + len, &len2);
     617           0 :                         len += len2;
     618           0 :                     }
     619             : 
     620           0 :                     if (rand_uchar(u) % 5 == 0) {
     621           0 :                         LLVMFuzzerMutate(buf, (ulong)len, (ulong)len);
     622           0 :                     }
     623             : 
     624             :                     send(clients_fd[pos], buf, (size_t)len, MSG_NOSIGNAL);
     625           0 :                 }
     626           0 :             }
     627           0 :         }
     628           0 :         break;
     629           0 :     }
     630           0 : }
     631             : 
     632             : int
     633             : LLVMFuzzerTestOneInput( uchar const * data,
     634             :                         ulong         size ) {
     635             : 
     636             :   if (size >= sizeof(int)) {
     637             :     struct Unstructured u = {
     638             :         .data = data,
     639             :         .size = size,
     640             :         .used = 0
     641             :     };
     642             :     pthread_t thread;
     643             :     uint32_t ip_as_int;
     644             :     inet_pton(AF_INET, "0.0.0.0", &ip_as_int);
     645             : 
     646             :     srand( rand_uint(&u));
     647             : 
     648             :     void * shmem = aligned_alloc( fd_http_server_align(), fd_http_server_footprint( PARAMS ) );
     649             :     assert( shmem );
     650             : 
     651             :     fd_http_server_callbacks_t gui_callbacks = {
     652             :         .open = open_callback,
     653             :         .close = close_callback,
     654             :         .request = request_callback,
     655             :         .ws_open = ws_open_callback,
     656             :         .ws_close = ws_close_callback,
     657             :         .ws_message = ws_message_callback,
     658             :     };
     659             : 
     660             :     http_server = fd_http_server_join( fd_http_server_new( shmem, PARAMS, gui_callbacks, NULL ) );
     661             :     http_server = fd_http_server_listen( http_server, ip_as_int, 0 );
     662             : 
     663             :     union sockaddr_pun {
     664             :         struct sockaddr_in addr_in;
     665             :         struct sockaddr    sa;
     666             :     };
     667             : 
     668             :     union sockaddr_pun addr_pun;
     669             :     memset(&addr_pun, 0, sizeof(addr_pun));
     670             : 
     671             :     socklen_t addr_len = sizeof(addr_pun);
     672             : 
     673             :     if (getsockname(http_server->socket_fd, &addr_pun.sa, &addr_len) == -1) {
     674             :         printf( "bind failed (%i-%s)", errno, strerror( errno ) );
     675             :         abort();
     676             :     }
     677             : 
     678             :     port = ntohs(addr_pun.addr_in.sin_port);
     679             : 
     680             :     xorshift_init(&poll_rng, (uint32_t) rand_uint(&u));
     681             : 
     682             :     stop = 0;
     683             :     pthread_create(&thread, NULL, stem_thread, NULL);
     684             : 
     685             :     uchar n_actions = (uchar) rand_uchar(&u) % 32;
     686             :     for (uchar i = 0; i < n_actions; ++i) {
     687             :         do_action(&u);
     688             : 
     689             :         ulong iters = stem_iters;
     690             :         do { sched_yield(); } while (stem_iters < iters + 1);
     691             :     }
     692             : 
     693             :     stop = 1;
     694             :     pthread_join(thread, NULL);
     695             : 
     696             :     close_reset_clients_fd(http_server);
     697             :     close(fd_http_server_fd(http_server));
     698             :     fd_http_server_delete(fd_http_server_leave(http_server));
     699             :     free( shmem );
     700             :   }
     701             : 
     702             :   return 0;
     703             : }

Generated by: LCOV version 1.14