blob: 556b518f06759bcdc5f08365eb6667aca9d10f4a [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 Greencc012472011-11-07 19:53:23 +080019 debug("__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 Greencc012472011-11-07 19:53:23 +080044 debug("__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) {
48 fprintf(stderr, "Unable to get host name from %s\n",
49 wsi->c_address);
50 goto oom4;
51 }
52
53 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
54
55 if (wsi->sock < 0) {
56 fprintf(stderr, "Unable to open socket\n");
57 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 Greena41314f2011-05-23 10:00:03 +010082 fprintf(stderr, "Connect failed\n");
Tobias Maierd1db83c2012-05-30 12:46:42 +080083#ifdef WIN32
84 closesocket(wsi->sock);
85#else
86 close(wsi->sock);
87#endif
Andy Greena41314f2011-05-23 10:00:03 +010088 goto oom4;
89 }
90
Andy Greencc012472011-11-07 19:53:23 +080091 debug("connected\n");
Andy Greena41314f2011-05-23 10:00:03 +010092
93 /* into fd -> wsi hashtable */
94
95 insert_wsi(context, wsi);
96
97 /* into internal poll list */
98
99 context->fds[context->fds_count].fd = wsi->sock;
100 context->fds[context->fds_count].revents = 0;
101 context->fds[context->fds_count++].events = POLLIN;
102
103 /* external POLL support via protocol 0 */
104 context->protocols[0].callback(context, wsi,
105 LWS_CALLBACK_ADD_POLL_FD,
106 (void *)(long)wsi->sock, NULL, POLLIN);
107
108 /* we are connected to server, or proxy */
109
110 if (context->http_proxy_port) {
111
112 n = send(wsi->sock, pkt, plen, 0);
113 if (n < 0) {
114#ifdef WIN32
115 closesocket(wsi->sock);
116#else
117 close(wsi->sock);
118#endif
119 fprintf(stderr, "ERROR writing to proxy socket\n");
120 goto bail1;
121 }
122
123 libwebsocket_set_timeout(wsi,
124 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, 5);
125
126 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
127
128 return wsi;
129 }
130
131 /*
132 * provoke service to issue the handshake directly
133 * we need to do it this way because in the proxy case, this is the
134 * next state and executed only if and when we get a good proxy
135 * response inside the state machine
136 */
137
138 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
139 pfd.fd = wsi->sock;
140 pfd.revents = POLLIN;
David Galeano36750b82013-01-09 16:17:04 +0800141
142 n = libwebsocket_service_fd(context, &pfd);
143
144 if (n < 0)
Andy Green3928f612012-07-20 12:58:38 +0800145 goto oom4;
Andy Greena41314f2011-05-23 10:00:03 +0100146
David Galeano36750b82013-01-09 16:17:04 +0800147 if (n) /* returns 1 on failure after closing wsi */
148 return NULL;
149
Andy Greena41314f2011-05-23 10:00:03 +0100150 return wsi;
151
152oom4:
153 if (wsi->c_protocol)
154 free(wsi->c_protocol);
155
156 if (wsi->c_origin)
157 free(wsi->c_origin);
158
159 free(wsi->c_host);
160 free(wsi->c_path);
161
162bail1:
163 free(wsi);
164
165 return NULL;
166}
167
Andy Green90c7cbc2011-01-27 06:26:52 +0000168/**
169 * libwebsocket_client_connect() - Connect to another websocket server
Peter Hinz56885f32011-03-02 22:03:47 +0000170 * @context: Websocket context
Andy Green90c7cbc2011-01-27 06:26:52 +0000171 * @address: Remote server address, eg, "myserver.com"
172 * @port: Port to connect to on the remote server, eg, 80
173 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
174 * signed certs
175 * @path: Websocket path on server
176 * @host: Hostname on server
177 * @origin: Socket origin name
178 * @protocol: Comma-separated list of protocols being asked for from
179 * the server, or just one. The server will pick the one it
180 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +0000181 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
Andy Green6ee372f2012-04-09 15:09:01 +0800182 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +0000183 *
184 * This function creates a connection to a remote server
185 */
186
Andy Green4739e5c2011-01-22 12:51:57 +0000187struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +0000188libwebsocket_client_connect(struct libwebsocket_context *context,
Andy Green4739e5c2011-01-22 12:51:57 +0000189 const char *address,
190 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +0000191 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +0000192 const char *path,
193 const char *host,
194 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +0000195 const char *protocol,
196 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +0000197{
Andy Green4739e5c2011-01-22 12:51:57 +0000198 struct libwebsocket *wsi;
199 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100200 int m;
201 struct libwebsocket_extension *ext;
202 int handled;
Andy Greenbe93fef2011-02-14 20:25:43 +0000203#ifndef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000204 if (ssl_connection) {
205 fprintf(stderr, "libwebsockets not configured for ssl\n");
206 return NULL;
207 }
208#endif
Andy Green4739e5c2011-01-22 12:51:57 +0000209
Andy Green6964bb52011-01-23 16:50:33 +0000210 wsi = malloc(sizeof(struct libwebsocket));
Andy Greenbe93fef2011-02-14 20:25:43 +0000211 if (wsi == NULL)
212 goto bail1;
Andy Green4739e5c2011-01-22 12:51:57 +0000213
Darin Willitsc19456f2011-02-14 17:52:39 +0000214 memset(wsi, 0, sizeof *wsi);
215
Andy Greenbfb051f2011-02-09 08:49:14 +0000216 /* -1 means just use latest supported */
217
218 if (ietf_version_or_minus_one == -1)
Andy Green193306c2011-02-26 11:08:46 +0000219 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
Andy Greenbfb051f2011-02-09 08:49:14 +0000220
221 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green4739e5c2011-01-22 12:51:57 +0000222 wsi->name_buffer_pos = 0;
223 wsi->user_space = NULL;
224 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
225 wsi->pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +0000226 wsi->protocol = NULL;
Andy Greena71eafc2011-02-14 17:59:43 +0000227 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Greend6e09112011-03-05 16:12:15 +0000228 wsi->count_active_extensions = 0;
Andy Greenbe93fef2011-02-14 20:25:43 +0000229#ifdef LWS_OPENSSL_SUPPORT
230 wsi->use_ssl = ssl_connection;
231#endif
232
Andy Greena41314f2011-05-23 10:00:03 +0100233 wsi->c_port = port;
234 wsi->c_address = strdup(address);
235
Andy Greenbe93fef2011-02-14 20:25:43 +0000236 /* copy parameters over so state machine has access */
237
238 wsi->c_path = malloc(strlen(path) + 1);
239 if (wsi->c_path == NULL)
240 goto bail1;
241 strcpy(wsi->c_path, path);
Andy Green6ee372f2012-04-09 15:09:01 +0800242
Andy Greenbe93fef2011-02-14 20:25:43 +0000243 wsi->c_host = malloc(strlen(host) + 1);
244 if (wsi->c_host == NULL)
245 goto oom1;
246 strcpy(wsi->c_host, host);
Andy Green6ee372f2012-04-09 15:09:01 +0800247
Andy Green08d33922011-02-26 10:22:49 +0000248 if (origin) {
249 wsi->c_origin = malloc(strlen(origin) + 1);
250 strcpy(wsi->c_origin, origin);
251 if (wsi->c_origin == NULL)
252 goto oom2;
253 } else
254 wsi->c_origin = NULL;
Andy Green6ee372f2012-04-09 15:09:01 +0800255
David Brooks993343b2012-04-20 12:16:52 +0800256 wsi->c_callback = NULL;
Andy Greenbe93fef2011-02-14 20:25:43 +0000257 if (protocol) {
David Brooks993343b2012-04-20 12:16:52 +0800258 const char *pc;
259 struct libwebsocket_protocols *pp;
260
Andy Greenbe93fef2011-02-14 20:25:43 +0000261 wsi->c_protocol = malloc(strlen(protocol) + 1);
262 if (wsi->c_protocol == NULL)
263 goto oom3;
David Brooks993343b2012-04-20 12:16:52 +0800264
Andy Greenbe93fef2011-02-14 20:25:43 +0000265 strcpy(wsi->c_protocol, protocol);
David Brooks993343b2012-04-20 12:16:52 +0800266
267 pc = protocol;
268 while (*pc && *pc != ',')
269 pc++;
270 n = pc - protocol;
271 pp = context->protocols;
272 while (pp->name && !wsi->c_callback) {
273 if (!strncmp(protocol, pp->name, n))
274 wsi->c_callback = pp->callback;
275 pp++;
276 }
Andy Greenbe93fef2011-02-14 20:25:43 +0000277 } else
278 wsi->c_protocol = NULL;
279
David Brooks993343b2012-04-20 12:16:52 +0800280 if (!wsi->c_callback)
281 wsi->c_callback = context->protocols[0].callback;
282
Andy Greenbfb051f2011-02-09 08:49:14 +0000283 /* set up appropriate masking */
284
285 wsi->xor_mask = xor_no_mask;
286
287 switch (wsi->ietf_spec_revision) {
Andy Greeneeaacb32011-03-01 20:44:24 +0000288 case 0:
289 break;
Andy Greenbfb051f2011-02-09 08:49:14 +0000290 case 4:
291 wsi->xor_mask = xor_mask_04;
292 break;
293 case 5:
Andy Green9514bf82011-02-26 11:13:56 +0000294 case 6:
Andy Green33872cd2011-04-24 05:49:44 +0100295 case 7:
Andy Greend85cb202011-09-25 09:32:54 +0100296 case 8:
297 case 13:
Andy Greenbfb051f2011-02-09 08:49:14 +0000298 wsi->xor_mask = xor_mask_05;
299 break;
300 default:
301 fprintf(stderr,
302 "Client ietf version %d not supported\n",
303 wsi->ietf_spec_revision);
Andy Greenbe93fef2011-02-14 20:25:43 +0000304 goto oom4;
Andy Greenbfb051f2011-02-09 08:49:14 +0000305 }
306
307 /* force no mask if he asks for that though */
308
Peter Hinz56885f32011-03-02 22:03:47 +0000309 if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
Andy Greenbfb051f2011-02-09 08:49:14 +0000310 wsi->xor_mask = xor_no_mask;
311
Andy Green4739e5c2011-01-22 12:51:57 +0000312 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
313 wsi->utf8_token[n].token = NULL;
314 wsi->utf8_token[n].token_len = 0;
315 }
316
317 /*
Andy Greena41314f2011-05-23 10:00:03 +0100318 * Check with each extension if it is able to route and proxy this
319 * connection for us. For example, an extension like x-google-mux
320 * can handle this and then we don't need an actual socket for this
321 * connection.
Andy Green9659f372011-01-27 22:01:43 +0000322 */
323
Andy Greena41314f2011-05-23 10:00:03 +0100324 handled = 0;
325 ext = context->extensions;
326 n = 0;
Andy Green9659f372011-01-27 22:01:43 +0000327
Andy Greena41314f2011-05-23 10:00:03 +0100328 while (ext && ext->callback && !handled) {
329 m = ext->callback(context, ext, wsi,
330 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
331 (void *)(long)n, (void *)address, port);
332 if (m)
333 handled = 1;
Andy Green9659f372011-01-27 22:01:43 +0000334
Andy Greena41314f2011-05-23 10:00:03 +0100335 ext++;
336 n++;
Andy Green9659f372011-01-27 22:01:43 +0000337 }
338
Andy Greena41314f2011-05-23 10:00:03 +0100339 if (handled) {
Andy Greencc012472011-11-07 19:53:23 +0800340 debug("libwebsocket_client_connect: ext handling conn\n");
Andy Green5b9a4c02011-01-28 09:39:29 +0000341
Andy Greenbe93fef2011-02-14 20:25:43 +0000342 libwebsocket_set_timeout(wsi,
Andy Greena41314f2011-05-23 10:00:03 +0100343 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, 5);
Andy Green5b9a4c02011-01-28 09:39:29 +0000344
Andy Greena41314f2011-05-23 10:00:03 +0100345 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
Andy Greenbe93fef2011-02-14 20:25:43 +0000346 return wsi;
Andy Green9659f372011-01-27 22:01:43 +0000347 }
348
Andy Greencc012472011-11-07 19:53:23 +0800349 debug("libwebsocket_client_connect: direct conn\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000350
Andy Greena41314f2011-05-23 10:00:03 +0100351 return __libwebsocket_client_connect_2(context, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000352
Andy Green4739e5c2011-01-22 12:51:57 +0000353
Andy Greenbe93fef2011-02-14 20:25:43 +0000354oom4:
355 if (wsi->c_protocol)
356 free(wsi->c_protocol);
Andy Green4739e5c2011-01-22 12:51:57 +0000357
Andy Greenbe93fef2011-02-14 20:25:43 +0000358oom3:
Andy Green08d33922011-02-26 10:22:49 +0000359 if (wsi->c_origin)
360 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000361
362oom2:
363 free(wsi->c_host);
364
365oom1:
366 free(wsi->c_path);
367
Andy Green4739e5c2011-01-22 12:51:57 +0000368bail1:
369 free(wsi);
370
371 return NULL;
372}
David Brooks2c60d952012-04-20 12:19:01 +0800373
374
375/**
376 * libwebsocket_client_connect_extended() - Connect to another websocket server
377 * @context: Websocket context
378 * @address: Remote server address, eg, "myserver.com"
379 * @port: Port to connect to on the remote server, eg, 80
380 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
381 * signed certs
382 * @path: Websocket path on server
383 * @host: Hostname on server
384 * @origin: Socket origin name
385 * @protocol: Comma-separated list of protocols being asked for from
386 * the server, or just one. The server will pick the one it
387 * likes best.
388 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
389 * protocol supported, or the specific protocol ordinal
390 * @userdata: Pre-allocated user data
391 *
392 * This function creates a connection to a remote server
393 */
394
395struct libwebsocket *
396libwebsocket_client_connect_extended(struct libwebsocket_context *context,
397 const char *address,
398 int port,
399 int ssl_connection,
400 const char *path,
401 const char *host,
402 const char *origin,
403 const char *protocol,
404 int ietf_version_or_minus_one,
405 void *userdata)
406{
407 struct libwebsocket *ws =
408 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
409
410 if (ws && !ws->user_space && userdata)
411 ws->user_space = userdata ;
412
413 return ws ;
414 }