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

Generated by: LCOV version 1.14