GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/config.c Lines: 322 358 89.9 %
Date: 2020-12-10 21:44:00 Branches: 196 284 69.0 %

Line Branch Exec Source
1
#include <stdio.h> 				/* printf, fflush, fprintf, fopen, fclose */
2
#include <stdlib.h> 			/* abs, free */
3
#include <string.h>             /* strerror, memset, strncpy, memcpy, strlen,
4
                                   strtok, strtok_r */
5
#include <math.h> 				/* floor, log10, abs */
6
7
#include "config.h"
8
#include "str.h"
9
#include "json.h"
10
#include "alloc.h"
11
#include "error.h"
12
#include "log.h"
13
#include "predict.h"
14
15
json_settings settings;
16
17
72
static wss_error_t config_add_port_to_hosts(wss_config_t *config) {
18
72
    int n;
19
72
    unsigned int i;
20
72
    unsigned int hosts_length = config->hosts_length,
21
72
                 cur = 0,
22
72
                 digits = 0,
23
72
                 size = 0,
24
72
                 ports = 0;
25
26
72
    char *extra;
27
28
72
    if ( likely(config->port_http > 0) ) {
29
72
        digits += floor(log10(config->port_http)) + 1;
30
72
        ports++;
31
    }
32
33
72
    if ( likely(config->port_https > 0) ) {
34
72
        digits += floor(log10(config->port_https)) + 1;
35
72
        ports++;
36
    }
37
38
72
    if ( unlikely(NULL == (config->hosts = (char **)WSS_realloc(
39
                    (void **)&config->hosts, hosts_length*sizeof(char *), hosts_length*(ports+1)*sizeof(char *)))) ) {
40
        WSS_log_error("Unable to allocate new hosts");
41
        WSS_config_free(config);
42
        return WSS_MEMORY_ERROR;
43
    }
44
72
    config->hosts_length = hosts_length*(ports+1);
45
46
216
    for (i = 0; likely(i < hosts_length); i++) {
47
144
        size += strlen(config->hosts[i]);
48
    }
49
50
72
    if ( unlikely(NULL == (extra = WSS_malloc((hosts_length*digits + hosts_length*ports*2 + size*ports)*sizeof(char)))) ) {
51
        WSS_log_error("Unable to allocate extra");
52
        WSS_config_free(config);
53
        return WSS_MEMORY_ERROR;
54
    }
55
56
72
    if ( likely(config->port_http > 0) ) {
57
216
        for (i = 0; likely(i < hosts_length); i++) {
58
144
            if ( unlikely(0 > (n = sprintf(extra+cur, "%s:%u", config->hosts[i], config->port_http))) ) {
59
                WSS_log_error("Unable to perform sprintf");
60
                WSS_config_free(config);
61
                return WSS_PRINTF_ERROR;
62
            }
63
144
            config->hosts[hosts_length*ports+i] = extra+cur;
64
144
            cur += n+1;
65
        }
66
72
        ports--;
67
    }
68
69
72
    if ( likely(config->port_https > 0) ) {
70
216
        for (i = 0; likely(i < hosts_length); i++) {
71
144
            if ( unlikely(0 > (n = sprintf(extra+cur, "%s:%u", config->hosts[i], config->port_https))) ) {
72
                WSS_log_error("Unable to perform sprintf");
73
                WSS_config_free(config);
74
                return WSS_PRINTF_ERROR;
75
            }
76
144
            config->hosts[hosts_length*ports+i] = extra+cur;
77
144
            cur += n+1;
78
        }
79
    }
80
81
    return WSS_SUCCESS;
82
}
83
84
7175
static void * WSS_config_alloc (size_t size, int zero, void * user_data)
85
{
86
7175
   (void) user_data;
87
7175
   return zero ? WSS_calloc (1, size) : WSS_malloc (size);
88
}
89
90
7153
static void WSS_config_release (void * ptr, void * user_data)
91
{
92
7153
   (void) user_data;
93
7153
   WSS_free(&ptr);
94
7153
}
95
96
/**
97
 * Loads configuration from JSON file
98
 *
99
 * @param   config  [wss_config_t *]    "The configuration structure to fill"
100
 * @param   path    [char *]            "The path to the JSON file"
101
 * @return 			[wss_error_t]       "The error status"
102
 */
