blob: c81f6413c95807fa9587c588bd10ef67b76cc714 [file] [log] [blame]
Andy Green76f61e72013-01-16 11:53:05 +08001/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010-2013 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#ifdef WIN32
25#include <tchar.h>
26#include <io.h>
27#else
28#ifdef LWS_BUILTIN_GETIFADDRS
29#include <getifaddrs.h>
30#else
31#include <ifaddrs.h>
32#endif
33#include <sys/un.h>
34#include <sys/socket.h>
35#include <netdb.h>
36#endif
37
Andy Greenb5b23192013-02-11 17:13:32 +080038int lws_client_socket_service(struct libwebsocket_context *context,
39 struct libwebsocket *wsi, struct pollfd *pollfd)
Andy Green76f61e72013-01-16 11:53:05 +080040{
41 int n;
Andy Greenc97067c2013-02-10 11:03:32 +080042 char *p = (char *)&context->service_buffer[0];
Andy Green76f61e72013-01-16 11:53:05 +080043 int len;
44 char c;
Andy Green76f61e72013-01-16 11:53:05 +080045
46 switch (wsi->mode) {
47
Andy Green5dc62ea2013-09-20 20:26:12 +080048 case LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT:
49
50 /*
51 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
52 * timeout protection set in client-handshake.c
53 */
54
55 if (__libwebsocket_client_connect_2(context, wsi) == NULL) {
56 /* closed */
57 lwsl_client("closed\n");
58 return -1;
59 }
60
61 /* either still pending connection, or changed mode */
62 return 0;
63
Andy Green76f61e72013-01-16 11:53:05 +080064 case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
65
66 /* handle proxy hung up on us */
67
68 if (pollfd->revents & (POLLERR | POLLHUP)) {
69
70 lwsl_warn("Proxy connection %p (fd=%d) dead\n",
71 (void *)wsi, pollfd->fd);
72
73 libwebsocket_close_and_free_session(context, wsi,
74 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green040d2ef2013-01-16 13:40:43 +080075 return 0;
Andy Green76f61e72013-01-16 11:53:05 +080076 }
77
Andy Greenc97067c2013-02-10 11:03:32 +080078 n = recv(wsi->sock, context->service_buffer,
Andy Greenb5b23192013-02-11 17:13:32 +080079 sizeof(context->service_buffer), 0);
Andy Green76f61e72013-01-16 11:53:05 +080080 if (n < 0) {
81 libwebsocket_close_and_free_session(context, wsi,
82 LWS_CLOSE_STATUS_NOSTATUS);
83 lwsl_err("ERROR reading from proxy socket\n");
Andy Green040d2ef2013-01-16 13:40:43 +080084 return 0;
Andy Green76f61e72013-01-16 11:53:05 +080085 }
86
Andy Greenc97067c2013-02-10 11:03:32 +080087 context->service_buffer[13] = '\0';
88 if (strcmp((char *)context->service_buffer, "HTTP/1.0 200 ")) {
Andy Green76f61e72013-01-16 11:53:05 +080089 libwebsocket_close_and_free_session(context, wsi,
90 LWS_CLOSE_STATUS_NOSTATUS);
Andy Greenb5b23192013-02-11 17:13:32 +080091 lwsl_err("ERROR proxy: %s\n", context->service_buffer);
Andy Green040d2ef2013-01-16 13:40:43 +080092 return 0;
Andy Green76f61e72013-01-16 11:53:05 +080093 }
94
95 /* clear his proxy connection timeout */
96
97 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
98
99 /* fallthru */
100
101 case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
102
103 /*
104 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
105 * timeout protection set in client-handshake.c
106 */
107
108 #ifdef LWS_OPENSSL_SUPPORT
109
110 /*
111 * take care of our libwebsocket_callback_on_writable
112 * happening at a time when there's no real connection yet
113 */
114
115 pollfd->events &= ~POLLOUT;
116
117 /* external POLL support via protocol 0 */
118 context->protocols[0].callback(context, wsi,
119 LWS_CALLBACK_CLEAR_MODE_POLL_FD,
Andy Green0c2f4d82013-02-19 19:19:51 +0800120 wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
Andy Green76f61e72013-01-16 11:53:05 +0800121
Andy Greenb5b23192013-02-11 17:13:32 +0800122 /* we can retry this... just cook the SSL BIO the first time */
Andy Green76f61e72013-01-16 11:53:05 +0800123
124 if (wsi->use_ssl && !wsi->ssl) {
125
126 wsi->ssl = SSL_new(context->ssl_client_ctx);
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900127
Andy Greenb5b23192013-02-11 17:13:32 +0800128#ifdef USE_CYASSL
129 /*
130 * CyaSSL does certificate verification differently
131 * from OpenSSL.
132 * If we should ignore the certificate, we need to set
133 * this before SSL_new and SSL_connect is called.
134 * Otherwise the connect will simply fail with error
135 * code -155
136 */
137 if (wsi->use_ssl == 2)
138 CyaSSL_set_verify(wsi->ssl,
139 SSL_VERIFY_NONE, NULL);
140#endif /* USE_CYASSL */
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900141
Andy Greenb5b23192013-02-11 17:13:32 +0800142 wsi->client_bio =
143 BIO_new_socket(wsi->sock, BIO_NOCLOSE);
Andy Green76f61e72013-01-16 11:53:05 +0800144 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
145
Andy Greenb5b23192013-02-11 17:13:32 +0800146#ifdef USE_CYASSL
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900147 CyaSSL_set_using_nonblock(wsi->ssl, 1);
Andy Greenb5b23192013-02-11 17:13:32 +0800148#else
Andy Greenc4d05a52013-01-28 17:48:21 +0800149 BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
Andy Greenb5b23192013-02-11 17:13:32 +0800150#endif
Andy Greenc4d05a52013-01-28 17:48:21 +0800151
Andy Green76f61e72013-01-16 11:53:05 +0800152 SSL_set_ex_data(wsi->ssl,
153 openssl_websocket_private_data_index,
154 context);
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900155 }
Andy Green76f61e72013-01-16 11:53:05 +0800156
157 if (wsi->use_ssl) {
Andy Greene000a702013-01-29 12:37:35 +0800158 lws_latency_pre(context, wsi);
Andy Green76f61e72013-01-16 11:53:05 +0800159 n = SSL_connect(wsi->ssl);
Andy Greenb5b23192013-02-11 17:13:32 +0800160 lws_latency(context, wsi,
161 "SSL_connect LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE",
162 n, n > 0);
Andy Green76f61e72013-01-16 11:53:05 +0800163
164 if (n < 0) {
165 n = SSL_get_error(wsi->ssl, n);
166
167 if (n == SSL_ERROR_WANT_READ ||
168 n == SSL_ERROR_WANT_WRITE) {
169 /*
Andy Greenb5b23192013-02-11 17:13:32 +0800170 * wants us to retry connect due to
171 * state of the underlying ssl layer...
172 * but since it may be stalled on
173 * blocked write, no incoming data may
174 * arrive to trigger the retry.
175 * Force (possibly many times if the SSL
176 * state persists in returning the
177 * condition code, but other sockets
178 * are getting serviced inbetweentimes)
179 * us to get called back when writable.
Andy Green76f61e72013-01-16 11:53:05 +0800180 */
181
Andy Greenb5b23192013-02-11 17:13:32 +0800182 lwsl_info(
183 "SSL_connect WANT_... retrying\n");
184 libwebsocket_callback_on_writable(
185 context, wsi);
shys24f4eb62013-10-24 22:27:08 +0800186
187 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SSL;
188
Andy Green76f61e72013-01-16 11:53:05 +0800189 return 0; /* no error */
190 }
191 n = -1;
192 }
193
194 if (n <= 0) {
195 /*
196 * retry if new data comes until we
197 * run into the connection timeout or win
198 */
199
Joakim Soderbergb82b0dd2013-02-22 09:28:15 +0800200 lwsl_err("SSL connect error %lu: %s\n",
201 ERR_get_error(),
Andy Green76f61e72013-01-16 11:53:05 +0800202 ERR_error_string(ERR_get_error(),
Andy Greenb5b23192013-02-11 17:13:32 +0800203 (char *)context->service_buffer));
Andy Green76f61e72013-01-16 11:53:05 +0800204 return 0;
205 }
shys24f4eb62013-10-24 22:27:08 +0800206 } else
207 wsi->ssl = NULL;
Andy Green76f61e72013-01-16 11:53:05 +0800208
shys24f4eb62013-10-24 22:27:08 +0800209 case LWS_CONNMODE_WS_CLIENT_WAITING_SSL:
210
211 if (wsi->use_ssl) {
212
213 if (wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SSL) {
214 lws_latency_pre(context, wsi);
215 n = SSL_connect(wsi->ssl);
216 lws_latency(context, wsi,
217 "SSL_connect LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE",
218 n, n > 0);
219
220 if (n < 0) {
221 n = SSL_get_error(wsi->ssl, n);
222
223 if (n == SSL_ERROR_WANT_READ ||
224 n == SSL_ERROR_WANT_WRITE) {
225 /*
226 * wants us to retry connect due to
227 * state of the underlying ssl layer...
228 * but since it may be stalled on
229 * blocked write, no incoming data may
230 * arrive to trigger the retry.
231 * Force (possibly many times if the SSL
232 * state persists in returning the
233 * condition code, but other sockets
234 * are getting serviced inbetweentimes)
235 * us to get called back when writable.
236 */
237
238 lwsl_info(
239 "SSL_connect WANT_... retrying\n");
240 libwebsocket_callback_on_writable(
241 context, wsi);
242
243 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SSL;
244
245 return 0; /* no error */
246 }
247 n = -1;
248 }
249
250 if (n <= 0) {
251 /*
252 * retry if new data comes until we
253 * run into the connection timeout or win
254 */
255
256 lwsl_err("SSL connect error %lu: %s\n",
257 ERR_get_error(),
258 ERR_error_string(ERR_get_error(),
259 (char *)context->service_buffer));
260 return 0;
261 }
262 }
263
Joakim Soderbergb378ce92013-02-06 15:29:18 +0900264 #ifndef USE_CYASSL
Andy Greenb5b23192013-02-11 17:13:32 +0800265 /*
266 * See comment above about CyaSSL certificate
267 * verification
268 */
Andy Greene000a702013-01-29 12:37:35 +0800269 lws_latency_pre(context, wsi);
Andy Green76f61e72013-01-16 11:53:05 +0800270 n = SSL_get_verify_result(wsi->ssl);
Andy Greenb5b23192013-02-11 17:13:32 +0800271 lws_latency(context, wsi,
272 "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
273 n, n > 0);
Andy Green76f61e72013-01-16 11:53:05 +0800274 if ((n != X509_V_OK) && (
275 n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
276 wsi->use_ssl != 2)) {
277
Andy Greenb5b23192013-02-11 17:13:32 +0800278 lwsl_err(
279 "server's cert didn't look good %d\n", n);
Andy Green76f61e72013-01-16 11:53:05 +0800280 libwebsocket_close_and_free_session(context,
281 wsi, LWS_CLOSE_STATUS_NOSTATUS);
Andy Green040d2ef2013-01-16 13:40:43 +0800282 return 0;
Andy Green76f61e72013-01-16 11:53:05 +0800283 }
Andy Greenb5b23192013-02-11 17:13:32 +0800284#endif /* USE_CYASSL */
Andy Green76f61e72013-01-16 11:53:05 +0800285 } else
286 wsi->ssl = NULL;
Andy Greenb5b23192013-02-11 17:13:32 +0800287#endif
Andy Green76f61e72013-01-16 11:53:05 +0800288
289 p = libwebsockets_generate_client_handshake(context, wsi, p);
Andy Green040d2ef2013-01-16 13:40:43 +0800290 if (p == NULL) {
Andy Greenb5b23192013-02-11 17:13:32 +0800291 lwsl_err("Failed to generate handshake for client\n");
Andy Green040d2ef2013-01-16 13:40:43 +0800292 libwebsocket_close_and_free_session(context, wsi,
293 LWS_CLOSE_STATUS_NOSTATUS);
294 return 0;
295 }
Andy Green76f61e72013-01-16 11:53:05 +0800296
297 /* send our request to the server */
298
Andy Greene000a702013-01-29 12:37:35 +0800299 lws_latency_pre(context, wsi);
Andy Greenb5b23192013-02-11 17:13:32 +0800300#ifdef LWS_OPENSSL_SUPPORT
Andy Green76f61e72013-01-16 11:53:05 +0800301 if (wsi->use_ssl)
Andy Greenb5b23192013-02-11 17:13:32 +0800302 n = SSL_write(wsi->ssl, context->service_buffer,
303 p - (char *)context->service_buffer);
Andy Green76f61e72013-01-16 11:53:05 +0800304 else
Andy Greenb5b23192013-02-11 17:13:32 +0800305#endif
306 n = send(wsi->sock, context->service_buffer,
Joachim Bauch8294c1f2013-06-29 10:22:09 +0800307 p - (char *)context->service_buffer, MSG_NOSIGNAL);
Andy Greenb5b23192013-02-11 17:13:32 +0800308 lws_latency(context, wsi,
309 "send or SSL_write LWS_CONNMODE...HANDSHAKE",
310 n, n >= 0);
Andy Green76f61e72013-01-16 11:53:05 +0800311
312 if (n < 0) {
313 lwsl_debug("ERROR writing to client socket\n");
314 libwebsocket_close_and_free_session(context, wsi,
315 LWS_CLOSE_STATUS_NOSTATUS);
Andy Green040d2ef2013-01-16 13:40:43 +0800316 return 0;
Andy Green76f61e72013-01-16 11:53:05 +0800317 }
318
Andy Green623a98d2013-01-21 11:04:23 +0800319 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
320 wsi->u.hdr.lextable_pos = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800321 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
322 libwebsocket_set_timeout(wsi,
Andy Greenb5b23192013-02-11 17:13:32 +0800323 PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
324 AWAITING_TIMEOUT);
Andy Green76f61e72013-01-16 11:53:05 +0800325 break;
326
327 case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
328
329 /* handle server hung up on us */
330
331 if (pollfd->revents & (POLLERR | POLLHUP)) {
332
333 lwsl_debug("Server connection %p (fd=%d) dead\n",
334 (void *)wsi, pollfd->fd);
335
336 goto bail3;
337 }
338
Andy Green5a4f3ae2013-03-09 09:09:46 +0800339 if (!(pollfd->revents & POLLIN))
340 break;
Andy Green76f61e72013-01-16 11:53:05 +0800341
342 /* interpret the server response */
343
344 /*
345 * HTTP/1.1 101 Switching Protocols
346 * Upgrade: websocket
347 * Connection: Upgrade
348 * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
349 * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
350 * Sec-WebSocket-Protocol: chat
351 */
352
353 /*
354 * we have to take some care here to only take from the
355 * socket bytewise. The browser may (and has been seen to
356 * in the case that onopen() performs websocket traffic)
357 * coalesce both handshake response and websocket traffic
358 * in one packet, since at that point the connection is
359 * definitively ready from browser pov.
360 */
361
362 len = 1;
Andy Greenb5b23192013-02-11 17:13:32 +0800363 while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE &&
364 len > 0) {
Andy Green76f61e72013-01-16 11:53:05 +0800365#ifdef LWS_OPENSSL_SUPPORT
Andy Green96d882a2013-01-30 12:27:27 +0800366 if (wsi->use_ssl) {
Andy Green76f61e72013-01-16 11:53:05 +0800367 len = SSL_read(wsi->ssl, &c, 1);
Andy Green96d882a2013-01-30 12:27:27 +0800368 if (len < 0) {
369 n = SSL_get_error(wsi->ssl, len);
370 if (n == SSL_ERROR_WANT_READ ||
Andy Greenb5b23192013-02-11 17:13:32 +0800371 n == SSL_ERROR_WANT_WRITE)
Andy Green96d882a2013-01-30 12:27:27 +0800372 return 0;
373 }
374 } else
Andy Green76f61e72013-01-16 11:53:05 +0800375#endif
376 len = recv(wsi->sock, &c, 1, 0);
377
Andy Green090789e2013-02-11 20:03:59 +0800378 if (len < 0) {
379 lwsl_warn("error on parsing recv\n");
Andy Green96d882a2013-01-30 12:27:27 +0800380 goto bail3;
Andy Green090789e2013-02-11 20:03:59 +0800381 }
Andy Green96d882a2013-01-30 12:27:27 +0800382
Andy Green3455e672013-02-04 08:55:42 +0800383 if (libwebsocket_parse(wsi, c)) {
Andy Green090789e2013-02-11 20:03:59 +0800384 lwsl_warn("problems parsing header\n");
Andy Green3455e672013-02-04 08:55:42 +0800385 goto bail3;
386 }
Andy Green76f61e72013-01-16 11:53:05 +0800387 }
388
389 /*
390 * hs may also be coming in multiple packets, there is a 5-sec
391 * libwebsocket timeout still active here too, so if parsing did
392 * not complete just wait for next packet coming in this state
393 */
394
Andy Green623a98d2013-01-21 11:04:23 +0800395 if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
Andy Green76f61e72013-01-16 11:53:05 +0800396 break;
397
398 /*
399 * otherwise deal with the handshake. If there's any
400 * packet traffic already arrived we'll trigger poll() again
401 * right away and deal with it that way
402 */
403
404 return lws_client_interpret_server_handshake(context, wsi);
405
406bail3:
Andy Greenb5b23192013-02-11 17:13:32 +0800407 lwsl_info(
408 "closing connection at LWS_CONNMODE...SERVER_REPLY\n");
Andy Green76f61e72013-01-16 11:53:05 +0800409 libwebsocket_close_and_free_session(context, wsi,
410 LWS_CLOSE_STATUS_NOSTATUS);
Fujii Bunichirohe9294762013-09-18 21:01:02 +0800411 return -1;
Andy Green76f61e72013-01-16 11:53:05 +0800412
413 case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
414 lwsl_ext("LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT\n");
415 break;
416
417 case LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD:
418 lwsl_ext("LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD\n");
419 break;
420 default:
421 break;
422 }
423
424 return 0;
425}
426
427
428/*
429 * In-place str to lower case
430 */
431
432static void
433strtolower(char *s)
434{
435 while (*s) {
Bob Robertsac049112013-04-25 09:16:30 +0800436 *s = tolower((int)*s);
Andy Green76f61e72013-01-16 11:53:05 +0800437 s++;
438 }
439}
440
441int
442lws_client_interpret_server_handshake(struct libwebsocket_context *context,
443 struct libwebsocket *wsi)
444{
Andy Green76f61e72013-01-16 11:53:05 +0800445 const char *pc;
Andy Green76f61e72013-01-16 11:53:05 +0800446 int okay = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800447 char *p;
448 int len;
Andy Green3182ece2013-01-20 17:08:31 +0800449#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800450 char ext_name[128];
451 struct libwebsocket_extension *ext;
452 void *v;
Andy Green3182ece2013-01-20 17:08:31 +0800453 int more = 1;
454 const char *c;
455#endif
Andy Green76f61e72013-01-16 11:53:05 +0800456 int n;
Andy Green01b206e2013-03-23 09:53:17 +0800457 int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
Andy Green76f61e72013-01-16 11:53:05 +0800458
459 /*
460 * well, what the server sent looked reasonable for syntax.
461 * Now let's confirm it sent all the necessary headers
462 */
Andy Green76f61e72013-01-16 11:53:05 +0800463
Andy Green090789e2013-02-11 20:03:59 +0800464 if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
465 lwsl_info("no ACCEPT\n");
Andy Green16ab3182013-02-10 18:02:31 +0800466 goto bail3;
Andy Green090789e2013-02-11 20:03:59 +0800467 }
Andy Green16ab3182013-02-10 18:02:31 +0800468
469 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
Andy Green090789e2013-02-11 20:03:59 +0800470 if (!p) {
471 lwsl_info("no URI\n");
Andy Green16ab3182013-02-10 18:02:31 +0800472 goto bail3;
Andy Green090789e2013-02-11 20:03:59 +0800473 }
Andy Green16ab3182013-02-10 18:02:31 +0800474 if (p && strncmp(p, "101", 3)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800475 lwsl_warn(
476 "lws_client_handshake: got bad HTTP response '%s'\n", p);
Andy Green76f61e72013-01-16 11:53:05 +0800477 goto bail3;
478 }
479
Andy Green16ab3182013-02-10 18:02:31 +0800480 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
Andy Green090789e2013-02-11 20:03:59 +0800481 if (!p) {
482 lwsl_info("no UPGRADE\n");
Andy Green16ab3182013-02-10 18:02:31 +0800483 goto bail3;
Andy Green090789e2013-02-11 20:03:59 +0800484 }
Andy Green16ab3182013-02-10 18:02:31 +0800485 strtolower(p);
486 if (strcmp(p, "websocket")) {
Andy Greenb5b23192013-02-11 17:13:32 +0800487 lwsl_warn(
488 "lws_client_handshake: got bad Upgrade header '%s'\n", p);
Andy Green76f61e72013-01-16 11:53:05 +0800489 goto bail3;
490 }
491
Andy Green16ab3182013-02-10 18:02:31 +0800492 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);
Andy Green090789e2013-02-11 20:03:59 +0800493 if (!p) {
494 lwsl_info("no Connection hdr\n");
Andy Green16ab3182013-02-10 18:02:31 +0800495 goto bail3;
Andy Green090789e2013-02-11 20:03:59 +0800496 }
Andy Green16ab3182013-02-10 18:02:31 +0800497 strtolower(p);
498 if (strcmp(p, "upgrade")) {
Andy Greenb5b23192013-02-11 17:13:32 +0800499 lwsl_warn("lws_client_int_s_hs: bad header %s\n", p);
Andy Green76f61e72013-01-16 11:53:05 +0800500 goto bail3;
501 }
502
Andy Greene77fb802013-02-11 13:04:45 +0800503 pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
Andy Green76f61e72013-01-16 11:53:05 +0800504 if (pc == NULL)
Andy Greenb5b23192013-02-11 17:13:32 +0800505 lwsl_parser("lws_client_int_s_hs: no protocol list\n");
Andy Green76f61e72013-01-16 11:53:05 +0800506 else
Andy Greenb5b23192013-02-11 17:13:32 +0800507 lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);
Andy Green76f61e72013-01-16 11:53:05 +0800508
509 /*
510 * confirm the protocol the server wants to talk was in the list
511 * of protocols we offered
512 */
513
Andy Green16ab3182013-02-10 18:02:31 +0800514 len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
515 if (!len) {
Andy Green76f61e72013-01-16 11:53:05 +0800516
Andy Greenb5b23192013-02-11 17:13:32 +0800517 lwsl_info("lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\n");
Andy Green76f61e72013-01-16 11:53:05 +0800518 /*
519 * no protocol name to work from,
520 * default to first protocol
521 */
522 wsi->protocol = &context->protocols[0];
Andy Green76f61e72013-01-16 11:53:05 +0800523 goto check_extensions;
524 }
525
Andy Green16ab3182013-02-10 18:02:31 +0800526 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
527 len = strlen(p);
528
Andy Green76f61e72013-01-16 11:53:05 +0800529 while (*pc && !okay) {
Andy Greenb5b23192013-02-11 17:13:32 +0800530 if (!strncmp(pc, p, len) &&
531 (pc[len] == ',' || pc[len] == '\0')) {
Andy Green76f61e72013-01-16 11:53:05 +0800532 okay = 1;
533 continue;
534 }
535 while (*pc && *pc != ',')
536 pc++;
537 while (*pc && *pc != ' ')
538 pc++;
539 }
540
Andy Green76f61e72013-01-16 11:53:05 +0800541 if (!okay) {
Andy Greenb5b23192013-02-11 17:13:32 +0800542 lwsl_err("lws_client_int_s_hs: got bad protocol %s\n", p);
Andy Green76f61e72013-01-16 11:53:05 +0800543 goto bail2;
544 }
545
546 /*
547 * identify the selected protocol struct and set it
548 */
549 n = 0;
550 wsi->protocol = NULL;
Andy Green16ab3182013-02-10 18:02:31 +0800551 while (context->protocols[n].callback && !wsi->protocol) {
552 if (strcmp(p, context->protocols[n].name) == 0) {
Andy Green76f61e72013-01-16 11:53:05 +0800553 wsi->protocol = &context->protocols[n];
Andy Green16ab3182013-02-10 18:02:31 +0800554 break;
Andy Green76f61e72013-01-16 11:53:05 +0800555 }
556 n++;
557 }
558
559 if (wsi->protocol == NULL) {
Andy Greenb5b23192013-02-11 17:13:32 +0800560 lwsl_err("lws_client_int_s_hs: fail protocol %s\n", p);
Andy Green76f61e72013-01-16 11:53:05 +0800561 goto bail2;
562 }
563
564
565check_extensions:
Andy Green3182ece2013-01-20 17:08:31 +0800566#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800567 /* instantiate the accepted extensions */
568
Andy Green16ab3182013-02-10 18:02:31 +0800569 if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
Andy Green76f61e72013-01-16 11:53:05 +0800570 lwsl_ext("no client extenstions allowed by server\n");
571 goto check_accept;
572 }
573
574 /*
575 * break down the list of server accepted extensions
576 * and go through matching them or identifying bogons
577 */
578
Andy Greenb5b23192013-02-11 17:13:32 +0800579 if (lws_hdr_copy(wsi, (char *)context->service_buffer,
Andy Green090789e2013-02-11 20:03:59 +0800580 sizeof(context->service_buffer), WSI_TOKEN_EXTENSIONS) < 0) {
581 lwsl_warn("ext list from server failed to copy\n");
Andy Green16ab3182013-02-10 18:02:31 +0800582 goto bail2;
Andy Green090789e2013-02-11 20:03:59 +0800583 }
Andy Green16ab3182013-02-10 18:02:31 +0800584
585 c = (char *)context->service_buffer;
Andy Green76f61e72013-01-16 11:53:05 +0800586 n = 0;
587 while (more) {
588
589 if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
590 ext_name[n] = *c++;
591 if (n < sizeof(ext_name) - 1)
592 n++;
593 continue;
594 }
595 ext_name[n] = '\0';
596 if (!*c)
597 more = 0;
598 else {
599 c++;
600 if (!n)
601 continue;
602 }
603
604 /* check we actually support it */
605
606 lwsl_ext("checking client ext %s\n", ext_name);
607
608 n = 0;
609 ext = wsi->protocol->owning_server->extensions;
610 while (ext && ext->callback) {
611
612 if (strcmp(ext_name, ext->name)) {
613 ext++;
614 continue;
615 }
616
617 n = 1;
618
619 lwsl_ext("instantiating client ext %s\n", ext_name);
620
621 /* instantiate the extension on this conn */
622
623 wsi->active_extensions_user[
624 wsi->count_active_extensions] =
625 malloc(ext->per_session_data_size);
626 if (wsi->active_extensions_user[
627 wsi->count_active_extensions] == NULL) {
628 lwsl_err("Out of mem\n");
629 goto bail2;
630 }
631 memset(wsi->active_extensions_user[
632 wsi->count_active_extensions], 0,
633 ext->per_session_data_size);
634 wsi->active_extensions[
635 wsi->count_active_extensions] = ext;
636
637 /* allow him to construct his context */
638
639 ext->callback(wsi->protocol->owning_server,
640 ext, wsi,
641 LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
642 wsi->active_extensions_user[
643 wsi->count_active_extensions],
644 NULL, 0);
645
646 wsi->count_active_extensions++;
647
648 ext++;
649 }
650
651 if (n == 0) {
Andy Greenb5b23192013-02-11 17:13:32 +0800652 lwsl_warn("Unknown ext '%s'!\n", ext_name);
Andy Green76f61e72013-01-16 11:53:05 +0800653 goto bail2;
654 }
655
656 n = 0;
657 }
658
Andy Green76f61e72013-01-16 11:53:05 +0800659check_accept:
Andy Green3182ece2013-01-20 17:08:31 +0800660#endif
Andy Green76f61e72013-01-16 11:53:05 +0800661
Andy Green76f61e72013-01-16 11:53:05 +0800662 /*
663 * Confirm his accept token is the one we precomputed
664 */
665
Andy Green16ab3182013-02-10 18:02:31 +0800666 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
Andy Greena7521de2013-02-18 10:38:45 +0800667 if (strcmp(p, wsi->u.hdr.ah->initial_handshake_hash_base64)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800668 lwsl_warn("lws_client_int_s_hs: accept %s wrong vs %s\n", p,
Andy Greena7521de2013-02-18 10:38:45 +0800669 wsi->u.hdr.ah->initial_handshake_hash_base64);
Andy Green76f61e72013-01-16 11:53:05 +0800670 goto bail2;
671 }
672
Andy Green76f61e72013-01-16 11:53:05 +0800673 /* allocate the per-connection user memory (if any) */
Andy Green2af4d5b2013-02-18 16:30:10 +0800674 if (libwebsocket_ensure_user_space(wsi)) {
Andy Green090789e2013-02-11 20:03:59 +0800675 lwsl_err("Problem allocating wsi user mem\n");
Andy Green76f61e72013-01-16 11:53:05 +0800676 goto bail2;
Andy Green090789e2013-02-11 20:03:59 +0800677 }
Andy Green76f61e72013-01-16 11:53:05 +0800678
Andy Green2b57a342013-02-06 15:15:25 +0900679 /*
680 * we seem to be good to go, give client last chance to check
681 * headers and OK it
682 */
683
684 wsi->protocol->callback(context, wsi,
685 LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
686 wsi->user_space, NULL, 0);
687
Andy Green76f61e72013-01-16 11:53:05 +0800688 /* clear his proxy connection timeout */
689
690 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
691
Andy Green2b57a342013-02-06 15:15:25 +0900692 /* free up his parsing allocations */
Andy Green16ab3182013-02-10 18:02:31 +0800693 if (wsi->u.hdr.ah)
694 free(wsi->u.hdr.ah);
Andy Green2b57a342013-02-06 15:15:25 +0900695
Andy Green76f61e72013-01-16 11:53:05 +0800696 /* mark him as being alive */
697
698 wsi->state = WSI_STATE_ESTABLISHED;
699 wsi->mode = LWS_CONNMODE_WS_CLIENT;
700
Andy Green623a98d2013-01-21 11:04:23 +0800701 /* union transition */
Andy Green16ab3182013-02-10 18:02:31 +0800702
Andy Greenb5b23192013-02-11 17:13:32 +0800703 memset(&wsi->u, 0, sizeof(wsi->u));
Andy Green623a98d2013-01-21 11:04:23 +0800704
Andy Greenca0a1292013-03-16 11:24:23 +0800705 wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
706
Andy Green54495112013-02-06 21:10:16 +0900707 /*
708 * create the frame buffer for this connection according to the
709 * size mentioned in the protocol definition. If 0 there, then
710 * use a big default for compatibility
711 */
712
713 n = wsi->protocol->rx_buffer_size;
714 if (!n)
715 n = LWS_MAX_SOCKET_IO_BUF;
716 n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
717 wsi->u.ws.rx_user_buffer = malloc(n);
718 if (!wsi->u.ws.rx_user_buffer) {
719 lwsl_err("Out of Mem allocating rx buffer %d\n", n);
Andy Green01b206e2013-03-23 09:53:17 +0800720 goto bail2;
Andy Green54495112013-02-06 21:10:16 +0900721 }
722 lwsl_info("Allocating client RX buffer %d\n", n);
723
Andy Green01b206e2013-03-23 09:53:17 +0800724 if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof n)) {
725 lwsl_warn("Failed to set SNDBUF to %d", n);
726 goto bail3;
727 }
728
Andy Green76f61e72013-01-16 11:53:05 +0800729 lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
730
731 /* call him back to inform him he is up */
732
733 wsi->protocol->callback(context, wsi,
734 LWS_CALLBACK_CLIENT_ESTABLISHED,
735 wsi->user_space, NULL, 0);
Andy Green3182ece2013-01-20 17:08:31 +0800736#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800737 /*
738 * inform all extensions, not just active ones since they
739 * already know
740 */
741
742 ext = context->extensions;
743
744 while (ext && ext->callback) {
745 v = NULL;
746 for (n = 0; n < wsi->count_active_extensions; n++)
747 if (wsi->active_extensions[n] == ext)
748 v = wsi->active_extensions_user[n];
749
750 ext->callback(context, ext, wsi,
751 LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, v, NULL, 0);
752 ext++;
753 }
Andy Green3182ece2013-01-20 17:08:31 +0800754#endif
Andy Green76f61e72013-01-16 11:53:05 +0800755
756 return 0;
757
758bail3:
Andy Green01b206e2013-03-23 09:53:17 +0800759 free(wsi->u.ws.rx_user_buffer);
760 wsi->u.ws.rx_user_buffer = NULL;
761 close_reason = LWS_CLOSE_STATUS_NOSTATUS;
Andy Green76f61e72013-01-16 11:53:05 +0800762
763bail2:
Andy Greene77fb802013-02-11 13:04:45 +0800764 if (wsi->protocol)
765 wsi->protocol->callback(context, wsi,
Andy Green16ab3182013-02-10 18:02:31 +0800766 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
767 wsi->user_space, NULL, 0);
768
Andy Green96d882a2013-01-30 12:27:27 +0800769 lwsl_info("closing connection due to bail2 connection error\n");
Andy Green16ab3182013-02-10 18:02:31 +0800770
Andy Green2b57a342013-02-06 15:15:25 +0900771 /* free up his parsing allocations */
772
Andy Green16ab3182013-02-10 18:02:31 +0800773 if (wsi->u.hdr.ah)
774 free(wsi->u.hdr.ah);
Andy Green2b57a342013-02-06 15:15:25 +0900775
Andy Green01b206e2013-03-23 09:53:17 +0800776 libwebsocket_close_and_free_session(context, wsi, close_reason);
Andy Green76f61e72013-01-16 11:53:05 +0800777
778 return 1;
779}
780
Andy Green76f61e72013-01-16 11:53:05 +0800781
782char *
783libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
784 struct libwebsocket *wsi, char *pkt)
785{
Andy Greenc97067c2013-02-10 11:03:32 +0800786 char buf[128];
Andy Green76f61e72013-01-16 11:53:05 +0800787 char hash[20];
Andy Green80f168b2013-01-21 11:04:49 +0800788 char key_b64[40];
Andy Green76f61e72013-01-16 11:53:05 +0800789 char *p = pkt;
790 int n;
Andy Green3182ece2013-01-20 17:08:31 +0800791#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800792 struct libwebsocket_extension *ext;
793 struct libwebsocket_extension *ext1;
794 int ext_count = 0;
Andy Green3182ece2013-01-20 17:08:31 +0800795#endif
Andy Green76f61e72013-01-16 11:53:05 +0800796
797 /*
798 * create the random key
799 */
800
801 n = libwebsockets_get_random(context, hash, 16);
802 if (n != 16) {
803 lwsl_err("Unable to read from random dev %s\n",
804 SYSTEM_RANDOM_FILEPATH);
Andy Green76f61e72013-01-16 11:53:05 +0800805 libwebsocket_close_and_free_session(context, wsi,
806 LWS_CLOSE_STATUS_NOSTATUS);
807 return NULL;
808 }
809
Andy Greenb5b23192013-02-11 17:13:32 +0800810 lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
Andy Green76f61e72013-01-16 11:53:05 +0800811
812 /*
813 * 00 example client handshake
814 *
815 * GET /socket.io/websocket HTTP/1.1
816 * Upgrade: WebSocket
817 * Connection: Upgrade
818 * Host: 127.0.0.1:9999
819 * Origin: http://127.0.0.1
820 * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
821 * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
822 * Cookie: socketio=websocket
823 *
824 * (Á®Ä0¶†≥
825 *
826 * 04 example client handshake
827 *
828 * GET /chat HTTP/1.1
829 * Host: server.example.com
830 * Upgrade: websocket
831 * Connection: Upgrade
832 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
833 * Sec-WebSocket-Origin: http://example.com
834 * Sec-WebSocket-Protocol: chat, superchat
835 * Sec-WebSocket-Version: 4
836 */
837
Andy Greenb5b23192013-02-11 17:13:32 +0800838 p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a",
839 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
Andy Green76f61e72013-01-16 11:53:05 +0800840
Andy Greenb5b23192013-02-11 17:13:32 +0800841 p += sprintf(p,
842 "Pragma: no-cache\x0d\x0a""Cache-Control: no-cache\x0d\x0a");
Andy Green76f61e72013-01-16 11:53:05 +0800843
Andy Greenb5b23192013-02-11 17:13:32 +0800844 p += sprintf(p, "Host: %s\x0d\x0a",
845 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
846 p += sprintf(p,
Andy Green090789e2013-02-11 20:03:59 +0800847"Upgrade: websocket\x0d\x0a""Connection: Upgrade\x0d\x0a""Sec-WebSocket-Key: ");
Andy Green80f168b2013-01-21 11:04:49 +0800848 strcpy(p, key_b64);
849 p += strlen(key_b64);
Andy Green76f61e72013-01-16 11:53:05 +0800850 p += sprintf(p, "\x0d\x0a");
Andy Greene77fb802013-02-11 13:04:45 +0800851 if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
u0u044e260e2013-10-25 17:13:11 +0800852 p += sprintf(p, "Origin: http://%s\x0d\x0a",
Andy Greenb5b23192013-02-11 17:13:32 +0800853 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
Andy Greene77fb802013-02-11 13:04:45 +0800854
855 if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
Andy Green76f61e72013-01-16 11:53:05 +0800856 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
Andy Greenb5b23192013-02-11 17:13:32 +0800857 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));
Andy Green76f61e72013-01-16 11:53:05 +0800858
859 /* tell the server what extensions we could support */
860
861 p += sprintf(p, "Sec-WebSocket-Extensions: ");
Andy Green3182ece2013-01-20 17:08:31 +0800862#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800863 ext = context->extensions;
864 while (ext && ext->callback) {
865
866 n = 0;
867 ext1 = context->extensions;
868
869 while (ext1 && ext1->callback) {
870 n |= ext1->callback(context, ext1, wsi,
871 LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
872 NULL, (char *)ext->name, 0);
873
874 ext1++;
875 }
876
877 if (n) { /* an extension vetos us */
878 lwsl_ext("ext %s vetoed\n", (char *)ext->name);
879 ext++;
880 continue;
881 }
882
883 n = context->protocols[0].callback(context, wsi,
884 LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
885 wsi->user_space, (char *)ext->name, 0);
886
887 /*
888 * zero return from callback means
889 * go ahead and allow the extension,
890 * it's what we get if the callback is
891 * unhandled
892 */
893
894 if (n) {
895 ext++;
896 continue;
897 }
898
899 /* apply it */
900
901 if (ext_count)
902 *p++ = ',';
903 p += sprintf(p, "%s", ext->name);
904 ext_count++;
905
906 ext++;
907 }
Andy Green3182ece2013-01-20 17:08:31 +0800908#endif
Andy Green76f61e72013-01-16 11:53:05 +0800909 p += sprintf(p, "\x0d\x0a");
910
911 if (wsi->ietf_spec_revision)
912 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
913 wsi->ietf_spec_revision);
914
915 /* give userland a chance to append, eg, cookies */
916
917 context->protocols[0].callback(context, wsi,
918 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
Andy Greenc97067c2013-02-10 11:03:32 +0800919 NULL, &p, (pkt + sizeof(context->service_buffer)) - p - 12);
Andy Green76f61e72013-01-16 11:53:05 +0800920
921 p += sprintf(p, "\x0d\x0a");
922
923 /* prepare the expected server accept response */
924
Andy Greencecf5e72013-02-12 10:07:22 +0800925 key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
926 n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64);
927
Andy Greenc97067c2013-02-10 11:03:32 +0800928 SHA1((unsigned char *)buf, n, (unsigned char *)hash);
Andy Green76f61e72013-01-16 11:53:05 +0800929
930 lws_b64_encode_string(hash, 20,
Andy Greena7521de2013-02-18 10:38:45 +0800931 wsi->u.hdr.ah->initial_handshake_hash_base64,
932 sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64));
Andy Green76f61e72013-01-16 11:53:05 +0800933
Andy Green76f61e72013-01-16 11:53:05 +0800934 return p;
935}
936