blob: ff20b174977cb981db7652a1cd8155baa8f667e0 [file] [log] [blame]
Andy Green4739e5c2011-01-22 12:51:57 +00001#include "private-libwebsockets.h"
Andy Green4739e5c2011-01-22 12:51:57 +00002
Andy Green6ee372f2012-04-09 15:09:01 +08003struct libwebsocket *__libwebsocket_client_connect_2(
Andy Greena41314f2011-05-23 10:00:03 +01004 struct libwebsocket_context *context,
5 struct libwebsocket *wsi
6) {
7 struct pollfd pfd;
8 struct timeval tv;
9 struct hostent *server_hostent;
10 struct sockaddr_in server_addr;
11 int n;
12 int plen = 0;
13 char pkt[512];
14 int opt = 1;
M Kf2431152011-09-25 10:34:35 +010015#if defined(__APPLE__)
Andy Green6ee372f2012-04-09 15:09:01 +080016 struct protoent *tcp_proto;
M Kf2431152011-09-25 10:34:35 +010017#endif
Andy Greena41314f2011-05-23 10:00:03 +010018
Andy Green43db0452013-01-10 19:50:35 +080019 lwsl_client("__libwebsocket_client_connect_2\n");
Andy Green3182ece2013-01-20 17:08:31 +080020#ifndef LWS_NO_EXTENSIONS
Andy Greena41314f2011-05-23 10:00:03 +010021 wsi->candidate_children_list = NULL;
Andy Green3182ece2013-01-20 17:08:31 +080022#endif
Andy Greena41314f2011-05-23 10:00:03 +010023
24 /*
25 * proxy?
26 */
27
28 if (context->http_proxy_port) {
29 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
30 "User-agent: libwebsockets\x0d\x0a"
31/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
32 "\x0d\x0a", wsi->c_address, wsi->c_port);
33
34 /* OK from now on we talk via the proxy */
35
36 free(wsi->c_address);
37 wsi->c_address = strdup(context->http_proxy_address);
38 wsi->c_port = context->http_proxy_port;
39 }
40
41 /*
42 * prepare the actual connection (to the proxy, if any)
43 */
44
Andy Green43db0452013-01-10 19:50:35 +080045 lwsl_client("__libwebsocket_client_connect_2: address %s", wsi->c_address);
Andy Green66a16f32011-05-24 22:07:45 +010046
Andy Greena41314f2011-05-23 10:00:03 +010047 server_hostent = gethostbyname(wsi->c_address);
48 if (server_hostent == NULL) {
Andy Green43db0452013-01-10 19:50:35 +080049 lwsl_err("Unable to get host name from %s\n", wsi->c_address);
Andy Greena41314f2011-05-23 10:00:03 +010050 goto oom4;
51 }
52
53 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
54
55 if (wsi->sock < 0) {
Andy Green43db0452013-01-10 19:50:35 +080056 lwsl_warn("Unable to open socket\n");
Andy Greena41314f2011-05-23 10:00:03 +010057 goto oom4;
58 }
59
60 server_addr.sin_family = AF_INET;
61 server_addr.sin_port = htons(wsi->c_port);
62 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
63 bzero(&server_addr.sin_zero, 8);
64
65 /* Disable Nagle */
M Kf2431152011-09-25 10:34:35 +010066#if !defined(__APPLE__)
Andy Green6ee372f2012-04-09 15:09:01 +080067 setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY,
68 (const void *)&opt, sizeof(opt));
M Kf2431152011-09-25 10:34:35 +010069#else
Andy Green6ee372f2012-04-09 15:09:01 +080070 tcp_proto = getprotobyname("TCP");
71 setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY,
72 &opt, sizeof(opt));
M Kf2431152011-09-25 10:34:35 +010073#endif
Andy Greena41314f2011-05-23 10:00:03 +010074
75 /* Set receiving timeout */
76 tv.tv_sec = 0;
77 tv.tv_usec = 100 * 1000;
78 setsockopt(wsi->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv);
79
80 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
Andy Green6ee372f2012-04-09 15:09:01 +080081 sizeof(struct sockaddr)) == -1) {
Andy Green43db0452013-01-10 19:50:35 +080082 lwsl_debug("Connect failed\n");
Andy Green3fc2c652013-01-14 15:35:02 +080083 compatible_close(wsi->sock);
Andy Greena41314f2011-05-23 10:00:03 +010084 goto oom4;
85 }
86
Andy Green43db0452013-01-10 19:50:35 +080087 lwsl_client("connected\n");
Andy Greena41314f2011-05-23 10:00:03 +010088
Andy Greendfb23042013-01-17 12:26:48 +080089 insert_wsi_socket_into_fds(context, wsi);
Andy Greena41314f2011-05-23 10:00:03 +010090
91 /* we are connected to server, or proxy */
92
93 if (context->http_proxy_port) {
94
95 n = send(wsi->sock, pkt, plen, 0);
96 if (n < 0) {
Andy Green3fc2c652013-01-14 15:35:02 +080097 compatible_close(wsi->sock);
Andy Green43db0452013-01-10 19:50:35 +080098 lwsl_debug("ERROR writing to proxy socket\n");
Andy Greena41314f2011-05-23 10:00:03 +010099 goto bail1;
100 }
101
102 libwebsocket_set_timeout(wsi,
David Galeanoc9f1ff82013-01-09 18:01:23 +0800103 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
Andy Greena41314f2011-05-23 10:00:03 +0100104
105 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
106
107 return wsi;
108 }
109
110 /*
111 * provoke service to issue the handshake directly
112 * we need to do it this way because in the proxy case, this is the
113 * next state and executed only if and when we get a good proxy
Andy Green73abc252013-01-13 11:05:30 +0800114 * response inside the state machine... but notice in SSL case this
115 * may not have sent anything yet with 0 return, and won't until some
116 * many retries from main loop. To stop that becoming endless,
117 * cover with a timeout.
Andy Greena41314f2011-05-23 10:00:03 +0100118 */
119
Andy Green73abc252013-01-13 11:05:30 +0800120 libwebsocket_set_timeout(wsi,
121 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
122
Andy Greena41314f2011-05-23 10:00:03 +0100123 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
124 pfd.fd = wsi->sock;
125 pfd.revents = POLLIN;
David Galeano36750b82013-01-09 16:17:04 +0800126
127 n = libwebsocket_service_fd(context, &pfd);
128
129 if (n < 0)
Andy Green3928f612012-07-20 12:58:38 +0800130 goto oom4;
Andy Greena41314f2011-05-23 10:00:03 +0100131
David Galeano36750b82013-01-09 16:17:04 +0800132 if (n) /* returns 1 on failure after closing wsi */
133 return NULL;
134
Andy Greena41314f2011-05-23 10:00:03 +0100135 return wsi;
136
137oom4:
138 if (wsi->c_protocol)
139 free(wsi->c_protocol);
140
141 if (wsi->c_origin)
142 free(wsi->c_origin);
143
144 free(wsi->c_host);
145 free(wsi->c_path);
146
147bail1:
148 free(wsi);
149
150 return NULL;
151}
152
Andy Green90c7cbc2011-01-27 06:26:52 +0000153/**
154 * libwebsocket_client_connect() - Connect to another websocket server
Peter Hinz56885f32011-03-02 22:03:47 +0000155 * @context: Websocket context
Andy Green90c7cbc2011-01-27 06:26:52 +0000156 * @address: Remote server address, eg, "myserver.com"
157 * @port: Port to connect to on the remote server, eg, 80
158 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
159 * signed certs
160 * @path: Websocket path on server
161 * @host: Hostname on server
162 * @origin: Socket origin name
163 * @protocol: Comma-separated list of protocols being asked for from
164 * the server, or just one. The server will pick the one it
165 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +0000166 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
Andy Green6ee372f2012-04-09 15:09:01 +0800167 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +0000168 *
169 * This function creates a connection to a remote server
170 */
171
Andy Green4739e5c2011-01-22 12:51:57 +0000172struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +0000173libwebsocket_client_connect(struct libwebsocket_context *context,
Andy Green4739e5c2011-01-22 12:51:57 +0000174 const char *address,
175 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +0000176 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +0000177 const char *path,
178 const char *host,
179 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +0000180 const char *protocol,
181 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +0000182{
Andy Green4739e5c2011-01-22 12:51:57 +0000183 struct libwebsocket *wsi;
184 int n;
Andy Green3182ece2013-01-20 17:08:31 +0800185#ifndef LWS_NO_EXTENSIONS
Andy Greena41314f2011-05-23 10:00:03 +0100186 int m;
187 struct libwebsocket_extension *ext;
188 int handled;
Andy Green3182ece2013-01-20 17:08:31 +0800189#endif
190
Andy Greenbe93fef2011-02-14 20:25:43 +0000191#ifndef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000192 if (ssl_connection) {
Andy Green43db0452013-01-10 19:50:35 +0800193 lwsl_err("libwebsockets not configured for ssl\n");
Andy Green90c7cbc2011-01-27 06:26:52 +0000194 return NULL;
195 }
196#endif
Andy Green4739e5c2011-01-22 12:51:57 +0000197
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800198 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
Andy Greenbe93fef2011-02-14 20:25:43 +0000199 if (wsi == NULL)
200 goto bail1;
Andy Green4739e5c2011-01-22 12:51:57 +0000201
Darin Willitsc19456f2011-02-14 17:52:39 +0000202 memset(wsi, 0, sizeof *wsi);
203
Andy Greenbfb051f2011-02-09 08:49:14 +0000204 /* -1 means just use latest supported */
205
206 if (ietf_version_or_minus_one == -1)
Andy Green193306c2011-02-26 11:08:46 +0000207 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
Andy Greenbfb051f2011-02-09 08:49:14 +0000208
209 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green4739e5c2011-01-22 12:51:57 +0000210 wsi->name_buffer_pos = 0;
211 wsi->user_space = NULL;
212 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
213 wsi->pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +0000214 wsi->protocol = NULL;
Andy Greena71eafc2011-02-14 17:59:43 +0000215 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green3182ece2013-01-20 17:08:31 +0800216#ifndef LWS_NO_EXTENSIONS
Andy Greend6e09112011-03-05 16:12:15 +0000217 wsi->count_active_extensions = 0;
Andy Green3182ece2013-01-20 17:08:31 +0800218#endif
Andy Greenbe93fef2011-02-14 20:25:43 +0000219#ifdef LWS_OPENSSL_SUPPORT
220 wsi->use_ssl = ssl_connection;
221#endif
222
Andy Greena41314f2011-05-23 10:00:03 +0100223 wsi->c_port = port;
224 wsi->c_address = strdup(address);
225
Andy Greenbe93fef2011-02-14 20:25:43 +0000226 /* copy parameters over so state machine has access */
227
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800228 wsi->c_path = (char *)malloc(strlen(path) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000229 if (wsi->c_path == NULL)
230 goto bail1;
231 strcpy(wsi->c_path, path);
Andy Green6ee372f2012-04-09 15:09:01 +0800232
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800233 wsi->c_host = (char *)malloc(strlen(host) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000234 if (wsi->c_host == NULL)
235 goto oom1;
236 strcpy(wsi->c_host, host);
Andy Green6ee372f2012-04-09 15:09:01 +0800237
Andy Green08d33922011-02-26 10:22:49 +0000238 if (origin) {
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800239 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
Andy Green08d33922011-02-26 10:22:49 +0000240 if (wsi->c_origin == NULL)
241 goto oom2;
Andy Green41c58032013-01-12 13:21:08 +0800242 strcpy(wsi->c_origin, origin);
Andy Green08d33922011-02-26 10:22:49 +0000243 } else
244 wsi->c_origin = NULL;
Andy Green6ee372f2012-04-09 15:09:01 +0800245
David Brooks993343b2012-04-20 12:16:52 +0800246 wsi->c_callback = NULL;
Andy Greenbe93fef2011-02-14 20:25:43 +0000247 if (protocol) {
David Brooks993343b2012-04-20 12:16:52 +0800248 const char *pc;
249 struct libwebsocket_protocols *pp;
250
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800251 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000252 if (wsi->c_protocol == NULL)
253 goto oom3;
David Brooks993343b2012-04-20 12:16:52 +0800254
Andy Greenbe93fef2011-02-14 20:25:43 +0000255 strcpy(wsi->c_protocol, protocol);
David Brooks993343b2012-04-20 12:16:52 +0800256
257 pc = protocol;
258 while (*pc && *pc != ',')
259 pc++;
260 n = pc - protocol;
261 pp = context->protocols;
262 while (pp->name && !wsi->c_callback) {
263 if (!strncmp(protocol, pp->name, n))
264 wsi->c_callback = pp->callback;
265 pp++;
266 }
Andy Greenbe93fef2011-02-14 20:25:43 +0000267 } else
268 wsi->c_protocol = NULL;
269
David Brooks993343b2012-04-20 12:16:52 +0800270 if (!wsi->c_callback)
271 wsi->c_callback = context->protocols[0].callback;
272
Andy Greenbfb051f2011-02-09 08:49:14 +0000273 /* set up appropriate masking */
274
275 wsi->xor_mask = xor_no_mask;
276
277 switch (wsi->ietf_spec_revision) {
Andy Greeneeaacb32011-03-01 20:44:24 +0000278 case 0:
279 break;
Andy Greenbfb051f2011-02-09 08:49:14 +0000280 case 4:
281 wsi->xor_mask = xor_mask_04;
282 break;
283 case 5:
Andy Green9514bf82011-02-26 11:13:56 +0000284 case 6:
Andy Green33872cd2011-04-24 05:49:44 +0100285 case 7:
Andy Greend85cb202011-09-25 09:32:54 +0100286 case 8:
287 case 13:
Andy Greenbfb051f2011-02-09 08:49:14 +0000288 wsi->xor_mask = xor_mask_05;
289 break;
290 default:
Andy Green43db0452013-01-10 19:50:35 +0800291 lwsl_parser("Client ietf version %d not supported\n",
Andy Greenbfb051f2011-02-09 08:49:14 +0000292 wsi->ietf_spec_revision);
Andy Greenbe93fef2011-02-14 20:25:43 +0000293 goto oom4;
Andy Greenbfb051f2011-02-09 08:49:14 +0000294 }
295
296 /* force no mask if he asks for that though */
297
Peter Hinz56885f32011-03-02 22:03:47 +0000298 if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
Andy Greenbfb051f2011-02-09 08:49:14 +0000299 wsi->xor_mask = xor_no_mask;
300
Andy Green4739e5c2011-01-22 12:51:57 +0000301 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
302 wsi->utf8_token[n].token = NULL;
303 wsi->utf8_token[n].token_len = 0;
304 }
305
Andy Green3182ece2013-01-20 17:08:31 +0800306#ifndef LWS_NO_EXTENSIONS
Andy Green4739e5c2011-01-22 12:51:57 +0000307 /*
Andy Greena41314f2011-05-23 10:00:03 +0100308 * Check with each extension if it is able to route and proxy this
309 * connection for us. For example, an extension like x-google-mux
310 * can handle this and then we don't need an actual socket for this
311 * connection.
Andy Green9659f372011-01-27 22:01:43 +0000312 */
313
Andy Greena41314f2011-05-23 10:00:03 +0100314 handled = 0;
315 ext = context->extensions;
316 n = 0;
Andy Green9659f372011-01-27 22:01:43 +0000317
Andy Greena41314f2011-05-23 10:00:03 +0100318 while (ext && ext->callback && !handled) {
319 m = ext->callback(context, ext, wsi,
320 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
321 (void *)(long)n, (void *)address, port);
322 if (m)
323 handled = 1;
Andy Green9659f372011-01-27 22:01:43 +0000324
Andy Greena41314f2011-05-23 10:00:03 +0100325 ext++;
326 n++;
Andy Green9659f372011-01-27 22:01:43 +0000327 }
328
Andy Greena41314f2011-05-23 10:00:03 +0100329 if (handled) {
Andy Green43db0452013-01-10 19:50:35 +0800330 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
Andy Green5b9a4c02011-01-28 09:39:29 +0000331
Andy Greenbe93fef2011-02-14 20:25:43 +0000332 libwebsocket_set_timeout(wsi,
David Galeanoc9f1ff82013-01-09 18:01:23 +0800333 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
Andy Green5b9a4c02011-01-28 09:39:29 +0000334
Andy Greena41314f2011-05-23 10:00:03 +0100335 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
Andy Greenbe93fef2011-02-14 20:25:43 +0000336 return wsi;
Andy Green9659f372011-01-27 22:01:43 +0000337 }
Andy Green3182ece2013-01-20 17:08:31 +0800338#endif
Andy Green43db0452013-01-10 19:50:35 +0800339 lwsl_client("libwebsocket_client_connect: direct conn\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000340
Andy Greena41314f2011-05-23 10:00:03 +0100341 return __libwebsocket_client_connect_2(context, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000342
Andy Green4739e5c2011-01-22 12:51:57 +0000343
Andy Greenbe93fef2011-02-14 20:25:43 +0000344oom4:
345 if (wsi->c_protocol)
346 free(wsi->c_protocol);
Andy Green4739e5c2011-01-22 12:51:57 +0000347
Andy Greenbe93fef2011-02-14 20:25:43 +0000348oom3:
Andy Green08d33922011-02-26 10:22:49 +0000349 if (wsi->c_origin)
350 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000351
352oom2:
353 free(wsi->c_host);
354
355oom1:
356 free(wsi->c_path);
357
Andy Green4739e5c2011-01-22 12:51:57 +0000358bail1:
359 free(wsi);
360
361 return NULL;
362}
David Brooks2c60d952012-04-20 12:19:01 +0800363
364
365/**
366 * libwebsocket_client_connect_extended() - Connect to another websocket server
367 * @context: Websocket context
368 * @address: Remote server address, eg, "myserver.com"
369 * @port: Port to connect to on the remote server, eg, 80
370 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
371 * signed certs
372 * @path: Websocket path on server
373 * @host: Hostname on server
374 * @origin: Socket origin name
375 * @protocol: Comma-separated list of protocols being asked for from
376 * the server, or just one. The server will pick the one it
377 * likes best.
378 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
379 * protocol supported, or the specific protocol ordinal
380 * @userdata: Pre-allocated user data
381 *
382 * This function creates a connection to a remote server
383 */
384
385struct libwebsocket *
386libwebsocket_client_connect_extended(struct libwebsocket_context *context,
387 const char *address,
388 int port,
389 int ssl_connection,
390 const char *path,
391 const char *host,
392 const char *origin,
393 const char *protocol,
394 int ietf_version_or_minus_one,
395 void *userdata)
396{
397 struct libwebsocket *ws =
398 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
399
400 if (ws && !ws->user_space && userdata)
401 ws->user_space = userdata ;
402
403 return ws ;
404 }