103
86
wss_error_t WSS_config_load(wss_config_t *config, char *path) {
104
86
    char error[1024];
105
86
    unsigned int i, j, length;
106
86
    char *name;
107
86
    json_value *value, *val, *temp;
108
86
    settings = (json_settings){
109
        .settings  = json_enable_comments,
110
        .mem_alloc = WSS_config_alloc,
111
        .mem_free  = WSS_config_release
112
    };
113
114
86
    config->length = strload(path, &config->string);
115
86
    if ( unlikely(NULL == config->string) ) {
116
1
        WSS_log_error("Unable to load JSON file: %s", error);
117
1
        WSS_config_free(config);
118
1
        return WSS_CONFIG_LOAD_ERROR;
119
    }
120
121
85
    config->data = json_parse_ex(&settings, config->string, config->length, error);
122
123
85
    if ( unlikely(config->data == 0) ) {
124
1
        WSS_log_error("Unable to parse JSON config: %s", error);
125
1
        WSS_config_free(config);
126
1
        return WSS_CONFIG_JSON_PARSE_ERROR;
127
    } else {
128
84
        if ( likely(config->data->type == json_object) ) {
129
454
            for (i = 0; likely(i < config->data->u.object.length); i++) {
130
379
                value = config->data->u.object.values[i].value;
131
379
                name = config->data->u.object.values[i].name;
132
133
379
                if ( strncmp(name, "hosts", 5) == 0 ) {
134
75
                    if ( likely(value->type == json_array) ) {
135
75
                        length = value->u.array.length;
136
137
75
                        if (length == 0) {
138
1
                            config->hosts_length = length;
139
1
                            config->hosts = NULL;
140
1
                            continue;
141
                        }
142
143
74
                        if ( unlikely(NULL == (config->hosts = WSS_calloc(length, sizeof(char *)))) ) {
144
                            WSS_log_error("Unable to calloc hosts");
145
                            WSS_config_free(config);
146
                            return WSS_MEMORY_ERROR;
147
                        }
148
149
220
                        for (j = 0; likely(j < length); j++) {
150
147
                            if ( likely(value->u.array.values[j]->type == json_string) ) {
151
146
                                config->hosts[j] =
152
146
                                    (char *) value->u.array.values[j]->u.string.ptr;
153
                            } else {
154
1
                                WSS_log_error("Invalid host");
155
1
                                WSS_config_free(config);
156
1
                                return WSS_CONFIG_INVALID_HOST;
157
                            }
158
                        }
159
73
                        config->hosts_length = length;
160
                    }
161
304
                } else if ( strncmp(name, "origins", 7) == 0 ) {
162
75
                    if ( likely(value->type == json_array) ) {
163
75
                        length = value->u.array.length;
164
165
75
                        if (length == 0) {
166
1
                            config->origins_length = length;
167
1
                            config->origins = NULL;
168
1
                            continue;
169
                        }
170
171
74
                        if ( unlikely(NULL == (config->origins = WSS_calloc(length, sizeof(char *)))) ) {
172
                            WSS_log_error("Unable to calloc origins");
173
                            WSS_config_free(config);
174
                            return WSS_MEMORY_ERROR;
175
                        }
176
177
220
                        for (j = 0; likely(j < length); j++) {
178
147
                            if ( likely(value->u.array.values[j]->type == json_string) ) {
179
146
                                config->origins[j] =
180
146
                                    (char *) value->u.array.values[j]->u.string.ptr;
181
                            } else {
182
1
                                WSS_log_error("Invalid origin");
183
1
                                WSS_config_free(config);
184
1
                                return WSS_CONFIG_INVALID_ORIGIN;
185
                            }
186
                        }
187
73
                        config->origins_length = length;
188
                    }
189
229
                } else if ( strncmp(name, "paths", 7) == 0 ) {
190
75
                    if ( likely(value->type == json_array) ) {
191
75
                        length = value->u.array.length;
192
193
75
                        if (length == 0) {
194
1
                            config->paths_length = length;
195
1
                            config->paths = NULL;
196
1
                            continue;
197
                        }
198
199
74
                        if ( unlikely(NULL == (config->paths = WSS_calloc(length, sizeof(char *)))) ) {
200
                            WSS_log_error("Unable to calloc paths");
201
                            WSS_config_free(config);
202
                            return WSS_MEMORY_ERROR;
203
                        }
204
205
220
                        for (j = 0; likely(j < length); j++) {
206
147
                            if ( likely(value->u.array.values[j]->type == json_string) ) {
207
146
                                config->paths[j] =
208
146
                                    (char *) value->u.array.values[j]->u.string.ptr;
209
                            } else {
210
1
                                WSS_log_error("Invalid path");
211
1
                                WSS_config_free(config);
212
1
                                return WSS_CONFIG_INVALID_PATH;
213
                            }
214
                        }
215
73
                        config->paths_length = length;
216
                    }
217
154
                } else if ( strncmp(name, "queries", 7) == 0 ) {
218
75
                    if ( likely(value->type == json_array) ) {
219
75
                        length = value->u.array.length;
220
221
75
                        if (length == 0) {
222
1
                            config->queries_length = length;
223
1
                            config->queries = NULL;
224
1
                            continue;
225
                        }
226
227
74
                        if ( unlikely(NULL == (config->queries = WSS_calloc(length, sizeof(char *)))) ) {
228
                            WSS_log_error("Unable to calloc queries");
229
                            WSS_config_free(config);
230
                            return WSS_MEMORY_ERROR;
231
                        }
232
233
220
                        for (j = 0; likely(j < length); j++) {
234
147
                            if ( likely(value->u.array.values[j]->type == json_string) ) {
235
146
                                config->queries[j] =
236
146
                                    (char *) value->u.array.values[j]->u.string.ptr;
237
                            } else {
238
1
                                WSS_log_error("Invalid query");
239
1
                                WSS_config_free(config);
240
1
                                return WSS_CONFIG_INVALID_QUERY;
241
                            }
242
                        }
243
73
                        config->queries_length = length;
244
                    }
245

79
                } else if ( strncmp(name, "setup", 5) == 0 && likely(value->type == json_object) ) {
246
79
                    if ( (val = json_value_find(value, "subprotocols")) != NULL ) {
247
77
                        if ( val->type == json_array) {
248
77
                            length = val->u.array.length;
249
250
77
                            if (length > 0) {
251
76
                                if ( unlikely(NULL == (config->subprotocols = WSS_calloc(length, sizeof(char *)))) ) {
252
                                    WSS_log_error("Unable to calloc subprotocols");
253
                                    WSS_config_free(config);
254
                                    return WSS_MEMORY_ERROR;
255
                                }
256
257
76
                                if ( unlikely(NULL == (config->subprotocols_config = WSS_calloc(length, sizeof(char *)))) ) {
258
                                    WSS_log_error("Unable to calloc subprotocols configuration");
259
                                    WSS_config_free(config);
260
                                    return WSS_MEMORY_ERROR;
261
                                }
262
263
224
                                for (j = 0; likely(j < length); j++) {
264
150
                                    if ( likely(val->u.array.values[j]->type == json_object) ) {
265
149
                                        if ( (temp = json_value_find(val->u.array.values[j], "file")) != NULL ) {
266
149
                                            if ( temp->type == json_string ) {
267
148
                                                config->subprotocols[j] =
268
148
                                                    (char *) temp->u.string.ptr;
269
148
                                                WSS_log_info("Found extension %s from configuration", config->subprotocols[j]);
270
                                            } else {
271
1
                                                WSS_log_error("Invalid subprotocol");
272
1
                                                WSS_config_free(config);
273
1
                                                return WSS_CONFIG_INVALID_SUBPROTOCOL;
274
                                            }
275
                                        }
276
277
148
                                        if ( (temp = json_value_find(val->u.array.values[j], "config")) != NULL ) {
278
148
                                            if ( temp->type == json_string ) {
279
147
                                                config->subprotocols_config[j] =
280
147
                                                    (char *) temp->u.string.ptr;
281
                                            } else {
282
1
                                                config->subprotocols_config[j] = NULL;
283
                                            }
284
                                        }
285
                                    } else {
286
1
                                        WSS_log_error("Invalid subprotocol");
287
1
                                        WSS_config_free(config);
288
1
                                        return WSS_CONFIG_INVALID_SUBPROTOCOL;
289
                                    }
290
                                }
291
                            } else {
292
1
                                config->subprotocols = NULL;
293
                            }
294
295
75
                            config->subprotocols_length = length;
296
75
                            WSS_log_info("Found %d subprotocols", length);
297
                        }
298
                    }
299
300
77
                    if ( (val = json_value_find(value, "extensions")) != NULL ) {
301
77
                        if ( likely(val->type == json_array) ) {
302
77
                            length = val->u.array.length;
303
304
77
                            if (length > 0) {
305
76
                                if ( unlikely(NULL == (config->extensions = WSS_calloc(length, sizeof(char *)))) ) {
306
                                    WSS_log_error("Unable to calloc extensions");
307
                                    WSS_config_free(config);
308
                                    return WSS_MEMORY_ERROR;
309
                                }
310
311
76
                                if ( unlikely(NULL == (config->extensions_config = WSS_calloc(length, sizeof(char *)))) ) {
312
                                    WSS_log_error("Unable to calloc extensions configuration");
313
                                    WSS_config_free(config);
314
                                    return WSS_MEMORY_ERROR;
315
                                }
316
317
150
                                for (j = 0; likely(j < length); j++) {
318
76
                                    if ( likely(val->u.array.values[j]->type == json_object) ) {
319
75
                                        if ( (temp = json_value_find(val->u.array.values[j], "file")) != NULL ) {
320
75
                                            if ( likely(temp->type == json_string) ) {
321
74
                                                config->extensions[j] =
322
74
                                                    (char *) temp->u.string.ptr;
323
74
                                                WSS_log_info("Found extension %s from configuration", config->extensions[j]);
324
                                            } else {
325
1
                                                WSS_log_error("Invalid extension");
326
1
                                                WSS_config_free(config);
327
1
                                                return WSS_CONFIG_INVALID_EXTENSION;
328
                                            }
329
                                        }
330
331
74
                                        if ( (temp = json_value_find(val->u.array.values[j], "config")) != NULL ) {
332
74
                                            if ( likely(temp->type == json_string) ) {
333
73
                                                config->extensions_config[j] =
334
73
                                                    (char *) temp->u.string.ptr;
335
                                            } else {
336
1
                                                config->extensions_config[j] = NULL;
337
                                            }
338
                                        }
339
                                    } else {
340
1
                                        WSS_log_error("Invalid extension");
341
1
                                        WSS_config_free(config);
342
1
                                        return WSS_CONFIG_INVALID_EXTENSION;
343
                                    }
344
                                }
345
                            } else {
346
1
                                config->extensions = NULL;
347
                            }
348
349
75
                            config->extensions_length = length;
350
75
                            WSS_log_info("Found %d extensions", length);
351
                        }
352
                    }
353
354
75
                    if ( (val = json_value_find(value, "favicon")) != NULL ) {
355
74
                        if ( likely(val->type == json_string) ) {
356
74
                            config->favicon = (char *)val->u.string.ptr;
357
                        }
358
                    }
359
360
75
                    if ( (val = json_value_find(value, "log_level")) != NULL ) {
361
74
                        if ( likely(val->type == json_integer) ) {
362
74
                            config->log = (unsigned int)val->u.integer;
363
                        }
364
                    }
365
366
75
                    if ( (val = json_value_find(value, "timeouts")) != NULL ) {
367
74
                        if ( likely(val->type == json_object) ) {
368
                            // Getting poll timeout
369
74
                            temp = json_value_find(val, "poll");
370

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
371
74
                                config->timeout_poll = temp->u.integer;
372
                            }
373
374
                            // Getting read timeout
375
74
                            temp = json_value_find(val, "read");
376

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
377
74
                                config->timeout_read = temp->u.integer;
378
                            }
379
380
                            // Getting write timeout
381
74
                            temp = json_value_find(val, "write");
382

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
383
74
                                config->timeout_write = temp->u.integer;
384
                            }
385
386
                            // Getting client timeout
387
74
                            temp = json_value_find(val, "client");
388

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
389
74
                                config->timeout_client = temp->u.integer;
390
                            }
391
392
                            // Getting amount of client pings
393
74
                            temp = json_value_find(val, "pings");
394

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
395
74
                                config->timeout_pings = temp->u.integer;
396
                            }
397
                        }
398
                    }
