2
* libwebsockets - small server side websockets and web server implementation
4
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
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.
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.
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,
22
#include "private-libwebsockets.h"
24
#ifndef LWS_BUILD_HASH
25
#define LWS_BUILD_HASH "unknown-build-hash"
28
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
31
* lws_get_library_version: get version and git hash library built from
33
* returns a const char * to a string like "1.1 178d78c"
34
* representing the library version followed by the git head hash it
38
LWS_VISIBLE const char *
39
lws_get_library_version(void)
41
return library_version;
45
* libwebsocket_create_context() - Create the websocket handler
46
* @info: pointer to struct with parameters
48
* This function creates the listening socket (if serving) and takes care
49
* of all initialization in one step.
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.
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
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.
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.
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.
74
LWS_VISIBLE struct libwebsocket_context *
75
libwebsocket_create_context(struct lws_context_creation_info *info)
77
struct libwebsocket_context *context = NULL;
80
int pid_daemon = get_daemonize_pid();
82
lwsl_notice("Initial logging level %d\n", log_level);
83
lwsl_notice("Library version: %s\n", library_version);
85
if (!(info->options & LWS_SERVER_OPTION_DISABLE_IPV6))
86
lwsl_notice("IPV6 compiled in and enabled\n");
88
lwsl_notice("IPV6 compiled in but disabled\n");
90
lwsl_notice("IPV6 not compiled in\n");
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);
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);
101
if (lws_plat_context_early_init())
104
context = (struct libwebsocket_context *)
105
malloc(sizeof(struct libwebsocket_context));
107
lwsl_err("No memory for websocket context\n");
110
memset(context, 0, sizeof(*context));
113
context->started_with_parent = pid_daemon;
114
lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
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 *),
132
sizeof(struct libwebsocket_context) +
133
((sizeof(struct libwebsocket_pollfd) +
134
sizeof(struct libwebsocket *)) *
137
context->fds = (struct libwebsocket_pollfd *)
138
malloc(sizeof(struct libwebsocket_pollfd) *
140
if (context->fds == NULL) {
141
lwsl_err("Unable to allocate fds array for %d connections\n",
147
context->lws_lookup = (struct libwebsocket **)
148
malloc(sizeof(struct libwebsocket *) * context->max_fds);
149
if (context->lws_lookup == NULL) {
151
"Unable to allocate lws_lookup array for %d connections\n",
157
memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) *
160
if (lws_plat_init_fd_tables(context)) {
161
free(context->lws_lookup);
167
lws_context_init_extensions(info, context);
169
context->user_space = info->user;
171
strcpy(context->canonical_hostname, "unknown");
173
lws_server_get_canonical_hostname(context, info);
175
/* split the proxy ads:port if given */
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;
185
p = getenv("http_proxy");
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';
192
p = strchr(context->http_proxy_address, ':');
194
lwsl_err("http_proxy needs to be ads:port\n");
198
context->http_proxy_port = atoi(p + 1);
203
if (context->http_proxy_address[0])
204
lwsl_notice(" Proxy %s:%u\n",
205
context->http_proxy_address,
206
context->http_proxy_port);
209
" per-conn mem: %u + %u headers + protocol rx buf\n",
210
sizeof(struct libwebsocket),
211
sizeof(struct allocated_headers));
213
if (lws_context_init_server_ssl(info, context))
216
if (lws_context_init_client_ssl(info, context))
219
if (lws_context_init_server(info, context))
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
227
lws_plat_drop_app_privileges(info);
229
/* initialize supported protocols */
231
for (context->count_protocols = 0;
232
info->protocols[context->count_protocols].callback;
233
context->count_protocols++) {
235
lwsl_parser(" Protocol: %s\n",
236
info->protocols[context->count_protocols].name);
238
info->protocols[context->count_protocols].owning_server =
240
info->protocols[context->count_protocols].protocol_index =
241
context->count_protocols;
244
* inform all the protocols that they are doing their one-time
245
* initialization if they want to
247
info->protocols[context->count_protocols].callback(context,
248
NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
252
* give all extensions a chance to create any per-context
253
* allocations they need
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,
262
if (lws_ext_callback_for_each_extension_type(context, NULL,
263
LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT,
270
libwebsocket_context_destroy(context);
275
* libwebsocket_context_destroy() - Destroy the websocket context
276
* @context: Websocket context
278
* This function closes any active connections and then frees the
279
* context. After calling this, any further use of the context is
283
libwebsocket_context_destroy(struct libwebsocket_context *context)
286
struct libwebsocket_protocols *protocol = context->protocols;
288
lwsl_notice("%s\n", __func__);
291
if (context->worst_latency_info[0])
292
lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
295
for (n = 0; n < context->fds_count; n++) {
296
struct libwebsocket *wsi =
297
context->lws_lookup[context->fds[n].fd];
300
libwebsocket_close_and_free_session(context,
301
wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
306
* give all extensions a chance to clean up any per-context
307
* allocations they might have made
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)
314
if (lws_ext_callback_for_each_extension_type(context, NULL,
315
LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, NULL, 0) < 0)
319
* inform all the protocols that they are done and will have no more
323
while (protocol->callback) {
324
protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
329
lws_plat_context_early_destroy(context);
331
lws_ssl_context_destroy(context);
335
if (context->lws_lookup)
336
free(context->lws_lookup);
338
lws_plat_context_late_destroy(context);