~roger.light/ubuntu/vivid/libwebsockets/fix-for-1422623

« back to all changes in this revision

Viewing changes to lib/context.c

  • Committer: Roger A. Light
  • Date: 2015-02-19 16:00:08 UTC
  • mfrom: (1.1.1)
  • Revision ID: roger@atchoo.org-20150219160008-162cd9naiu2yekny
New upstream release 1.3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * libwebsockets - small server side websockets and web server implementation
 
3
 *
 
4
 * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
 
5
 *
 
6
 *  This library is free software; you can redistribute it and/or
 
7
 *  modify it under the terms of the GNU Lesser General Public
 
8
 *  License as published by the Free Software Foundation:
 
9
 *  version 2.1 of the License.
 
10
 *
 
11
 *  This library is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 *  Lesser General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU Lesser General Public
 
17
 *  License along with this library; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
19
 *  MA  02110-1301  USA
 
20
 */
 
21
 
 
22
#include "private-libwebsockets.h"
 
23
 
 
24
#ifndef LWS_BUILD_HASH
 
25
#define LWS_BUILD_HASH "unknown-build-hash"
 
26
#endif
 
27
 
 
28
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
 
29
 
 
30
/**
 
31
 * lws_get_library_version: get version and git hash library built from
 
32
 *
 
33
 *      returns a const char * to a string like "1.1 178d78c"
 
34
 *      representing the library version followed by the git head hash it
 
35
 *      was built from
 
36
 */
 
37
 
 
38
LWS_VISIBLE const char *
 
39
lws_get_library_version(void)
 
40
{
 
41
        return library_version;
 
42
}
 
43
 
 
44
/**
 
45
 * libwebsocket_create_context() - Create the websocket handler
 
46
 * @info:       pointer to struct with parameters
 
47
 *
 
48
 *      This function creates the listening socket (if serving) and takes care
 
49
 *      of all initialization in one step.
 
50
 *
 
51
 *      After initialization, it returns a struct libwebsocket_context * that
 
52
 *      represents this server.  After calling, user code needs to take care
 
53
 *      of calling libwebsocket_service() with the context pointer to get the
 
54
 *      server's sockets serviced.  This must be done in the same process
 
55
 *      context as the initialization call.
 
56
 *
 
57
 *      The protocol callback functions are called for a handful of events
 
58
 *      including http requests coming in, websocket connections becoming
 
59
 *      established, and data arriving; it's also called periodically to allow
 
60
 *      async transmission.
 
61
 *
 
62
 *      HTTP requests are sent always to the FIRST protocol in @protocol, since
 
63
 *      at that time websocket protocol has not been negotiated.  Other
 
64
 *      protocols after the first one never see any HTTP callack activity.
 
65
 *
 
66
 *      The server created is a simple http server by default; part of the
 
67
 *      websocket standard is upgrading this http connection to a websocket one.
 
68
 *
 
69
 *      This allows the same server to provide files like scripts and favicon /
 
70
 *      images or whatever over http and dynamic data over websockets all in
 
71
 *      one place; they're all handled in the user callback.
 
72
 */
 
73
 
 
74
LWS_VISIBLE struct libwebsocket_context *
 
75
libwebsocket_create_context(struct lws_context_creation_info *info)
 
76
{
 
77
        struct libwebsocket_context *context = NULL;
 
78
        char *p;
 
79
 
 
80
        int pid_daemon = get_daemonize_pid();
 
81
 
 
82
        lwsl_notice("Initial logging level %d\n", log_level);
 
83
        lwsl_notice("Library version: %s\n", library_version);
 
84
#ifdef LWS_USE_IPV6
 
85
        if (!(info->options & LWS_SERVER_OPTION_DISABLE_IPV6))
 
86
                lwsl_notice("IPV6 compiled in and enabled\n");
 
87
        else
 
88
                lwsl_notice("IPV6 compiled in but disabled\n");
 
89
#else
 
90
        lwsl_notice("IPV6 not compiled in\n");
 
91
#endif
 
92
        lws_feature_status_libev(info);
 
93
        lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN);
 
94
        lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS);
 
95
 
 
96
        lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED);
 
97
        lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT);
 
98
        lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
 
99
        lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER);
 
100
 
 
101
        if (lws_plat_context_early_init())
 
102
                return NULL;
 
103
 
 
104
        context = (struct libwebsocket_context *)
 
105
                                malloc(sizeof(struct libwebsocket_context));
 
106
        if (!context) {
 
107
                lwsl_err("No memory for websocket context\n");
 
108
                return NULL;
 
109
        }
 
