GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/extensions.c Lines: 91 104 87.5 %
Date: 2020-12-10 21:44:00 Branches: 60 130 46.2 %

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











6
        HASH_ADD_KEYPTR(hh, extensions, proto->name, name_length, proto);
152
153
3
        WSS_log_trace("Setting custom allocators for extension %s", proto->name);
154
155
3
        proto->alloc(WSS_malloc, WSS_realloc_normal, WSS_free_normal);
156
157
3
        WSS_log_trace("Initializing extension %s", proto->name);
158
159
3
        proto->init(config->extensions_config[i]);
160
161
3
        WSS_log_info("Successfully loaded %s extension", proto->name);
162
    }
163
}
164
165
/**
166
 * Function that looks for a extension implementation of the name given.
167
 *
168
 * @param 	name	[char *] 	            "The name of the extension"
169
 * @return 	      	[wss_extension_t *]   "The extension or NULL"
170
 */
171
18
wss_extension_t *WSS_find_extension(char *name) {
172
18
    wss_extension_t *proto;
173
174
18
    if ( unlikely(NULL == name) ) {
175
        return NULL;
176
    }
177
178







31
    HASH_FIND_STR(extensions, name, proto);
179
180
    return proto;
181
}
182
183
/**
184
 * Destroys all memory used to load and store the extensions
185
 *
186
 * @return 	[void]
187
 */
188
14
void WSS_destroy_extensions() {
189
14
    wss_extension_t *proto, *tmp;
190
191

34
    HASH_ITER(hh, extensions, proto, tmp) {
192




3
        HASH_DEL(extensions, proto);
193
3
        proto->destroy();
194
3
        dlclose(proto->handle);
195
3
        WSS_free((void **) &proto->name);
196
3
        WSS_free((void **) &proto);
197
    }
198
14
}