399
400
75
                    if ( (val = json_value_find(value, "ssl")) != NULL ) {
401
74
                        if ( likely(val->type == json_object) ) {
402
                            // Getting SSL key path
403
74
                            temp = json_value_find(val, "key");
404

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
405
74
                                config->ssl_key = (char *)temp->u.string.ptr;
406
                            }
407
408
                            // Getting SSL cert path
409
74
                            temp = json_value_find(val, "cert");
410

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
411
74
                                config->ssl_cert = (char *)temp->u.string.ptr;
412
                            }
413
414
                            // Getting SSL CA cert path
415
74
                            temp = json_value_find(val, "ca_file");
416

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
417
74
                                config->ssl_ca_file = (char *)temp->u.string.ptr;
418
                            }
419
420
                            // Getting SSL CA cert path
421
74
                            temp = json_value_find(val, "ca_path");
422

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
423
74
                                config->ssl_ca_path = (char *)temp->u.string.ptr;
424
                            }
425
426
                            // Getting whether SSL should use compression
427
74
                            temp = json_value_find(val, "compression");
428

74
                            if ( temp != NULL && likely(temp->type == json_boolean) ) {
429
74
                                config->ssl_compression = temp->u.boolean;
430
                            }
431
432
                            // Getting whether peer certificate is required