110
        memset(context, 0, sizeof(*context));
 
111
 
 
112
        if (pid_daemon) {
 
113
                context->started_with_parent = pid_daemon;
 
114
                lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
 
115
        }
 
116
 
 
117
        context->listen_service_extraseen = 0;
 
118
        context->protocols = info->protocols;
 
119
        context->token_limits = info->token_limits;
 
120
        context->listen_port = info->port;
 
121
        context->http_proxy_port = 0;
 
122
        context->http_proxy_address[0] = '\0';
 
123
        context->options = info->options;
 
124
        context->iface = info->iface;
 
125
        /* to reduce this allocation, */
 
126
        context->max_fds = getdtablesize();
 
127
        lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n",
 
128
                sizeof(struct libwebsocket_context),
 
129
                sizeof(struct libwebsocket_pollfd) +
 
130
                                        sizeof(struct libwebsocket *),
 
131
                context->max_fds,
 
132
                sizeof(struct libwebsocket_context) +
 
133
                ((sizeof(struct libwebsocket_pollfd) +
 
134
                                        sizeof(struct libwebsocket *)) *
 
135
                                                             context->max_fds));
 
136
 
 
137
        context->fds = (struct libwebsocket_pollfd *)
 
138
                                malloc(sizeof(struct libwebsocket_pollfd) *
 
139
                                                              context->max_fds);
 
140
        if (context->fds == NULL) {
 
141
                lwsl_err("Unable to allocate fds array for %d connections\n",
 
142
                                                              context->max_fds);
 
143
                free(context);
 
144
                return NULL;
 
145
        }
 
146
 
 
147
        context->lws_lookup = (struct libwebsocket **)
 
148
                      malloc(sizeof(struct libwebsocket *) * context->max_fds);
 
149
        if (context->lws_lookup == NULL) {
 
150
                lwsl_err(
 
151
                  "Unable to allocate lws_lookup array for %d connections\n",
 
152
                                                              context->max_fds);
 
153
                free(context->fds);
 
154
                free(context);
 
155
                return NULL;
 
156
        }
 
157
        memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) *
 
158
                                                        context->max_fds);
 
159
 
 
160
        if (lws_plat_init_fd_tables(context)) {
 
161
                free(context->lws_lookup);
 
162
                free(context->fds);
 
163
                free(context);
 
164
                return NULL;
 
165
        }
 
166
 
 
167
        lws_context_init_extensions(info, context);
 
168
 
 
169
        context->user_space = info->user;
 
170
 
 
171
        strcpy(context->canonical_hostname, "unknown");
 
172
 
 
173
        lws_server_get_canonical_hostname(context, info);
 
174
 
 
175
        /* split the proxy ads:port if given */
 
176
 
 
177
        if (info->http_proxy_address) {
 
178
                strncpy(context->http_proxy_address, info->http_proxy_address,
 
179
                                      sizeof(context->http_proxy_address) - 1);
 
180
                context->http_proxy_address[
 
181
                                sizeof(context->http_proxy_address) - 1] = '\0';
 
182
                context->http_proxy_port = info->http_proxy_port;
 
183
        } else {
 
184
#ifdef HAVE_GETENV
 
185
                p = getenv("http_proxy");
 
186
                if (p) {
 
187
                        strncpy(context->http_proxy_address, p,
 
188
                                       sizeof(context->http_proxy_address) - 1);
 
189
                        context->http_proxy_address[
 
190
                                sizeof(context->http_proxy_address) - 1] = '\0';
 
191
 
 
192
                        p = strchr(context->http_proxy_address, ':');
 
193
                        if (p == NULL) {
 
194
                                lwsl_err("http_proxy needs to be ads:port\n");
 
195
                                goto bail;
 
196
                        }
 
197
                        *p = '\0';
 
198
                        context->http_proxy_port = atoi(p + 1);
 
199
                }
 
200
#endif
 
201
        }
 
202
 
 
203
        if (context->http_proxy_address[0])
 
204
                lwsl_notice(" Proxy %s:%u\n",
 
205
                                context->http_proxy_address,
 
206
                                                      context->http_proxy_port);
 
207
 
 
208
        lwsl_notice(
 
209
                " per-conn mem: %u + %u headers + protocol rx buf\n",
 
210
                                sizeof(struct libwebsocket),
 
211
                                              sizeof(struct allocated_headers));
 
212
                
 
213
        if (lws_context_init_server_ssl(info, context))
 
214
                goto bail;
 
