blob: 1fc78f7d12e995a831f0b8767d158ab2355366dd [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;
Andy Greena41314f2011-05-23 10:00:03 +01008 struct hostent *server_hostent;
9 struct sockaddr_in server_addr;
10 int n;
11 int plen = 0;
Andy Greena41314f2011-05-23 10:00:03 +010012
Andy Green43db0452013-01-10 19:50:35 +080013 lwsl_client("__libwebsocket_client_connect_2\n");
Andy Green3182ece2013-01-20 17:08:31 +080014#ifndef LWS_NO_EXTENSIONS
Andy Greena41314f2011-05-23 10:00:03 +010015 wsi->candidate_children_list = NULL;
Andy Green3182ece2013-01-20 17:08:31 +080016#endif
Andy Greena41314f2011-05-23 10:00:03 +010017
18 /*
19 * proxy?
20 */
21
22 if (context->http_proxy_port) {
Andy Greenf54a94b2013-02-10 15:19:39 +080023 plen = sprintf(context->service_buffer,
24 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
Andy Greena41314f2011-05-23 10:00:03 +010025 "User-agent: libwebsockets\x0d\x0a"
26/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
27 "\x0d\x0a", wsi->c_address, wsi->c_port);
28
29 /* OK from now on we talk via the proxy */
30
31 free(wsi->c_address);
32 wsi->c_address = strdup(context->http_proxy_address);
33 wsi->c_port = context->http_proxy_port;
34 }
35
36 /*
37 * prepare the actual connection (to the proxy, if any)
38 */
39
Andy Greena690cd02013-02-09 12:25:31 +080040 lwsl_client("__libwebsocket_client_connect_2: address %s\n",
41 wsi->c_address);
Andy Green66a16f32011-05-24 22:07:45 +010042
Andy Greena41314f2011-05-23 10:00:03 +010043 server_hostent = gethostbyname(wsi->c_address);
44 if (server_hostent == NULL) {
Andy Green43db0452013-01-10 19:50:35 +080045 lwsl_err("Unable to get host name from %s\n", wsi->c_address);
Andy Greena41314f2011-05-23 10:00:03 +010046 goto oom4;
47 }
48
49 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
50
51 if (wsi->sock < 0) {
Andy Green43db0452013-01-10 19:50:35 +080052 lwsl_warn("Unable to open socket\n");
Andy Greena41314f2011-05-23 10:00:03 +010053 goto oom4;
54 }
55
56 server_addr.sin_family = AF_INET;
57 server_addr.sin_port = htons(wsi->c_port);
58 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
59 bzero(&server_addr.sin_zero, 8);
60
Andy Greena41314f2011-05-23 10:00:03 +010061 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
Andy Green6ee372f2012-04-09 15:09:01 +080062 sizeof(struct sockaddr)) == -1) {
Andy Green43db0452013-01-10 19:50:35 +080063 lwsl_debug("Connect failed\n");
Andy Green3fc2c652013-01-14 15:35:02 +080064 compatible_close(wsi->sock);
Andy Greena41314f2011-05-23 10:00:03 +010065 goto oom4;
66 }
67
Andy Green43db0452013-01-10 19:50:35 +080068 lwsl_client("connected\n");
Andy Greena41314f2011-05-23 10:00:03 +010069
Andy Greena690cd02013-02-09 12:25:31 +080070 if (lws_set_socket_options(context, wsi->sock)) {
71 lwsl_err("Failed to set wsi socket options\n");
72 close(wsi->sock);
73 goto oom4;
74 }
75
Andy Greendfb23042013-01-17 12:26:48 +080076 insert_wsi_socket_into_fds(context, wsi);
Andy Greena41314f2011-05-23 10:00:03 +010077
78 /* we are connected to server, or proxy */
79
80 if (context->http_proxy_port) {
81
Andy Greenf54a94b2013-02-10 15:19:39 +080082 n = send(wsi->sock, context->service_buffer, plen, 0);
Andy Greena41314f2011-05-23 10:00:03 +010083 if (n < 0) {
Andy Green3fc2c652013-01-14 15:35:02 +080084 compatible_close(wsi->sock);
Andy Green43db0452013-01-10 19:50:35 +080085 lwsl_debug("ERROR writing to proxy socket\n");
Andy Greena41314f2011-05-23 10:00:03 +010086 goto bail1;
87 }
88
89 libwebsocket_set_timeout(wsi,
David Galeanoc9f1ff82013-01-09 18:01:23 +080090 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
Andy Greena41314f2011-05-23 10:00:03 +010091
92 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
93
94 return wsi;
95 }
96
97 /*
98 * provoke service to issue the handshake directly
99 * we need to do it this way because in the proxy case, this is the
100 * next state and executed only if and when we get a good proxy
Andy Green73abc252013-01-13 11:05:30 +0800101 * response inside the state machine... but notice in SSL case this
102 * may not have sent anything yet with 0 return, and won't until some
103 * many retries from main loop. To stop that becoming endless,
104 * cover with a timeout.
Andy Greena41314f2011-05-23 10:00:03 +0100105 */
106
Andy Green73abc252013-01-13 11:05:30 +0800107 libwebsocket_set_timeout(wsi,
108 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
109
Andy Greena41314f2011-05-23 10:00:03 +0100110 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
111 pfd.fd = wsi->sock;
112 pfd.revents = POLLIN;
David Galeano36750b82013-01-09 16:17:04 +0800113
114 n = libwebsocket_service_fd(context, &pfd);
115
116 if (n < 0)
Andy Green3928f612012-07-20 12:58:38 +0800117 goto oom4;
Andy Greena41314f2011-05-23 10:00:03 +0100118
David Galeano36750b82013-01-09 16:17:04 +0800119 if (n) /* returns 1 on failure after closing wsi */
120 return NULL;
121
Andy Greena41314f2011-05-23 10:00:03 +0100122 return wsi;
123
124oom4:
125 if (wsi->c_protocol)
126 free(wsi->c_protocol);
127
128 if (wsi->c_origin)
129 free(wsi->c_origin);
130
131 free(wsi->c_host);
132 free(wsi->c_path);
133
134bail1:
135 free(wsi);
136
137 return NULL;
138}
139
Andy Green90c7cbc2011-01-27 06:26:52 +0000140/**
141 * libwebsocket_client_connect() - Connect to another websocket server
Peter Hinz56885f32011-03-02 22:03:47 +0000142 * @context: Websocket context
Andy Green90c7cbc2011-01-27 06:26:52 +0000143 * @address: Remote server address, eg, "myserver.com"
144 * @port: Port to connect to on the remote server, eg, 80
145 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
146 * signed certs
147 * @path: Websocket path on server
148 * @host: Hostname on server
149 * @origin: Socket origin name
150 * @protocol: Comma-separated list of protocols being asked for from
151 * the server, or just one. The server will pick the one it
152 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +0000153 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
Andy Green6ee372f2012-04-09 15:09:01 +0800154 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +0000155 *
156 * This function creates a connection to a remote server
157 */
158
Andy Green4739e5c2011-01-22 12:51:57 +0000159struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +0000160libwebsocket_client_connect(struct libwebsocket_context *context,
Andy Green4739e5c2011-01-22 12:51:57 +0000161 const char *address,
162 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +0000163 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +0000164 const char *path,
165 const char *host,
166 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +0000167 const char *protocol,
168 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +0000169{
Andy Green4739e5c2011-01-22 12:51:57 +0000170 struct libwebsocket *wsi;
171 int n;
Andy Green3182ece2013-01-20 17:08:31 +0800172#ifndef LWS_NO_EXTENSIONS
Andy Greena41314f2011-05-23 10:00:03 +0100173 int m;
174 struct libwebsocket_extension *ext;
175 int handled;
Andy Green3182ece2013-01-20 17:08:31 +0800176#endif
177
Andy Greenbe93fef2011-02-14 20:25:43 +0000178#ifndef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000179 if (ssl_connection) {
Andy Green43db0452013-01-10 19:50:35 +0800180 lwsl_err("libwebsockets not configured for ssl\n");
Andy Green90c7cbc2011-01-27 06:26:52 +0000181 return NULL;
182 }
183#endif
Andy Green4739e5c2011-01-22 12:51:57 +0000184
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800185 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
Andy Greenbe93fef2011-02-14 20:25:43 +0000186 if (wsi == NULL)
187 goto bail1;
Andy Green4739e5c2011-01-22 12:51:57 +0000188
Darin Willitsc19456f2011-02-14 17:52:39 +0000189 memset(wsi, 0, sizeof *wsi);
190
Andy Greenbfb051f2011-02-09 08:49:14 +0000191 /* -1 means just use latest supported */
192
193 if (ietf_version_or_minus_one == -1)
Andy Green193306c2011-02-26 11:08:46 +0000194 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
Andy Greenbfb051f2011-02-09 08:49:14 +0000195
196 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green623a98d2013-01-21 11:04:23 +0800197 wsi->u.hdr.name_buffer_pos = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000198 wsi->user_space = NULL;
199 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
Andy Green623a98d2013-01-21 11:04:23 +0800200 wsi->u.ws.pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +0000201 wsi->protocol = NULL;
Andy Greena71eafc2011-02-14 17:59:43 +0000202 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Green3182ece2013-01-20 17:08:31 +0800203#ifndef LWS_NO_EXTENSIONS
Andy Greend6e09112011-03-05 16:12:15 +0000204 wsi->count_active_extensions = 0;
Andy Green3182ece2013-01-20 17:08:31 +0800205#endif
Andy Greenbe93fef2011-02-14 20:25:43 +0000206#ifdef LWS_OPENSSL_SUPPORT
207 wsi->use_ssl = ssl_connection;
208#endif
209
Andy Greena41314f2011-05-23 10:00:03 +0100210 wsi->c_port = port;
211 wsi->c_address = strdup(address);
212
Andy Greenbe93fef2011-02-14 20:25:43 +0000213 /* copy parameters over so state machine has access */
214
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800215 wsi->c_path = (char *)malloc(strlen(path) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000216 if (wsi->c_path == NULL)
217 goto bail1;
218 strcpy(wsi->c_path, path);
Andy Green6ee372f2012-04-09 15:09:01 +0800219
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800220 wsi->c_host = (char *)malloc(strlen(host) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000221 if (wsi->c_host == NULL)
222 goto oom1;
223 strcpy(wsi->c_host, host);
Andy Green6ee372f2012-04-09 15:09:01 +0800224
Andy Green08d33922011-02-26 10:22:49 +0000225 if (origin) {
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800226 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
Andy Green08d33922011-02-26 10:22:49 +0000227 if (wsi->c_origin == NULL)
228 goto oom2;
Andy Green41c58032013-01-12 13:21:08 +0800229 strcpy(wsi->c_origin, origin);
Andy Green08d33922011-02-26 10:22:49 +0000230 } else
231 wsi->c_origin = NULL;
Andy Green6ee372f2012-04-09 15:09:01 +0800232
David Brooks993343b2012-04-20 12:16:52 +0800233 wsi->c_callback = NULL;
Andy Greenbe93fef2011-02-14 20:25:43 +0000234 if (protocol) {
David Brooks993343b2012-04-20 12:16:52 +0800235 const char *pc;
236 struct libwebsocket_protocols *pp;
237
Aaron Zinman4550f1d2013-01-10 12:35:18 +0800238 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
Andy Greenbe93fef2011-02-14 20:25:43 +0000239 if (wsi->c_protocol == NULL)
240 goto oom3;
David Brooks993343b2012-04-20 12:16:52 +0800241
Andy Greenbe93fef2011-02-14 20:25:43 +0000242 strcpy(wsi->c_protocol, protocol);
David Brooks993343b2012-04-20 12:16:52 +0800243
244 pc = protocol;
245 while (*pc && *pc != ',')
246 pc++;
247 n = pc - protocol;
248 pp = context->protocols;
249 while (pp->name && !wsi->c_callback) {
250 if (!strncmp(protocol, pp->name, n))
251 wsi->c_callback = pp->callback;
252 pp++;
253 }
Andy Greenbe93fef2011-02-14 20:25:43 +0000254 } else
255 wsi->c_protocol = NULL;
256
David Brooks993343b2012-04-20 12:16:52 +0800257 if (!wsi->c_callback)
258 wsi->c_callback = context->protocols[0].callback;
259
Andy Green4739e5c2011-01-22 12:51:57 +0000260 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
Andy Green68a672b2013-02-06 20:23:40 +0900261 wsi->u.hdr.hdrs[n].token = NULL;
262 wsi->u.hdr.hdrs[n].token_len = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000263 }
264
Andy Green3182ece2013-01-20 17:08:31 +0800265#ifndef LWS_NO_EXTENSIONS
Andy Green4739e5c2011-01-22 12:51:57 +0000266 /*
Andy Greena41314f2011-05-23 10:00:03 +0100267 * Check with each extension if it is able to route and proxy this
268 * connection for us. For example, an extension like x-google-mux
269 * can handle this and then we don't need an actual socket for this
270 * connection.
Andy Green9659f372011-01-27 22:01:43 +0000271 */
272
Andy Greena41314f2011-05-23 10:00:03 +0100273 handled = 0;
274 ext = context->extensions;
275 n = 0;
Andy Green9659f372011-01-27 22:01:43 +0000276
Andy Greena41314f2011-05-23 10:00:03 +0100277 while (ext && ext->callback && !handled) {
278 m = ext->callback(context, ext, wsi,
279 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
280 (void *)(long)n, (void *)address, port);
281 if (m)
282 handled = 1;
Andy Green9659f372011-01-27 22:01:43 +0000283
Andy Greena41314f2011-05-23 10:00:03 +0100284 ext++;
285 n++;
Andy Green9659f372011-01-27 22:01:43 +0000286 }
287
Andy Greena41314f2011-05-23 10:00:03 +0100288 if (handled) {
Andy Green43db0452013-01-10 19:50:35 +0800289 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
Andy Green5b9a4c02011-01-28 09:39:29 +0000290
Andy Greenbe93fef2011-02-14 20:25:43 +0000291 libwebsocket_set_timeout(wsi,
David Galeanoc9f1ff82013-01-09 18:01:23 +0800292 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
Andy Green5b9a4c02011-01-28 09:39:29 +0000293
Andy Greena41314f2011-05-23 10:00:03 +0100294 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
Andy Greenbe93fef2011-02-14 20:25:43 +0000295 return wsi;
Andy Green9659f372011-01-27 22:01:43 +0000296 }
Andy Green3182ece2013-01-20 17:08:31 +0800297#endif
Andy Green43db0452013-01-10 19:50:35 +0800298 lwsl_client("libwebsocket_client_connect: direct conn\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000299
Andy Greena41314f2011-05-23 10:00:03 +0100300 return __libwebsocket_client_connect_2(context, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000301
Andy Greenbe93fef2011-02-14 20:25:43 +0000302oom3:
Andy Green08d33922011-02-26 10:22:49 +0000303 if (wsi->c_origin)
304 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000305
306oom2:
307 free(wsi->c_host);
308
309oom1:
310 free(wsi->c_path);
311
Andy Green4739e5c2011-01-22 12:51:57 +0000312bail1:
313 free(wsi);
314
315 return NULL;
316}
David Brooks2c60d952012-04-20 12:19:01 +0800317
318
319/**
320 * libwebsocket_client_connect_extended() - Connect to another websocket server
321 * @context: Websocket context
322 * @address: Remote server address, eg, "myserver.com"
323 * @port: Port to connect to on the remote server, eg, 80
324 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
325 * signed certs
326 * @path: Websocket path on server
327 * @host: Hostname on server
328 * @origin: Socket origin name
329 * @protocol: Comma-separated list of protocols being asked for from
330 * the server, or just one. The server will pick the one it
331 * likes best.
332 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
333 * protocol supported, or the specific protocol ordinal
334 * @userdata: Pre-allocated user data
335 *
336 * This function creates a connection to a remote server
337 */
338
339struct libwebsocket *
340libwebsocket_client_connect_extended(struct libwebsocket_context *context,
341 const char *address,
342 int port,
343 int ssl_connection,
344 const char *path,
345 const char *host,
346 const char *origin,
347 const char *protocol,
348 int ietf_version_or_minus_one,
349 void *userdata)
350{
351 struct libwebsocket *ws =
352 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
353
354 if (ws && !ws->user_space && userdata)
355 ws->user_space = userdata ;
356
357 return ws ;
358 }