433
74
                            temp = json_value_find(val, "peer_cert");
434

74
                            if ( temp != NULL && likely(temp->type == json_boolean) ) {
435
74
                                config->ssl_peer_cert = temp->u.boolean;
436
                            }
437
438
                            // Getting diffie helman parameters to use
439
74
                            temp = json_value_find(val, "dhparam");
440

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
441
74
                                config->ssl_dhparam = (char *)temp->u.string.ptr;
442
                            }
443
444
                            // Getting list of ciphers to use for SSL
445
74
                            temp = json_value_find(val, "cipher_list");
446

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
447
74
                                config->ssl_cipher_list = (char *)temp->u.string.ptr;
448
                            }
449
450
                            // Getting suites of ciphers to use for TLS 1.3
451
74
                            temp = json_value_find(val, "cipher_suites");
452

74
                            if ( temp != NULL && likely(temp->type == json_string) ) {
453
74
                                config->ssl_cipher_suites = (char *)temp->u.string.ptr;
454
                            }
455
                        }
456
                    }
457
458
75
                    if ( (val = json_value_find(value, "port")) != NULL ) {
459
74
                        if ( likely(val->type == json_object) ) {
460
                            // Getting HTTP port
461
74
                            temp = json_value_find(val, "http");
462

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
463
74
                                config->port_http =
464
74
                                    (unsigned int)temp->u.integer;
465
                            }
466
467
                            // Getting HTTPS port
468
74
                            temp = json_value_find(val, "https");
469

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
470
74
                                config->port_https =
471
74
                                    (unsigned int)temp->u.integer;
472
                            }
