blob: c6f8ba3ef21cfb80b6a9c88a279f00f625cf9cb0 [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 Greena71eafc2011-02-14 17:59:43 +000095 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green4739e5c2011-01-22 12:51:57 +000096
Andy Greenbfb051f2011-02-09 08:49:14 +000097 /* set up appropriate masking */
98
99 wsi->xor_mask = xor_no_mask;
100
101 switch (wsi->ietf_spec_revision) {
102 case 4:
103 wsi->xor_mask = xor_mask_04;
104 break;
105 case 5:
106 wsi->xor_mask = xor_mask_05;
107 break;
108 default:
109 fprintf(stderr,
110 "Client ietf version %d not supported\n",
111 wsi->ietf_spec_revision);
112 return NULL;
113 }
114
115 /* force no mask if he asks for that though */
116
117 if (this->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
118 wsi->xor_mask = xor_no_mask;
119
Andy Green4739e5c2011-01-22 12:51:57 +0000120 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
121 wsi->utf8_token[n].token = NULL;
122 wsi->utf8_token[n].token_len = 0;
123 }
124
125 /*
Andy Green9659f372011-01-27 22:01:43 +0000126 * proxy?
127 */
128
129 if (this->http_proxy_port) {
130 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
131 "User-agent: libwebsockets\x0d\x0a"
132/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
133 "\x0d\x0a", address, port);
134
135 /* OK from now on we talk via the proxy */
136
137 address = this->http_proxy_address;
138 port = this->http_proxy_port;
139 }
140
141 /*
142 * prepare the actual connection (to the proxy, if any)
Andy Green4739e5c2011-01-22 12:51:57 +0000143 */
144
145 server_hostent = gethostbyname(address);
146 if (server_hostent == NULL) {
147 fprintf(stderr, "Unable to get host name from %s\n", address);
148 goto bail1;
149 }
150
151 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
Andy Green6964bb52011-01-23 16:50:33 +0000152
Andy Green4739e5c2011-01-22 12:51:57 +0000153 if (wsi->sock < 0) {
154 fprintf(stderr, "Unable to open socket\n");
155 goto bail1;
156 }
157
Andy Green0d338332011-02-12 11:57:43 +0000158 insert_wsi(this, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000159
160 server_addr.sin_family = AF_INET;
161 server_addr.sin_port = htons(port);
162 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
163 bzero(&server_addr.sin_zero, 8);
164
165 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
166 sizeof(struct sockaddr)) == -1) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000167 fprintf(stderr, "Connect failed\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000168 goto bail1;
Andy Green6964bb52011-01-23 16:50:33 +0000169 }
Andy Green4739e5c2011-01-22 12:51:57 +0000170
Andy Green9659f372011-01-27 22:01:43 +0000171 /* we are connected to server, or proxy */
172
Andy Green9659f372011-01-27 22:01:43 +0000173 if (this->http_proxy_port) {
174
175 n = send(wsi->sock, pkt, plen, 0);
176 if (n < 0) {
Andy Green5b9a4c02011-01-28 09:39:29 +0000177 close(wsi->sock);
178 fprintf(stderr, "ERROR writing to proxy socket\n");
179 goto bail1;
180 }
181
182 pfd.fd = wsi->sock;
183 pfd.events = POLLIN;
184 pfd.revents = 0;
185
186 n = poll(&pfd, 1, 5000);
187 if (n <= 0) {
188 close(wsi->sock);
189 fprintf(stderr, "libwebsocket_client_handshake "
190 "timeout on proxy response");
Andy Green02244bb2011-01-28 09:01:19 +0000191 goto bail1;
Andy Green9659f372011-01-27 22:01:43 +0000192 }
193
194 n = recv(wsi->sock, pkt, sizeof pkt, 0);
195 if (n < 0) {
Andy Green02244bb2011-01-28 09:01:19 +0000196 close(wsi->sock);
Andy Green5b9a4c02011-01-28 09:39:29 +0000197 fprintf(stderr, "ERROR reading from proxy socket\n");
Andy Green02244bb2011-01-28 09:01:19 +0000198 goto bail1;
Andy Green9659f372011-01-27 22:01:43 +0000199 }
200
201 pkt[13] = '\0';
202 if (strcmp(pkt, "HTTP/1.0 200 ") != 0) {
Andy Green02244bb2011-01-28 09:01:19 +0000203 close(wsi->sock);
Andy Green9659f372011-01-27 22:01:43 +0000204 fprintf(stderr, "ERROR from proxy: %s\n", pkt);
Andy Green02244bb2011-01-28 09:01:19 +0000205 goto bail1;
Andy Green9659f372011-01-27 22:01:43 +0000206 }
207
208 /* we can just start sending to proxy */
209 }
210
Andy Green90c7cbc2011-01-27 06:26:52 +0000211#ifdef LWS_OPENSSL_SUPPORT
212 if (ssl_connection) {
213
214 wsi->ssl = SSL_new(this->ssl_client_ctx);
215 wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
216 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
217
218 if (SSL_connect(wsi->ssl) <= 0) {
219 fprintf(stderr, "SSL connect error %s\n",
220 ERR_error_string(ERR_get_error(), ssl_err_buf));
Andy Green9659f372011-01-27 22:01:43 +0000221 goto bail1;
Andy Green90c7cbc2011-01-27 06:26:52 +0000222 }
223
224 n = SSL_get_verify_result(wsi->ssl);
225 if (n != X509_V_OK) {
Andy Green9659f372011-01-27 22:01:43 +0000226 if (n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
227 ssl_connection != 2) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000228
Andy Green9659f372011-01-27 22:01:43 +0000229 fprintf(stderr, "server's cert didn't "
230 "look good %d\n", n);
231 goto bail2;
232 }
Andy Green90c7cbc2011-01-27 06:26:52 +0000233 }
Andy Green9659f372011-01-27 22:01:43 +0000234 } else {
Andy Green90c7cbc2011-01-27 06:26:52 +0000235 wsi->ssl = NULL;
Andy Green90c7cbc2011-01-27 06:26:52 +0000236#endif
Andy Green9659f372011-01-27 22:01:43 +0000237
238
239#ifdef LWS_OPENSSL_SUPPORT
240 }
241#endif
242
Andy Green6964bb52011-01-23 16:50:33 +0000243 /*
244 * create the random key
245 */
Andy Green4739e5c2011-01-22 12:51:57 +0000246
Andy Green44eee682011-02-10 09:32:24 +0000247 n = read(this->fd_random, hash, 16);
Andy Green4739e5c2011-01-22 12:51:57 +0000248 if (n != 16) {
249 fprintf(stderr, "Unable to read from random device %s\n",
250 SYSTEM_RANDOM_FILEPATH);
Andy Green4739e5c2011-01-22 12:51:57 +0000251 goto bail2;
252 }
Andy Green4739e5c2011-01-22 12:51:57 +0000253
Andy Green6964bb52011-01-23 16:50:33 +0000254 lws_b64_encode_string(hash, 16, key_b64, sizeof key_b64);
Andy Green4739e5c2011-01-22 12:51:57 +0000255
256 /*
257 * 04 example client handshake
258 *
259 * GET /chat HTTP/1.1
260 * Host: server.example.com
261 * Upgrade: websocket
262 * Connection: Upgrade
263 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
264 * Sec-WebSocket-Origin: http://example.com
265 * Sec-WebSocket-Protocol: chat, superchat
266 * Sec-WebSocket-Version: 4
267 */
268
269 p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", path);
270 p += sprintf(p, "Host: %s\x0d\x0a", host);
271 p += sprintf(p, "Upgrade: websocket\x0d\x0a");
272 p += sprintf(p, "Connection: Upgrade\x0d\x0aSec-WebSocket-Key: ");
273 strcpy(p, key_b64);
274 p += strlen(key_b64);
275 p += sprintf(p, "\x0d\x0aSec-WebSocket-Origin: %s\x0d\x0a", origin);
276 if (protocol != NULL)
277 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", protocol);
Andy Greenbfb051f2011-02-09 08:49:14 +0000278 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a\x0d\x0a",
279 wsi->ietf_spec_revision);
Andy Green4739e5c2011-01-22 12:51:57 +0000280
281
282 /* prepare the expected server accept response */
283
284 strcpy(buf, key_b64);
285 strcpy(&buf[strlen(buf)], magic_websocket_guid);
286
287 SHA1((unsigned char *)buf, strlen(buf), (unsigned char *)hash);
288
289 lws_b64_encode_string(hash, 20, wsi->initial_handshake_hash_base64,
290 sizeof wsi->initial_handshake_hash_base64);
291
292 /* send our request to the server */
293
Andy Green90c7cbc2011-01-27 06:26:52 +0000294#ifdef LWS_OPENSSL_SUPPORT
295 if (ssl_connection)
296 n = SSL_write(wsi->ssl, pkt, p - pkt);
297 else
298#endif
299 n = send(wsi->sock, pkt, p - pkt, 0);
300
301 if (n < 0) {
302 fprintf(stderr, "ERROR writing to client socket\n");
303 goto bail2;
304 }
Andy Green4739e5c2011-01-22 12:51:57 +0000305
306 wsi->parser_state = WSI_TOKEN_NAME_PART;
307
308 pfd.fd = wsi->sock;
309 pfd.events = POLLIN;
310 pfd.revents = 0;
311
312 n = poll(&pfd, 1, 5000);
313 if (n < 0) {
314 fprintf(stderr, "libwebsocket_client_handshake socket error "
315 "while waiting for handshake response");
316 goto bail2;
317 }
318 if (n == 0) {
319 fprintf(stderr, "libwebsocket_client_handshake timeout "
320 "while waiting for handshake response");
321 goto bail2;
322 }
323
324 /* interpret the server response */
325
326 /*
327 * HTTP/1.1 101 Switching Protocols
328 * Upgrade: websocket
329 * Connection: Upgrade
330 * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
331 * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
332 * Sec-WebSocket-Protocol: chat
333 */
334
Andy Green90c7cbc2011-01-27 06:26:52 +0000335#ifdef LWS_OPENSSL_SUPPORT
336 if (ssl_connection)
337 len = SSL_read(wsi->ssl, pkt, sizeof pkt);
338 else
339#endif
340 len = recv(wsi->sock, pkt, sizeof pkt, 0);
341
Andy Green4739e5c2011-01-22 12:51:57 +0000342 if (len < 0) {
343 fprintf(stderr, "libwebsocket_client_handshake read error\n");
344 goto bail2;
345 }
346
347 p = pkt;
348 for (n = 0; n < len; n++)
349 libwebsocket_parse(wsi, *p++);
350
351 if (wsi->parser_state != WSI_PARSING_COMPLETE) {
352 fprintf(stderr, "libwebsocket_client_handshake server response"
353 " failed parsing\n");
354 goto bail2;
355 }
356
357 /*
358 * well, what the server sent looked reasonable for syntax.
359 * Now let's confirm it sent all the necessary headers
360 */
361
362 if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
363 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
364 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
365 !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
366 !wsi->utf8_token[WSI_TOKEN_NONCE].token_len ||
367 (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
368 protocol != NULL)) {
369 fprintf(stderr, "libwebsocket_client_handshake "
Andy Green927eb7b2011-02-01 08:52:55 +0000370 "missing required header(s)\n");
Andy Green1efb63c2011-02-06 17:42:06 +0000371 pkt[len] = '\0';
Andy Green927eb7b2011-02-01 08:52:55 +0000372 fprintf(stderr, "%s", pkt);
Andy Green4739e5c2011-01-22 12:51:57 +0000373 goto bail2;
374 }
375
376 /*
377 * Everything seems to be there, now take a closer look at what is in
378 * each header
379 */
380
381 strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
382 if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
383 "101 switching protocols")) {
384 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
385 " HTTP response '%s'\n",
386 wsi->utf8_token[WSI_TOKEN_HTTP].token);
387 goto bail2;
388 }
389
390 strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
391 if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token, "websocket")) {
392 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
393 " Upgrade header '%s'\n",
394 wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
395 goto bail2;
Andy Green6964bb52011-01-23 16:50:33 +0000396 }
Andy Green4739e5c2011-01-22 12:51:57 +0000397
398 strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
399 if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token, "upgrade")) {
400 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
401 " Connection hdr '%s'\n",
402 wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
403 goto bail2;
404 }
405 /*
406 * confirm the protocol the server wants to talk was in the list of
407 * protocols we offered
408 */
409
410 if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
411
412 /* no protocol name to work from, default to first protocol */
Andy Green90c7cbc2011-01-27 06:26:52 +0000413 wsi->protocol = &this->protocols[0];
Andy Green4739e5c2011-01-22 12:51:57 +0000414
415 goto check_accept;
416 }
417
418 pc = protocol;
419 while (*pc && !okay) {
420 if ((!strncmp(pc, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
421 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) &&
422 (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' ||
423 pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) {
424 okay = 1;
425 continue;
426 }
427 while (*pc && *pc != ',')
428 pc++;
429 while (*pc && *pc != ' ')
430 pc++;
431 }
432 if (!okay) {
433 fprintf(stderr, "libwebsocket_client_handshake server "
434 "sent bad protocol '%s'\n",
435 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
436 goto bail2;
437 }
438
439 /*
440 * identify the selected protocol struct and set it
441 */
442 n = 0;
443 wsi->protocol = NULL;
Andy Green90c7cbc2011-01-27 06:26:52 +0000444 while (this->protocols[n].callback) {
Andy Green4739e5c2011-01-22 12:51:57 +0000445 if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
Andy Green90c7cbc2011-01-27 06:26:52 +0000446 this->protocols[n].name) == 0)
447 wsi->protocol = &this->protocols[n];
Andy Green4739e5c2011-01-22 12:51:57 +0000448 n++;
449 }
450
451 if (wsi->protocol == NULL) {
452 fprintf(stderr, "libwebsocket_client_handshake server "
453 "requested protocol '%s', which we "
454 "said we supported but we don't!\n",
455 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
456 goto bail2;
457 }
458
459check_accept:
460 /*
461 * Confirm his accept token is the same as the one we precomputed
462 */
463
464 if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
465 wsi->initial_handshake_hash_base64)) {
466 fprintf(stderr, "libwebsocket_client_handshake server sent "
467 "bad ACCEPT '%s' vs computed '%s'\n",
468 wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
469 wsi->initial_handshake_hash_base64);
470 goto bail2;
471 }
472
473 /*
474 * Calculate the masking key to use when sending data to server
475 */
476
477 strcpy(buf, key_b64);
478 p = buf + strlen(key_b64);
479 strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
480 p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
481 strcpy(p, magic_websocket_04_masking_guid);
482 SHA1((unsigned char *)buf, strlen(buf), wsi->masking_key_04);
483
Andy Green864d9022011-01-30 11:43:51 +0000484 /* allocate the per-connection user memory (if any) */
485
486 if (wsi->protocol->per_session_data_size) {
487 wsi->user_space = malloc(
488 wsi->protocol->per_session_data_size);
489 if (wsi->user_space == NULL) {
490 fprintf(stderr, "Out of memory for "
491 "conn user space\n");
492 goto bail2;
493 }
494 } else
495 wsi->user_space = NULL;
496
Andy Green4739e5c2011-01-22 12:51:57 +0000497 /* okay he is good to go */
498
Andy Green90c7cbc2011-01-27 06:26:52 +0000499 this->fds[this->fds_count].fd = wsi->sock;
500 this->fds[this->fds_count].revents = 0;
501 this->fds[this->fds_count++].events = POLLIN;
Andy Green4739e5c2011-01-22 12:51:57 +0000502
Andy Green3221f922011-02-12 13:14:11 +0000503 /* external POLL support via protocol 0 */
Andy Green62c54d22011-02-14 09:14:25 +0000504 this->protocols[0].callback(this, wsi,
Andy Green3221f922011-02-12 13:14:11 +0000505 LWS_CALLBACK_ADD_POLL_FD,
506 (void *)(long)wsi->sock, NULL, POLLIN);
507
508
Andy Green4739e5c2011-01-22 12:51:57 +0000509 wsi->state = WSI_STATE_ESTABLISHED;
Andy Greenf3d3b402011-02-09 07:16:34 +0000510 wsi->mode = LWS_CONNMODE_WS_CLIENT;
Andy Green4739e5c2011-01-22 12:51:57 +0000511
512 fprintf(stderr, "handshake OK for protocol %s\n", wsi->protocol->name);
513
Andy Green90c7cbc2011-01-27 06:26:52 +0000514 /* call him back to inform him he is up */
515
Andy Green62c54d22011-02-14 09:14:25 +0000516 wsi->protocol->callback(this, wsi,
Andy Green90c7cbc2011-01-27 06:26:52 +0000517 LWS_CALLBACK_CLIENT_ESTABLISHED,
518 wsi->user_space,
519 NULL, 0);
Andy Green4739e5c2011-01-22 12:51:57 +0000520 return wsi;
521
522
523bail2:
Andy Green4b6fbe12011-02-14 08:03:48 +0000524 libwebsocket_close_and_free_session(this, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000525bail1:
526 free(wsi);
527
528 return NULL;
529}