GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/subprotocols.c Lines: 81 94 86.2 %
Date: 2020-12-10 21:44:00 Branches: 65 126 51.6 %

Line Branch Exec Source
1
#include <dlfcn.h>
2
#include <stdio.h>
3
#include <libgen.h>
4
#include <unistd.h>
5
6
#include "subprotocols.h"
7
#include "subprotocol.h"
8
#include "uthash.h"
9
#include "message.h"
10
#include "alloc.h"
11
#include "log.h"
12
#include "predict.h"
13
14
/**
15
 * Global hashtable of subprotocols
16
 */
17
wss_subprotocol_t *subprotocols = NULL;
18
19
/**
20
 * Function that loads subprotocol implementations into memory, by loading the
21
 * shared objects defined in the configuration.
22
 *
23
 * E.g.
24
 *
25
 * subprotocols/echo/echo.so
26
 * subprotocols/broadcast/broadcast.so
27
 *
28
 * @param 	config	[config_t *] 	"The configuration of the server"
29
 * @return 	      	[void]
30
 */
31
22
void WSS_load_subprotocols(wss_config_t *config)
32
{
33
22
    size_t i, j;
34
22
    char *name;
35
22
    char *pyname;
36
22
    int *handle;
37
22
    wss_subprotocol_t* proto;
38
22
    int name_length;
39
40
22
    if ( unlikely(NULL == config) ) {
41
1
        return;
42
    }
43
44
21
    WSS_log_trace("Loading %d subprotocols", config->subprotocols_length);
45
46
76
    for (i = 0; i < config->subprotocols_length; i++) {
47
34
        name_length = 0;
48
49
34
        WSS_log_trace("Loading subprotocol %s", config->subprotocols[i]);
50
51
34
        if ( unlikely(NULL == (handle = dlopen(config->subprotocols[i], RTLD_LAZY))) ) {
52
1
            WSS_log_error("Failed to load shared object: %s", dlerror());
53
1
            continue;
54
        }
55
56
33
        if ( unlikely(NULL == (proto = WSS_malloc(sizeof(wss_subprotocol_t)))) ) {
57
            WSS_log_error("Unable to allocate subprotocol structure");
58
            dlclose(handle);
59
            return;
60
        }
61
33
        proto->handle = handle;
62
63
33
        if ( unlikely((*(void**)(&proto->alloc) = dlsym(proto->handle, "setAllocators")) == NULL) ) {
64
1
            WSS_log_error("Failed to find 'setAllocators' function: %s", dlerror());
65
1
            dlclose(proto->handle);
66
1
            WSS_free((void **) &proto);
67
1
            continue;
68
        }
69
70
32
        if ( unlikely((*(void**)(&proto->init) = dlsym(proto->handle, "onInit")) == NULL) ) {
71
1
            WSS_log_error("Failed to find 'onInit' function: %s", dlerror());
72
1
            dlclose(proto->handle);
73
1
            WSS_free((void **) &proto);
74
1
            continue;
75
        }
76
77
31
        if ( unlikely((*(void**)(&proto->connect) = dlsym(proto->handle, "onConnect")) == NULL) ) {
78
1
            WSS_log_error("Failed to find 'onConnect' function: %s", dlerror());
79
1
            dlclose(proto->handle);
80
1
            WSS_free((void **) &proto);
81
1
            continue;
82
        }
83
84
30
        if ( unlikely((*(void**)(&proto->message) = dlsym(proto->handle, "onMessage")) == NULL) ) {
85
1
            WSS_log_error("Failed to find 'onMessage' function: %s", dlerror());
86
1
            dlclose(proto->handle);
87
1
            WSS_free((void **) &proto);
88
1
            continue;
89
        }
90
91
29
        if ( unlikely((*(void**)(&proto->write) = dlsym(proto->handle, "onWrite")) == NULL) ) {
92
1
            WSS_log_error("Failed to find 'onWrite' function: %s", dlerror());
93
1
            dlclose(proto->handle);
94
1
            WSS_free((void **) &proto);
95
1
            continue;
96
        }
97
98
28
        if ( unlikely((*(void**)(&proto->close) = dlsym(proto->handle, "onClose")) == NULL) ) {
99
1
            WSS_log_error("Failed to find 'onClose' function: %s", dlerror());
100
1
            dlclose(proto->handle);
101
1
            WSS_free((void **) &proto);
102
1
            continue;
103
        }
104
105
27
        if ( unlikely((*(void**)(&proto->destroy) = dlsym(proto->handle, "onDestroy")) == NULL) ) {
106
1
            WSS_log_error("Failed to find 'onDestroy' function: %s", dlerror());
107
1
            dlclose(proto->handle);
108
1
            WSS_free((void **) &proto);
109
1
            continue;
110
        }
111
112
26
        name = basename(config->subprotocols[i]);
113
221
        for (j = 0; name[j] != '.' && name[j] != '\0'; j++) {
114
169
            name_length++;
115
        }
116
117
26
        if ( unlikely(NULL == (proto->name = WSS_malloc(name_length+1))) ) {
118
            WSS_log_error("Unable to allocate name");
119
            dlclose(proto->handle);
120
            WSS_free((void **) &proto);
121
            return;
122
        }
123
124
        // Call Cython init if available
125
26
        if ( unlikely(NULL == (pyname = WSS_malloc(7+name_length+1))) ) {
126
            WSS_log_error("Unable to allocate name");
127
            dlclose(proto->handle);
128
            WSS_free((void **) &proto->name);
129
            WSS_free((void **) &proto);
130
            return;
131
        }
132
133
26
        sprintf(pyname, "PyInit_%s", name);
134
26
        if ( unlikely((*(void**)(&proto->pyinit) = dlsym(proto->handle, name)) != NULL) ) {
135
            proto->pyinit();
136
        }
137
26
        WSS_free((void **) &pyname);
138
139
26
        memcpy(proto->name, name, name_length);
140
141











26
        HASH_ADD_KEYPTR(hh, subprotocols, proto->name, name_length, proto);
142
143
26
        WSS_log_trace("Setting custom allocators for subprotocol %s", proto->name);
144
145
        // Set custom allocators
146
26
        proto->alloc(WSS_malloc, WSS_realloc_normal, WSS_free_normal);
147
148
26
        WSS_log_trace("Initializing subprotocol %s", proto->name);
149
150
        // Initialize subprotocol
151
26
        proto->init(config->subprotocols_config[i], WSS_message_send);
152
153
26
        WSS_log_info("Successfully loaded %s extension", proto->name);
154
    }
155
}
156
157
/**
158
 * Function that looks for a subprotocol implementation of the name given.
159
 *
160
 * @param 	name	[char *] 	            "The name of the subprotocol"
161
 * @return 	      	[wss_subprotocol_t *]   "The subprotocol or NULL"
162
 */
163
43
wss_subprotocol_t *WSS_find_subprotocol(char *name) {
164
43
    wss_subprotocol_t *proto;
165
166
43
    if ( unlikely(NULL == name) ) {
167
        return NULL;
168
    }
169
170







66
    HASH_FIND_STR(subprotocols, name, proto);
171
172
    return proto;
173
}
174
175
/**
176
 * Destroys all memory used to load and store the subprotocols
177
 *
178
 * @return 	[void]
179
 */
180
22
void WSS_destroy_subprotocols() {
181
22
    wss_subprotocol_t *proto, *tmp;
182
183

96
    HASH_ITER(hh, subprotocols, proto, tmp) {
184




26
        HASH_DEL(subprotocols, proto);
185
26
        proto->destroy();
186
26
        dlclose(proto->handle);
187
26
        WSS_free((void **) &proto->name);
188
26
        WSS_free((void **) &proto);
189
    }
190
22
}