473
                        }
474
                    }
475
476
75
                    if ( (val = json_value_find(value, "size")) != NULL ) {
477
74
                        if ( likely(val->type == json_object) ) {
478
                            // Getting buffer size
479
74
                            temp = json_value_find(val, "buffer");
480

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
481
74
                                config->size_buffer =
482
74
                                    (unsigned int)temp->u.integer;
483
                            }
484
485
                            // Getting thread size
486
74
                            temp = json_value_find(val, "thread");
487

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
488
74
                                config->size_thread =
489
74
                                    (unsigned int)temp->u.integer;
490
                            }
491
492
                            // Getting uri size
493
74
                            temp = json_value_find(val, "uri");
494

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
495
74
                                config->size_uri =
496
74
                                    (unsigned int)temp->u.integer;
497
                            }
498
499
                            // Getting header size
500
74
                            temp = json_value_find(val, "header");
501

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
502
74
                                config->size_header =
503
74
                                    (unsigned int)temp->u.integer;
504
                            }
505
506
                            // Getting ringbuffer size
507
74
                            temp = json_value_find(val, "ringbuffer");
508

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
509
74
                                config->size_ringbuffer =
510
74
                                    (unsigned int)temp->u.integer;
511
                            }
512
513
                            // Getting payload size
514
74
                            temp = json_value_find(val, "payload");