215
        
 
216
        if (lws_context_init_client_ssl(info, context))
 
217
                goto bail;
 
218
 
 
219
        if (lws_context_init_server(info, context))
 
220
                goto bail;
 
221
 
 
222
        /*
 
223
         * drop any root privs for this process
 
224
         * to listen on port < 1023 we would have needed root, but now we are
 
225
         * listening, we don't want the power for anything else
 
226
         */
 
227
        lws_plat_drop_app_privileges(info);
 
228
 
 
229
        /* initialize supported protocols */
 
230
 
 
231
        for (context->count_protocols = 0;
 
232
                info->protocols[context->count_protocols].callback;
 
233
                                                   context->count_protocols++) {
 
234
 
 
235
                lwsl_parser("  Protocol: %s\n",
 
236
                                info->protocols[context->count_protocols].name);
 
237
 
 
238
                info->protocols[context->count_protocols].owning_server =
 
239
                                                                        context;
 
240
                info->protocols[context->count_protocols].protocol_index =
 
241
                                                       context->count_protocols;
 
242
 
 
243
                /*
 
244
                 * inform all the protocols that they are doing their one-time
 
245
                 * initialization if they want to
 
246
                 */
 
247
                info->protocols[context->count_protocols].callback(context,
 
248
                               NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
 
249
        }
 
250
 
 
251
        /*
 
252
         * give all extensions a chance to create any per-context
 
253
         * allocations they need
 
254
         */
 
255
 
 
256
        if (info->port != CONTEXT_PORT_NO_LISTEN) {
 
257
                if (lws_ext_callback_for_each_extension_type(context, NULL,
 
258
                                LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT,
 
259
                                                                   NULL, 0) < 0)
 
260
                        goto bail;
 
261
        } else
 
262
                if (lws_ext_callback_for_each_extension_type(context, NULL,
 
263
                                LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT,
 
264
                                                                   NULL, 0) < 0)
 
265
                        goto bail;
 
266
 
 
267
        return context;
 
268
 
 
269
bail:
 
270
        libwebsocket_context_destroy(context);
 
271
        return NULL;
 
272
}
 
273
 
 
274
/**
 
275
 * libwebsocket_context_destroy() - Destroy the websocket context
 
276
 * @context:    Websocket context
 
277
 *
 
278
 *      This function closes any active connections and then frees the
 
279
 *      context.  After calling this, any further use of the context is
 
280
 *      undefined.
 
281
 */
 
282
LWS_VISIBLE void
 
283
libwebsocket_context_destroy(struct libwebsocket_context *context)
 
284
{
 
285
        int n;
 
286
        struct libwebsocket_protocols *protocol = context->protocols;
 
287
 
 
288
        lwsl_notice("%s\n", __func__);
 
289
 
 
290
#ifdef LWS_LATENCY
 
291
        if (context->worst_latency_info[0])
 
292
                lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
 
293
#endif
 
294
 
 
295
        for (n = 0; n < context->fds_count; n++) {
 
296
                struct libwebsocket *wsi =
 
297
                                        context->lws_lookup[context->fds[n].fd];
 
298
                if (!wsi)
 
299
                        continue;
 
300
                libwebsocket_close_and_free_session(context,
 
301
                        wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
 
302
                n--;
 
303
        }
 
304
 
 
305
        /*
 
306
         * give all extensions a chance to clean up any per-context
 
307
         * allocations they might have made
 
308
         */
 
309
        if (context->listen_port) {
 
310
                if (lws_ext_callback_for_each_extension_type(context, NULL,
 
311
                         LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, NULL, 0) < 0)
 
312
                        return;
 
313
        } else
 
314
                if (lws_ext_callback_for_each_extension_type(context, NULL,
 
315
                         LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, NULL, 0) < 0)
 
316
                        return;
 
317
 
 
318
        /*
 
319
         * inform all the protocols that they are done and will have no more
 
320
         * callbacks
 
321
         */
 
322
 
 
323
        while (protocol->callback) {
 
324
                protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
 
325
                                NULL, NULL, 0);
 
326
                protocol++;
 
327
        }
 
328
 
 
329
        lws_plat_context_early_destroy(context);
 
330
 
 
331
        lws_ssl_context_destroy(context);
 
332
 
 
333
        if (context->fds)
 
334
                free(context->fds);
 
335
        if (context->lws_lookup)
 
336
                free(context->lws_lookup);
 
337
 
 
338
        lws_plat_context_late_destroy(context);
 
339
 
 
340
        free(context);
 
341
}