blob: 8c821efbee9cb5027c5cde68a6fff2917894fb1f [file] [log] [blame]
Andy Green4739e5c2011-01-22 12:51:57 +00001#include "private-libwebsockets.h"
2#include <netdb.h>
3
4
5/*
6 * In-place str to lower case
7 */
8
9void
10strtolower(char *s)
11{
Andy Green90c7cbc2011-01-27 06:26:52 +000012 while (*s) {
13 *s = tolower(*s);
14 s++;
15 }
Andy Green4739e5c2011-01-22 12:51:57 +000016}
17
Andy Green90c7cbc2011-01-27 06:26:52 +000018
19/**
20 * libwebsocket_client_connect() - Connect to another websocket server
21 * @this: Websocket context
22 * @address: Remote server address, eg, "myserver.com"
23 * @port: Port to connect to on the remote server, eg, 80
24 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
25 * signed certs
26 * @path: Websocket path on server
27 * @host: Hostname on server
28 * @origin: Socket origin name
29 * @protocol: Comma-separated list of protocols being asked for from
30 * the server, or just one. The server will pick the one it
31 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +000032 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
33 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +000034 *
35 * This function creates a connection to a remote server
36 */
37
Andy Green4739e5c2011-01-22 12:51:57 +000038struct libwebsocket *
Andy Green90c7cbc2011-01-27 06:26:52 +000039libwebsocket_client_connect(struct libwebsocket_context *this,
Andy Green4739e5c2011-01-22 12:51:57 +000040 const char *address,
41 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +000042 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +000043 const char *path,
44 const char *host,
45 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +000046 const char *protocol,
47 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +000048{
49 struct hostent *server_hostent;
50 struct sockaddr_in server_addr;
51 char buf[150];
52 char key_b64[150];
53 char hash[20];
Andy Green4739e5c2011-01-22 12:51:57 +000054 struct pollfd pfd;
55 static const char magic_websocket_guid[] =
56 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
57 static const char magic_websocket_04_masking_guid[] =
58 "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
59 char pkt[1024];
60 char *p = &pkt[0];
Andy Green6964bb52011-01-23 16:50:33 +000061 const char *pc;
Andy Green4739e5c2011-01-22 12:51:57 +000062 int len;
63 int okay = 0;
64 struct libwebsocket *wsi;
65 int n;
Andy Green9659f372011-01-27 22:01:43 +000066 int plen = 0;
Andy Green90c7cbc2011-01-27 06:26:52 +000067#ifdef LWS_OPENSSL_SUPPORT
68 char ssl_err_buf[512];
69#else
70 if (ssl_connection) {
71 fprintf(stderr, "libwebsockets not configured for ssl\n");
72 return NULL;
73 }
74#endif
Andy Green4739e5c2011-01-22 12:51:57 +000075
Andy Green6964bb52011-01-23 16:50:33 +000076 wsi = malloc(sizeof(struct libwebsocket));
Andy Green90c7cbc2011-01-27 06:26:52 +000077 if (wsi == NULL) {
Andy Green9659f372011-01-27 22:01:43 +000078 fprintf(stderr, "Out of memory allocing new connection\n");
Andy Green4739e5c2011-01-22 12:51:57 +000079 return NULL;
Andy Green90c7cbc2011-01-27 06:26:52 +000080 }
Andy Green4739e5c2011-01-22 12:51:57 +000081
Darin Willitsc19456f2011-02-14 17:52:39 +000082 memset(wsi, 0, sizeof *wsi);
83
Andy Greenbfb051f2011-02-09 08:49:14 +000084 /* -1 means just use latest supported */
85
86 if (ietf_version_or_minus_one == -1)
87 ietf_version_or_minus_one = 5;
88
89 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green4739e5c2011-01-22 12:51:57 +000090 wsi->name_buffer_pos = 0;
91 wsi->user_space = NULL;
92 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
93 wsi->pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +000094 wsi->protocol = NULL;
Andy Green4739e5c2011-01-22 12:51:57 +000095
Andy Greenbfb051f2011-02-09 08:49:14 +000096 /* set up appropriate masking */
97
98 wsi->xor_mask = xor_no_mask;
99
100 switch (wsi->ietf_spec_revision) {
101 case 4:
102 wsi->xor_mask = xor_mask_04;
103 break;
104 case 5:
105 wsi->xor_mask = xor_mask_05;
106 break;
107 default:
108 fprintf(stderr,
109 "Client ietf version %d not supported\n",
110 wsi->ietf_spec_revision);
111 return NULL;
112 }
113
114 /* force no mask if he asks for that though */
115
116 if (this->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
117 wsi->xor_mask = xor_no_mask;
118
Andy Green4739e5c2011-01-22 12:51:57 +0000119 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
120 wsi->utf8_token[n].token = NULL;
121 wsi->utf8_token[n].token_len = 0;
122 }
123
124 /*
Andy Green9659f372011-01-27 22:01:43 +0000125 * proxy?
126 */
127
128 if (this->http_proxy_port) {
129 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
130 "User-agent: libwebsockets\x0d\x0a"
131/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
132 "\x0d\x0a", address, port);
133
134 /* OK from now on we talk via the proxy */
135
136 address = this->http_proxy_address;
137 port = this->http_proxy_port;
138 }
139
140 /*
141 * prepare the actual connection (to the proxy, if any)
Andy Green4739e5c2011-01-22 12:51:57 +0000142 */
143
144 server_hostent = gethostbyname(address);
145 if (server_hostent == NULL) {
146 fprintf(stderr, "Unable to get host name from %s\n", address);
147 goto bail1;
148 }
149
150 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
Andy Green6964bb52011-01-23 16:50:33 +0000151
Andy Green4739e5c2011-01-22 12:51:57 +0000152 if (wsi->sock < 0) {
153 fprintf(stderr, "Unable to open socket\n");
154 goto bail1;
155 }
156
Andy Green0d338332011-02-12 11:57:43 +0000157 insert_wsi(this, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000158
159 server_addr.sin_family = AF_INET;
160 server_addr.sin_port = htons(port);
161 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
162 bzero(&server_addr.sin_zero, 8);
163
164 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
165 sizeof(struct sockaddr)) == -1) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000166 fprintf(stderr, "Connect failed\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000167 goto bail1;
Andy Green6964bb52011-01-23 16:50:33 +0000168 }
Andy Green4739e5c2011-01-22 12:51:57 +0000169
Andy Green9659f372011-01-27 22:01:43 +0000170 /* we are connected to server, or proxy */
171
Andy Green9659f372011-01-27 22:01:43 +0000172 if (this->http_proxy_port) {
173
174 n = send(wsi->sock, pkt, plen, 0);
175 if (n < 0) {
Andy Green5b9a4c02011-01-28 09:39:29 +0000176 close(wsi->sock);
177 fprintf(stderr, "ERROR writing to proxy socket\n");
178 goto bail1;
179 }
180
181 pfd.fd = wsi->sock;
182 pfd.events = POLLIN;
183 pfd.revents = 0;
184
185 n = poll(&pfd, 1, 5000);
186 if (n <= 0) {
187 close(wsi->sock);
188 fprintf(stderr, "libwebsocket_client_handshake "
189 "timeout on proxy response");
Andy Green02244bb2011-01-28 09:01:19 +0000190 goto bail1;
Andy Green9659f372011-01-27 22:01:43 +0000191 }
192
193 n = recv(wsi->sock, pkt, sizeof pkt, 0);
194 if (n < 0) {
Andy Green02244bb2011-01-28 09:01:19 +0000195 close(wsi->sock);
Andy Green5b9a4c02011-01-28 09:39:29 +0000196 fprintf(stderr, "ERROR reading from proxy socket\n");
Andy Green02244bb2011-01-28 09:01:19 +0000197 goto bail1;
Andy Green9659f372011-01-27 22:01:43 +0000198 }
199
200 pkt[13] = '\0';
201 if (strcmp(pkt, "HTTP/1.0 200 ") != 0) {
Andy Green02244bb2011-01-28 09:01:19 +0000202 close(wsi->sock);
Andy Green9659f372011-01-27 22:01:43 +0000203 fprintf(stderr, "ERROR from proxy: %s\n", pkt);
Andy Green02244bb2011-01-28 09:01:19 +0000204 goto bail1;
Andy Green9659f372011-01-27 22:01:43 +0000205 }
206
207 /* we can just start sending to proxy */
208 }
209
Andy Green90c7cbc2011-01-27 06:26:52 +0000210#ifdef LWS_OPENSSL_SUPPORT
211 if (ssl_connection) {
212
213 wsi->ssl = SSL_new(this->ssl_client_ctx);
214 wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
215 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
216
217 if (SSL_connect(wsi->ssl) <= 0) {
218 fprintf(stderr, "SSL connect error %s\n",
219 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Green9659f372011-01-27 22:01:43 +0000220 goto bail1;
Andy Green90c7cbc2011-01-27 06:26:52 +0000221 }
222
223 n = SSL_get_verify_result(wsi->ssl);
224 if (n != X509_V_OK) {
Andy Green9659f372011-01-27 22:01:43 +0000225 if (n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
226 ssl_connection != 2) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000227
Andy Green9659f372011-01-27 22:01:43 +0000228 fprintf(stderr, "server's cert didn't "
229 "look good %d\n", n);
230 goto bail2;
231 }
Andy Green90c7cbc2011-01-27 06:26:52 +0000232 }
Andy Green9659f372011-01-27 22:01:43 +0000233 } else {
Andy Green90c7cbc2011-01-27 06:26:52 +0000234 wsi->ssl = NULL;
Andy Green90c7cbc2011-01-27 06:26:52 +0000235#endif
Andy Green9659f372011-01-27 22:01:43 +0000236
237
238#ifdef LWS_OPENSSL_SUPPORT
239 }
240#endif
241
Andy Green6964bb52011-01-23 16:50:33 +0000242 /*
243 * create the random key
244 */
Andy Green4739e5c2011-01-22 12:51:57 +0000245
Andy Green44eee682011-02-10 09:32:24 +0000246 n = read(this->fd_random, hash, 16);
Andy Green4739e5c2011-01-22 12:51:57 +0000247 if (n != 16) {
248 fprintf(stderr, "Unable to read from random device %s\n",
249 SYSTEM_RANDOM_FILEPATH);
Andy Green4739e5c2011-01-22 12:51:57 +0000250 goto bail2;
251 }
Andy Green4739e5c2011-01-22 12:51:57 +0000252
Andy Green6964bb52011-01-23 16:50:33 +0000253 lws_b64_encode_string(hash, 16, key_b64, sizeof key_b64);
Andy Green4739e5c2011-01-22 12:51:57 +0000254
255 /*
256 * 04 example client handshake
257 *
258 * GET /chat HTTP/1.1
259 * Host: server.example.com
260 * Upgrade: websocket
261 * Connection: Upgrade
262 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
263 * Sec-WebSocket-Origin: http://example.com
264 * Sec-WebSocket-Protocol: chat, superchat
265 * Sec-WebSocket-Version: 4
266 */
267
268 p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", path);
269 p += sprintf(p, "Host: %s\x0d\x0a", host);
270 p += sprintf(p, "Upgrade: websocket\x0d\x0a");
271 p += sprintf(p, "Connection: Upgrade\x0d\x0aSec-WebSocket-Key: ");
272 strcpy(p, key_b64);
273 p += strlen(key_b64);
274 p += sprintf(p, "\x0d\x0aSec-WebSocket-Origin: %s\x0d\x0a", origin);
275 if (protocol != NULL)
276 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", protocol);
Andy Greenbfb051f2011-02-09 08:49:14 +0000277 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a\x0d\x0a",
278 wsi->ietf_spec_revision);
Andy Green4739e5c2011-01-22 12:51:57 +0000279
280
281 /* prepare the expected server accept response */
282
283 strcpy(buf, key_b64);
284 strcpy(&buf[strlen(buf)], magic_websocket_guid);
285
286 SHA1((unsigned char *)buf, strlen(buf), (unsigned char *)hash);
287
288 lws_b64_encode_string(hash, 20, wsi->initial_handshake_hash_base64,
289 sizeof wsi->initial_handshake_hash_base64);
290
291 /* send our request to the server */
292
Andy Green90c7cbc2011-01-27 06:26:52 +0000293#ifdef LWS_OPENSSL_SUPPORT
294 if (ssl_connection)
295 n = SSL_write(wsi->ssl, pkt, p - pkt);
296 else
297#endif
298 n = send(wsi->sock, pkt, p - pkt, 0);
299
300 if (n < 0) {
301 fprintf(stderr, "ERROR writing to client socket\n");
302 goto bail2;
303 }
Andy Green4739e5c2011-01-22 12:51:57 +0000304
305 wsi->parser_state = WSI_TOKEN_NAME_PART;
306
307 pfd.fd = wsi->sock;
308 pfd.events = POLLIN;
309 pfd.revents = 0;
310
311 n = poll(&pfd, 1, 5000);
312 if (n < 0) {
313 fprintf(stderr, "libwebsocket_client_handshake socket error "
314 "while waiting for handshake response");
315 goto bail2;
316 }
317 if (n == 0) {
318 fprintf(stderr, "libwebsocket_client_handshake timeout "
319 "while waiting for handshake response");
320 goto bail2;
321 }
322
323 /* interpret the server response */
324
325 /*
326 * HTTP/1.1 101 Switching Protocols
327 * Upgrade: websocket
328 * Connection: Upgrade
329 * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
330 * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
331 * Sec-WebSocket-Protocol: chat
332 */
333
Andy Green90c7cbc2011-01-27 06:26:52 +0000334#ifdef LWS_OPENSSL_SUPPORT
335 if (ssl_connection)
336 len = SSL_read(wsi->ssl, pkt, sizeof pkt);
337 else
338#endif
339 len = recv(wsi->sock, pkt, sizeof pkt, 0);
340
Andy Green4739e5c2011-01-22 12:51:57 +0000341 if (len < 0) {
342 fprintf(stderr, "libwebsocket_client_handshake read error\n");
343 goto bail2;
344 }
345
346 p = pkt;
347 for (n = 0; n < len; n++)
348 libwebsocket_parse(wsi, *p++);
349
350 if (wsi->parser_state != WSI_PARSING_COMPLETE) {
351 fprintf(stderr, "libwebsocket_client_handshake server response"
352 " failed parsing\n");
353 goto bail2;
354 }
355
356 /*
357 * well, what the server sent looked reasonable for syntax.
358 * Now let's confirm it sent all the necessary headers
359 */
360
361 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
362 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
363 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
364 !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
365 !wsi->utf8_token[WSI_TOKEN_NONCE].token_len ||
366 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
367 protocol != NULL)) {
368 fprintf(stderr, "libwebsocket_client_handshake "
Andy Green927eb7b2011-02-01 08:52:55 +0000369 "missing required header(s)\n");
Andy Green1efb63c2011-02-06 17:42:06 +0000370 pkt[len] = '\0';
Andy Green927eb7b2011-02-01 08:52:55 +0000371 fprintf(stderr, "%s", pkt);
Andy Green4739e5c2011-01-22 12:51:57 +0000372 goto bail2;
373 }
374
375 /*
376 * Everything seems to be there, now take a closer look at what is in
377 * each header
378 */
379
380 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
381 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
382 "101 switching protocols")) {
383 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
384 " HTTP response '%s'\n",
385 wsi->utf8_token[WSI_TOKEN_HTTP].token);
386 goto bail2;
387 }
388
389 strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
390 if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token, "websocket")) {
391 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
392 " Upgrade header '%s'\n",
393 wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
394 goto bail2;
Andy Green6964bb52011-01-23 16:50:33 +0000395 }
Andy Green4739e5c2011-01-22 12:51:57 +0000396
397 strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
398 if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token, "upgrade")) {
399 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
400 " Connection hdr '%s'\n",
401 wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
402 goto bail2;
403 }
404 /*
405 * confirm the protocol the server wants to talk was in the list of
406 * protocols we offered
407 */
408
409 if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
410
411 /* no protocol name to work from, default to first protocol */
Andy Green90c7cbc2011-01-27 06:26:52 +0000412 wsi->protocol = &this->protocols[0];
Andy Green4739e5c2011-01-22 12:51:57 +0000413
414 goto check_accept;
415 }
416
417 pc = protocol;
418 while (*pc && !okay) {
419 if ((!strncmp(pc, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
420 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) &&
421 (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' ||
422 pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) {
423 okay = 1;
424 continue;
425 }
426 while (*pc && *pc != ',')
427 pc++;
428 while (*pc && *pc != ' ')
429 pc++;
430 }
431 if (!okay) {
432 fprintf(stderr, "libwebsocket_client_handshake server "
433 "sent bad protocol '%s'\n",
434 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
435 goto bail2;
436 }
437
438 /*
439 * identify the selected protocol struct and set it
440 */
441 n = 0;
442 wsi->protocol = NULL;
Andy Green90c7cbc2011-01-27 06:26:52 +0000443 while (this->protocols[n].callback) {
Andy Green4739e5c2011-01-22 12:51:57 +0000444 if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
Andy Green90c7cbc2011-01-27 06:26:52 +0000445 this->protocols[n].name) == 0)
446 wsi->protocol = &this->protocols[n];
Andy Green4739e5c2011-01-22 12:51:57 +0000447 n++;
448 }
449
450 if (wsi->protocol == NULL) {
451 fprintf(stderr, "libwebsocket_client_handshake server "
452 "requested protocol '%s', which we "
453 "said we supported but we don't!\n",
454 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
455 goto bail2;
456 }
457
458check_accept:
459 /*
460 * Confirm his accept token is the same as the one we precomputed
461 */
462
463 if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
464 wsi->initial_handshake_hash_base64)) {
465 fprintf(stderr, "libwebsocket_client_handshake server sent "
466 "bad ACCEPT '%s' vs computed '%s'\n",
467 wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
468 wsi->initial_handshake_hash_base64);
469 goto bail2;
470 }
471
472 /*
473 * Calculate the masking key to use when sending data to server
474 */
475
476 strcpy(buf, key_b64);
477 p = buf + strlen(key_b64);
478 strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
479 p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
480 strcpy(p, magic_websocket_04_masking_guid);
481 SHA1((unsigned char *)buf, strlen(buf), wsi->masking_key_04);
482
Andy Green864d9022011-01-30 11:43:51 +0000483 /* allocate the per-connection user memory (if any) */
484
485 if (wsi->protocol->per_session_data_size) {
486 wsi->user_space = malloc(
487 wsi->protocol->per_session_data_size);
488 if (wsi->user_space == NULL) {
489 fprintf(stderr, "Out of memory for "
490 "conn user space\n");
491 goto bail2;
492 }
493 } else
494 wsi->user_space = NULL;
495
Andy Green4739e5c2011-01-22 12:51:57 +0000496 /* okay he is good to go */
497
Andy Green90c7cbc2011-01-27 06:26:52 +0000498 this->fds[this->fds_count].fd = wsi->sock;
499 this->fds[this->fds_count].revents = 0;
500 this->fds[this->fds_count++].events = POLLIN;
Andy Green4739e5c2011-01-22 12:51:57 +0000501
Andy Green3221f922011-02-12 13:14:11 +0000502 /* external POLL support via protocol 0 */
Andy Green62c54d22011-02-14 09:14:25 +0000503 this->protocols[0].callback(this, wsi,
Andy Green3221f922011-02-12 13:14:11 +0000504 LWS_CALLBACK_ADD_POLL_FD,
505 (void *)(long)wsi->sock, NULL, POLLIN);
506
507
Andy Green4739e5c2011-01-22 12:51:57 +0000508 wsi->state = WSI_STATE_ESTABLISHED;
Andy Greenf3d3b402011-02-09 07:16:34 +0000509 wsi->mode = LWS_CONNMODE_WS_CLIENT;
Andy Green4739e5c2011-01-22 12:51:57 +0000510
511 fprintf(stderr, "handshake OK for protocol %s\n", wsi->protocol->name);
512
Andy Green90c7cbc2011-01-27 06:26:52 +0000513 /* call him back to inform him he is up */
514
Andy Green62c54d22011-02-14 09:14:25 +0000515 wsi->protocol->callback(this, wsi,
Andy Green90c7cbc2011-01-27 06:26:52 +0000516 LWS_CALLBACK_CLIENT_ESTABLISHED,
517 wsi->user_space,
518 NULL, 0);
Andy Green4739e5c2011-01-22 12:51:57 +0000519 return wsi;
520
521
522bail2:
Andy Green4b6fbe12011-02-14 08:03:48 +0000523 libwebsocket_close_and_free_session(this, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000524bail1:
525 free(wsi);
526
527 return NULL;
528}