515

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
516
74
                                config->size_payload =
517
74
                                    (unsigned int)temp->u.integer;
518
                            }
519
520
                            // Getting frame payload size
521
74
                            temp = json_value_find(val, "frame");
522

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
523
74
                                config->size_frame =
524
74
                                    (unsigned int)temp->u.integer;
525
                            }
526
527
                            // Getting max frame count for fragmented messages
528
74
                            temp = json_value_find(val, "fragmented");
529

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
530
74
                                config->max_frames =
531
74
                                    (unsigned int)temp->u.integer;
532
                            }
533
                        }
534
                    }
535
536
75
                    if ( (val = json_value_find(value, "pool")) != NULL ) {
537
74
                        if ( likely(val->type == json_object) ) {
538
                            // Getting amount of workers
539
74
                            temp = json_value_find(val, "workers");
540

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
541
74
                                config->pool_workers =
542
74
                                    (unsigned int)temp->u.integer;
543
                            }
544
545
                            // Getting amount of retries
546
74
                            temp = json_value_find(val, "retries");
547

74
                            if ( temp != NULL && likely(temp->type == json_integer) ) {
548
73
                                config->pool_retries =
549
73
                                    (unsigned int)temp->u.integer;
550
                            }
551
                        }
552
                    }
553
                }
554
            }
555
        } else {
556
1
            WSS_log_error("Root level of configuration is expected to be a JSON Object.");
557
1
            WSS_config_free(config);
558
1
            return WSS_CONFIG_JSON_ROOT_ERROR;
559
        }
560
    }
561
562
75
    if ( config->timeout_poll < 0 ) {
563
1
        config->timeout_poll = -1;
564
    }
565
566
75
    if ( config->timeout_read < 0 ) {
567
1
        config->timeout_read = -1;
568
    }
569
570
75
    if ( config->timeout_write < 0 ) {
571
1
        config->timeout_write = -1;
572
    }
573
574
75
    if ( config->timeout_client < 0 ) {
575
1
        config->timeout_client = -1;
576
    }
577
578
75
    if ( unlikely(config->port_http == 0 && config->port_https == 0) ) {
579
1
        WSS_log_error("No port chosen");
580
1
        WSS_config_free(config);
581
1
        return WSS_CONFIG_NO_PORT_ERROR;
582
    }
583
584
74
    if ( likely(config->hosts_length > 0) ) {
585
72
        return config_add_port_to_hosts(config);
586
    }
587
588
    return WSS_SUCCESS;
589
}
590
591
/**
592
 * Frees allocated memory from configuration
593
 *
594
 * @param   config  [wss_config_t *]    "The configuration structure to free"
595
 * @return 			[wss_error_t]       "The error status"
596
 */
597
103
wss_error_t WSS_config_free(wss_config_t *config) {
598
103
    unsigned int amount = 1;
599
600
103
    if ( likely(NULL != config) ) {
601
103
        if ( likely(config->port_http > 0) ) {
602
73
            amount++;
603
        }
604
605
103
        if ( likely(config->port_https > 0) ) {
606
73
            amount++;
607
        }
608
609
103
        if ( likely(amount > 1) ) {
610
73
            if ( NULL != config->hosts ) {
611
72
                WSS_free((void **)&config->hosts[(config->hosts_length/amount)*(amount-1)]);
612
            }
613
        }
614
615
103
        if ( likely(NULL != config->data) ) {
616
83
            json_value_free_ex(&settings, config->data);
617
83
            config->data = NULL;
618
        }
619
620
103
        WSS_free((void **) &config->string);
621
103
        WSS_free((void **) &config->hosts);
622
103
        WSS_free((void **) &config->origins);
623
103
        WSS_free((void **) &config->queries);
624
103
        WSS_free((void **) &config->extensions);
625
103
        WSS_free((void **) &config->subprotocols);
626
103
        WSS_free((void **) &config->extensions_config);
627
103
        WSS_free((void **) &config->subprotocols_config);
628
    }
629
630
103
    return WSS_SUCCESS;
631
}