blob: 15c4b13d4ab7010a99e84bb7fb5f56601aac1413 [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 Greena41314f2011-05-23 10:00:03 +010020
21 wsi->candidate_children_list = NULL;
22
23 /*
24 * proxy?
25 */
26
27 if (context->http_proxy_port) {
28 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
29 "User-agent: libwebsockets\x0d\x0a"
30/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
31 "\x0d\x0a", wsi->c_address, wsi->c_port);
32
33 /* OK from now on we talk via the proxy */
34
35 free(wsi->c_address);
36 wsi->c_address = strdup(context->http_proxy_address);
37 wsi->c_port = context->http_proxy_port;
38 }
39
40 /*
41 * prepare the actual connection (to the proxy, if any)
42 */
43
Andy Green43db0452013-01-10 19:50:35 +080044 lwsl_client("__libwebsocket_client_connect_2: address %s", wsi->c_address);
Andy Green66a16f32011-05-24 22:07:45 +010045
Andy Greena41314f2011-05-23 10:00:03 +010046 server_hostent = gethostbyname(wsi->c_address);
47 if (server_hostent == NULL) {
Andy Green43db0452013-01-10 19:50:35 +080048 lwsl_err("Unable to get host name from %s\n", wsi->c_address);
Andy Greena41314f2011-05-23 10:00:03 +010049 goto oom4;
50 }
51
52 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
53
54 if (wsi->sock < 0) {
Andy Green43db0452013-01-10 19:50:35 +080055 lwsl_warn("Unable to open socket\n");
Andy Greena41314f2011-05-23 10:00:03 +010056 goto oom4;
57 }
58
59 server_addr.sin_family = AF_INET;
60 server_addr.sin_port = htons(wsi->c_port);
61 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
62 bzero(&server_addr.sin_zero, 8);
63
64 /* Disable Nagle */
M Kf2431152011-09-25 10:34:35 +010065#if !defined(__APPLE__)
Andy Green6ee372f2012-04-09 15:09:01 +080066 setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY,
67 (const void *)&opt, sizeof(opt));
M Kf2431152011-09-25 10:34:35 +010068#else
Andy Green6ee372f2012-04-09 15:09:01 +080069 tcp_proto = getprotobyname("TCP");
70 setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY,
71 &opt, sizeof(opt));
M Kf2431152011-09-25 10:34:35 +010072#endif
Andy Greena41314f2011-05-23 10:00:03 +010073
74 /* Set receiving timeout */
75 tv.tv_sec = 0;
76 tv.tv_usec = 100 * 1000;
77 setsockopt(wsi->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv);
78
79 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
Andy Green6ee372f2012-04-09 15:09:01 +080080 sizeof(struct sockaddr)) == -1) {
Andy Green43db0452013-01-10 19:50:35 +080081 lwsl_debug("Connect failed\n");
Tobias Maierd1db83c2012-05-30 12:46:42 +080082#ifdef WIN32
83 closesocket(wsi->sock);
84#else
85 close(wsi->sock);
86#endif
Andy Greena41314f2011-05-23 10:00:03 +010087 goto oom4;
88 }
89
Andy Green43db0452013-01-10 19:50:35 +080090 lwsl_client("connected\n");
Andy Greena41314f2011-05-23 10:00:03 +010091
92 /* into fd -> wsi hashtable */
93
94 insert_wsi(context, wsi);
95
96 /* into internal poll list */
97
98 context->fds[context->fds_count].fd = wsi->sock;
99 context->fds[context->fds_count].revents = 0;
100 context->fds[context->fds_count++].events = POLLIN;
101
102 /* external POLL support via protocol 0 */
103 context->protocols[0].callback(context, wsi,
104 LWS_CALLBACK_ADD_POLL_FD,
105 (void *)(long)wsi->sock, NULL, POLLIN);
106
107 /* we are connected to server, or proxy */
108
109 if (context->http_proxy_port) {
110
111 n = send(wsi->sock, pkt, plen, 0);
112 if (n < 0) {
113#ifdef WIN32
114 closesocket(wsi->sock);
115#else
116 close(wsi->sock);
117#endif
Andy Green43db0452013-01-10 19:50:35 +0800118 lwsl_debug("ERROR writing to proxy socket\n");
Andy Greena41314f2011-05-23 10:00:03 +0100119 goto bail1;
120 }
121
122 libwebsocket_set_timeout(wsi,
David Galeanoc9f1ff82013-01-09 18:01:23 +0800123 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
Andy Greena41314f2011-05-23 10:00:03 +0100124
125 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
126
127 return wsi;
128 }
129
130 /*
131 * provoke service to issue the handshake directly
132 * we need to do it this way because in the proxy case, this is the
133 * next state and executed only if and when we get a good proxy
134 * response inside the state machine
135 */
136
137 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
138 pfd.fd = wsi->sock;
139 pfd.revents = POLLIN;
David Galeano36750b82013-01-09 16:17:04 +0800140
141 n = libwebsocket_service_fd(context, &pfd);
142
143 if (n < 0)
Andy Green3928f612012-07-20 12:58:38 +0800144 goto oom4;
Andy Greena41314f2011-05-23 10:00:03 +0100145
David Galeano36750b82013-01-09 16:17:04 +0800146 if (n) /* returns 1 on failure after closing wsi */
147 return NULL;
148
Andy Greena41314f2011-05-23 10:00:03 +0100149 return wsi;
150
151oom4:
152 if (wsi->c_protocol)
153 free(wsi->c_protocol);
154
155 if (wsi->c_origin)
156 free(wsi->c_origin);
157
158 free(wsi->c_host);
159 free(wsi->c_path);
160
161bail1:
162 free(wsi);
163
164 return NULL;
165}
166
Andy Green90c7cbc2011-01-27 06:26:52 +0000167/**
168 * libwebsocket_client_connect() - Connect to another websocket server
Peter Hinz56885f32011-03-02 22:03:47 +0000169 * @context: Websocket context
Andy Green90c7cbc2011-01-27 06:26:52 +0000170 * @address: Remote server address, eg, "myserver.com"
171 * @port: Port to connect to on the remote server, eg, 80
172 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
173 * signed certs
174 * @path: Websocket path on server
175 * @host: Hostname on server
176 * @origin: Socket origin name
177 * @protocol: Comma-separated list of protocols being asked for from
178 * the server, or just one. The server will pick the one it
179 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +0000180 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
Andy Green6ee372f2012-04-09 15:09:01 +0800181 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +0000182 *
183 * This function creates a connection to a remote server
184 */
185
Andy Green4739e5c2011-01-22 12:51:57 +0000186struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +0000187libwebsocket_client_connect(struct libwebsocket_context *context,
Andy Green4739e5c2011-01-22 12:51:57 +0000188 const char *address,
189 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +0000190 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +0000191 const char *path,
192 const char *host,
193 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +0000194 const char *protocol,
195 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +0000196{
Andy Green4739e5c2011-01-22 12:51:57 +0000197 struct libwebsocket *wsi;
198 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100199 int m;
200 struct libwebsocket_extension *ext;
201 int handled;
Andy Greenbe93fef2011-02-14 20:25:43 +0000202#ifndef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000203 if (ssl_connection) {
Andy Green43db0452013-01-10 19:50:35 +0800204 lwsl_err("libwebsockets not configured for ssl\n");
Andy Green90c7cbc2011-01-27 06:26:52 +0000205 return NULL;
206 }
207#endif
Andy Green4739e5c2011-01-22 12:51:57 +0000208
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800209 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
Andy Greenbe93fef2011-02-14 20:25:43 +0000210 if (wsi == NULL)
211 goto bail1;
Andy Green4739e5c2011-01-22 12:51:57 +0000212
Darin Willitsc19456f2011-02-14 17:52:39 +0000213 memset(wsi, 0, sizeof *wsi);
214
Andy Greenbfb051f2011-02-09 08:49:14 +0000215 /* -1 means just use latest supported */
216
217 if (ietf_version_or_minus_one == -1)
Andy Green193306c2011-02-26 11:08:46 +0000218 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
Andy Greenbfb051f2011-02-09 08:49:14 +0000219
220 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green4739e5c2011-01-22 12:51:57 +0000221 wsi->name_buffer_pos = 0;
222 wsi->user_space = NULL;
223 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
224 wsi->pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +0000225 wsi->protocol = NULL;
Andy Greena71eafc2011-02-14 17:59:43 +0000226 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Greend6e09112011-03-05 16:12:15 +0000227 wsi->count_active_extensions = 0;
Andy Greenbe93fef2011-02-14 20:25:43 +0000228#ifdef LWS_OPENSSL_SUPPORT
229 wsi->use_ssl = ssl_connection;
230#endif
231
Andy Greena41314f2011-05-23 10:00:03 +0100232 wsi->c_port = port;
233 wsi->c_address = strdup(address);
234
Andy Greenbe93fef2011-02-14 20:25:43 +0000235 /* copy parameters over so state machine has access */
236
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800237 wsi->c_path = (char *)malloc(strlen(path) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000238 if (wsi->c_path == NULL)
239 goto bail1;
240 strcpy(wsi->c_path, path);
Andy Green6ee372f2012-04-09 15:09:01 +0800241
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800242 wsi->c_host = (char *)malloc(strlen(host) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000243 if (wsi->c_host == NULL)
244 goto oom1;
245 strcpy(wsi->c_host, host);
Andy Green6ee372f2012-04-09 15:09:01 +0800246
Andy Green08d33922011-02-26 10:22:49 +0000247 if (origin) {
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800248 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
Andy Green08d33922011-02-26 10:22:49 +0000249 strcpy(wsi->c_origin, origin);
250 if (wsi->c_origin == NULL)
251 goto oom2;
252 } else
253 wsi->c_origin = NULL;
Andy Green6ee372f2012-04-09 15:09:01 +0800254
David Brooks993343b2012-04-20 12:16:52 +0800255 wsi->c_callback = NULL;
Andy Greenbe93fef2011-02-14 20:25:43 +0000256 if (protocol) {
David Brooks993343b2012-04-20 12:16:52 +0800257 const char *pc;
258 struct libwebsocket_protocols *pp;
259
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800260 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000261 if (wsi->c_protocol == NULL)
262 goto oom3;
David Brooks993343b2012-04-20 12:16:52 +0800263
Andy Greenbe93fef2011-02-14 20:25:43 +0000264 strcpy(wsi->c_protocol, protocol);
David Brooks993343b2012-04-20 12:16:52 +0800265
266 pc = protocol;
267 while (*pc && *pc != ',')
268 pc++;
269 n = pc - protocol;
270 pp = context->protocols;
271 while (pp->name && !wsi->c_callback) {
272 if (!strncmp(protocol, pp->name, n))
273 wsi->c_callback = pp->callback;
274 pp++;
275 }
Andy Greenbe93fef2011-02-14 20:25:43 +0000276 } else
277 wsi->c_protocol = NULL;
278
David Brooks993343b2012-04-20 12:16:52 +0800279 if (!wsi->c_callback)
280 wsi->c_callback = context->protocols[0].callback;
281
Andy Greenbfb051f2011-02-09 08:49:14 +0000282 /* set up appropriate masking */
283
284 wsi->xor_mask = xor_no_mask;
285
286 switch (wsi->ietf_spec_revision) {
Andy Greeneeaacb32011-03-01 20:44:24 +0000287 case 0:
288 break;
Andy Greenbfb051f2011-02-09 08:49:14 +0000289 case 4:
290 wsi->xor_mask = xor_mask_04;
291 break;
292 case 5:
Andy Green9514bf82011-02-26 11:13:56 +0000293 case 6:
Andy Green33872cd2011-04-24 05:49:44 +0100294 case 7:
Andy Greend85cb202011-09-25 09:32:54 +0100295 case 8:
296 case 13:
Andy Greenbfb051f2011-02-09 08:49:14 +0000297 wsi->xor_mask = xor_mask_05;
298 break;
299 default:
Andy Green43db0452013-01-10 19:50:35 +0800300 lwsl_parser("Client ietf version %d not supported\n",
Andy Greenbfb051f2011-02-09 08:49:14 +0000301 wsi->ietf_spec_revision);
Andy Greenbe93fef2011-02-14 20:25:43 +0000302 goto oom4;
Andy Greenbfb051f2011-02-09 08:49:14 +0000303 }
304
305 /* force no mask if he asks for that though */
306
Peter Hinz56885f32011-03-02 22:03:47 +0000307 if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
Andy Greenbfb051f2011-02-09 08:49:14 +0000308 wsi->xor_mask = xor_no_mask;
309
Andy Green4739e5c2011-01-22 12:51:57 +0000310 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
311 wsi->utf8_token[n].token = NULL;
312 wsi->utf8_token[n].token_len = 0;
313 }
314
315 /*
Andy Greena41314f2011-05-23 10:00:03 +0100316 * Check with each extension if it is able to route and proxy this
317 * connection for us. For example, an extension like x-google-mux
318 * can handle this and then we don't need an actual socket for this
319 * connection.
Andy Green9659f372011-01-27 22:01:43 +0000320 */
321
Andy Greena41314f2011-05-23 10:00:03 +0100322 handled = 0;
323 ext = context->extensions;
324 n = 0;
Andy Green9659f372011-01-27 22:01:43 +0000325
Andy Greena41314f2011-05-23 10:00:03 +0100326 while (ext && ext->callback && !handled) {
327 m = ext->callback(context, ext, wsi,
328 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
329 (void *)(long)n, (void *)address, port);
330 if (m)
331 handled = 1;
Andy Green9659f372011-01-27 22:01:43 +0000332
Andy Greena41314f2011-05-23 10:00:03 +0100333 ext++;
334 n++;
Andy Green9659f372011-01-27 22:01:43 +0000335 }
336
Andy Greena41314f2011-05-23 10:00:03 +0100337 if (handled) {
Andy Green43db0452013-01-10 19:50:35 +0800338 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
Andy Green5b9a4c02011-01-28 09:39:29 +0000339
Andy Greenbe93fef2011-02-14 20:25:43 +0000340 libwebsocket_set_timeout(wsi,
David Galeanoc9f1ff82013-01-09 18:01:23 +0800341 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
Andy Green5b9a4c02011-01-28 09:39:29 +0000342
Andy Greena41314f2011-05-23 10:00:03 +0100343 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
Andy Greenbe93fef2011-02-14 20:25:43 +0000344 return wsi;
Andy Green9659f372011-01-27 22:01:43 +0000345 }
346
Andy Green43db0452013-01-10 19:50:35 +0800347 lwsl_client("libwebsocket_client_connect: direct conn\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000348
Andy Greena41314f2011-05-23 10:00:03 +0100349 return __libwebsocket_client_connect_2(context, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000350
Andy Green4739e5c2011-01-22 12:51:57 +0000351
Andy Greenbe93fef2011-02-14 20:25:43 +0000352oom4:
353 if (wsi->c_protocol)
354 free(wsi->c_protocol);
Andy Green4739e5c2011-01-22 12:51:57 +0000355
Andy Greenbe93fef2011-02-14 20:25:43 +0000356oom3:
Andy Green08d33922011-02-26 10:22:49 +0000357 if (wsi->c_origin)
358 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000359
360oom2:
361 free(wsi->c_host);
362
363oom1:
364 free(wsi->c_path);
365
Andy Green4739e5c2011-01-22 12:51:57 +0000366bail1:
367 free(wsi);
368
369 return NULL;
370}
David Brooks2c60d952012-04-20 12:19:01 +0800371
372
373/**
374 * libwebsocket_client_connect_extended() - Connect to another websocket server
375 * @context: Websocket context
376 * @address: Remote server address, eg, "myserver.com"
377 * @port: Port to connect to on the remote server, eg, 80
378 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
379 * signed certs
380 * @path: Websocket path on server
381 * @host: Hostname on server
382 * @origin: Socket origin name
383 * @protocol: Comma-separated list of protocols being asked for from
384 * the server, or just one. The server will pick the one it
385 * likes best.
386 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
387 * protocol supported, or the specific protocol ordinal
388 * @userdata: Pre-allocated user data
389 *
390 * This function creates a connection to a remote server
391 */
392
393struct libwebsocket *
394libwebsocket_client_connect_extended(struct libwebsocket_context *context,
395 const char *address,
396 int port,
397 int ssl_connection,
398 const char *path,
399 const char *host,
400 const char *origin,
401 const char *protocol,
402 int ietf_version_or_minus_one,
403 void *userdata)
404{
405 struct libwebsocket *ws =
406 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
407
408 if (ws && !ws->user_space && userdata)
409 ws->user_space = userdata ;
410
411 return ws ;
412 }