blob: 58761ca798f836e14c6bbcc2292f0f9773d4f210 [file] [log] [blame]
Andy Green4739e5c2011-01-22 12:51:57 +00001#include "private-libwebsockets.h"
2#include <netdb.h>
3
4
Andy Green6ee372f2012-04-09 15:09:01 +08005struct libwebsocket *__libwebsocket_client_connect_2(
Andy Greena41314f2011-05-23 10:00:03 +01006 struct libwebsocket_context *context,
7 struct libwebsocket *wsi
8) {
9 struct pollfd pfd;
10 struct timeval tv;
11 struct hostent *server_hostent;
12 struct sockaddr_in server_addr;
13 int n;
14 int plen = 0;
15 char pkt[512];
16 int opt = 1;
M Kf2431152011-09-25 10:34:35 +010017#if defined(__APPLE__)
Andy Green6ee372f2012-04-09 15:09:01 +080018 struct protoent *tcp_proto;
M Kf2431152011-09-25 10:34:35 +010019#endif
Andy Greena41314f2011-05-23 10:00:03 +010020
Andy Greencc012472011-11-07 19:53:23 +080021 debug("__libwebsocket_client_connect_2\n");
Andy Greena41314f2011-05-23 10:00:03 +010022
23 wsi->candidate_children_list = NULL;
24
25 /*
26 * proxy?
27 */
28
29 if (context->http_proxy_port) {
30 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
31 "User-agent: libwebsockets\x0d\x0a"
32/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
33 "\x0d\x0a", wsi->c_address, wsi->c_port);
34
35 /* OK from now on we talk via the proxy */
36
37 free(wsi->c_address);
38 wsi->c_address = strdup(context->http_proxy_address);
39 wsi->c_port = context->http_proxy_port;
40 }
41
42 /*
43 * prepare the actual connection (to the proxy, if any)
44 */
45
Andy Greencc012472011-11-07 19:53:23 +080046 debug("__libwebsocket_client_connect_2: address %s", wsi->c_address);
Andy Green66a16f32011-05-24 22:07:45 +010047
Andy Greena41314f2011-05-23 10:00:03 +010048 server_hostent = gethostbyname(wsi->c_address);
49 if (server_hostent == NULL) {
50 fprintf(stderr, "Unable to get host name from %s\n",
51 wsi->c_address);
52 goto oom4;
53 }
54
55 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
56
57 if (wsi->sock < 0) {
58 fprintf(stderr, "Unable to open socket\n");
59 goto oom4;
60 }
61
62 server_addr.sin_family = AF_INET;
63 server_addr.sin_port = htons(wsi->c_port);
64 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
65 bzero(&server_addr.sin_zero, 8);
66
67 /* Disable Nagle */
M Kf2431152011-09-25 10:34:35 +010068#if !defined(__APPLE__)
Andy Green6ee372f2012-04-09 15:09:01 +080069 setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY,
70 (const void *)&opt, sizeof(opt));
M Kf2431152011-09-25 10:34:35 +010071#else
Andy Green6ee372f2012-04-09 15:09:01 +080072 tcp_proto = getprotobyname("TCP");
73 setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY,
74 &opt, sizeof(opt));
M Kf2431152011-09-25 10:34:35 +010075#endif
Andy Greena41314f2011-05-23 10:00:03 +010076
77 /* Set receiving timeout */
78 tv.tv_sec = 0;
79 tv.tv_usec = 100 * 1000;
80 setsockopt(wsi->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv);
81
82 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
Andy Green6ee372f2012-04-09 15:09:01 +080083 sizeof(struct sockaddr)) == -1) {
Andy Greena41314f2011-05-23 10:00:03 +010084 fprintf(stderr, "Connect failed\n");
85 goto oom4;
86 }
87
Andy Greencc012472011-11-07 19:53:23 +080088 debug("connected\n");
Andy Greena41314f2011-05-23 10:00:03 +010089
90 /* into fd -> wsi hashtable */
91
92 insert_wsi(context, wsi);
93
94 /* into internal poll list */
95
96 context->fds[context->fds_count].fd = wsi->sock;
97 context->fds[context->fds_count].revents = 0;
98 context->fds[context->fds_count++].events = POLLIN;
99
100 /* external POLL support via protocol 0 */
101 context->protocols[0].callback(context, wsi,
102 LWS_CALLBACK_ADD_POLL_FD,
103 (void *)(long)wsi->sock, NULL, POLLIN);
104
105 /* we are connected to server, or proxy */
106
107 if (context->http_proxy_port) {
108
109 n = send(wsi->sock, pkt, plen, 0);
110 if (n < 0) {
111#ifdef WIN32
112 closesocket(wsi->sock);
113#else
114 close(wsi->sock);
115#endif
116 fprintf(stderr, "ERROR writing to proxy socket\n");
117 goto bail1;
118 }
119
120 libwebsocket_set_timeout(wsi,
121 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, 5);
122
123 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
124
125 return wsi;
126 }
127
128 /*
129 * provoke service to issue the handshake directly
130 * we need to do it this way because in the proxy case, this is the
131 * next state and executed only if and when we get a good proxy
132 * response inside the state machine
133 */
134
135 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
136 pfd.fd = wsi->sock;
137 pfd.revents = POLLIN;
138 libwebsocket_service_fd(context, &pfd);
139
140 return wsi;
141
142oom4:
143 if (wsi->c_protocol)
144 free(wsi->c_protocol);
145
146 if (wsi->c_origin)
147 free(wsi->c_origin);
148
149 free(wsi->c_host);
150 free(wsi->c_path);
151
152bail1:
153 free(wsi);
154
155 return NULL;
156}
157
Andy Green90c7cbc2011-01-27 06:26:52 +0000158/**
159 * libwebsocket_client_connect() - Connect to another websocket server
Peter Hinz56885f32011-03-02 22:03:47 +0000160 * @context: Websocket context
Andy Green90c7cbc2011-01-27 06:26:52 +0000161 * @address: Remote server address, eg, "myserver.com"
162 * @port: Port to connect to on the remote server, eg, 80
163 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
164 * signed certs
165 * @path: Websocket path on server
166 * @host: Hostname on server
167 * @origin: Socket origin name
168 * @protocol: Comma-separated list of protocols being asked for from
169 * the server, or just one. The server will pick the one it
170 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +0000171 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
Andy Green6ee372f2012-04-09 15:09:01 +0800172 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +0000173 *
174 * This function creates a connection to a remote server
175 */
176
Andy Green4739e5c2011-01-22 12:51:57 +0000177struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +0000178libwebsocket_client_connect(struct libwebsocket_context *context,
Andy Green4739e5c2011-01-22 12:51:57 +0000179 const char *address,
180 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +0000181 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +0000182 const char *path,
183 const char *host,
184 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +0000185 const char *protocol,
186 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +0000187{
Andy Green4739e5c2011-01-22 12:51:57 +0000188 struct libwebsocket *wsi;
189 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100190 int m;
191 struct libwebsocket_extension *ext;
192 int handled;
Andy Greenbe93fef2011-02-14 20:25:43 +0000193#ifndef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000194 if (ssl_connection) {
195 fprintf(stderr, "libwebsockets not configured for ssl\n");
196 return NULL;
197 }
198#endif
Andy Green4739e5c2011-01-22 12:51:57 +0000199
Andy Green6964bb52011-01-23 16:50:33 +0000200 wsi = malloc(sizeof(struct libwebsocket));
Andy Greenbe93fef2011-02-14 20:25:43 +0000201 if (wsi == NULL)
202 goto bail1;
Andy Green4739e5c2011-01-22 12:51:57 +0000203
Darin Willitsc19456f2011-02-14 17:52:39 +0000204 memset(wsi, 0, sizeof *wsi);
205
Andy Greenbfb051f2011-02-09 08:49:14 +0000206 /* -1 means just use latest supported */
207
208 if (ietf_version_or_minus_one == -1)
Andy Green193306c2011-02-26 11:08:46 +0000209 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
Andy Greenbfb051f2011-02-09 08:49:14 +0000210
211 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green4739e5c2011-01-22 12:51:57 +0000212 wsi->name_buffer_pos = 0;
213 wsi->user_space = NULL;
214 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
215 wsi->pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +0000216 wsi->protocol = NULL;
Andy Greena71eafc2011-02-14 17:59:43 +0000217 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Greend6e09112011-03-05 16:12:15 +0000218 wsi->count_active_extensions = 0;
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
228 wsi->c_path = malloc(strlen(path) + 1);
229 if (wsi->c_path == NULL)
230 goto bail1;
231 strcpy(wsi->c_path, path);
Andy Green6ee372f2012-04-09 15:09:01 +0800232
Andy Greenbe93fef2011-02-14 20:25:43 +0000233 wsi->c_host = malloc(strlen(host) + 1);
234 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) {
239 wsi->c_origin = malloc(strlen(origin) + 1);
240 strcpy(wsi->c_origin, origin);
241 if (wsi->c_origin == NULL)
242 goto oom2;
243 } else
244 wsi->c_origin = NULL;
Andy Green6ee372f2012-04-09 15:09:01 +0800245
Andy Greenbe93fef2011-02-14 20:25:43 +0000246 if (protocol) {
247 wsi->c_protocol = malloc(strlen(protocol) + 1);
248 if (wsi->c_protocol == NULL)
249 goto oom3;
250 strcpy(wsi->c_protocol, protocol);
251 } else
252 wsi->c_protocol = NULL;
253
Andy Greenbfb051f2011-02-09 08:49:14 +0000254 /* set up appropriate masking */
255
256 wsi->xor_mask = xor_no_mask;
257
258 switch (wsi->ietf_spec_revision) {
Andy Greeneeaacb32011-03-01 20:44:24 +0000259 case 0:
260 break;
Andy Greenbfb051f2011-02-09 08:49:14 +0000261 case 4:
262 wsi->xor_mask = xor_mask_04;
263 break;
264 case 5:
Andy Green9514bf82011-02-26 11:13:56 +0000265 case 6:
Andy Green33872cd2011-04-24 05:49:44 +0100266 case 7:
Andy Greend85cb202011-09-25 09:32:54 +0100267 case 8:
268 case 13:
Andy Greenbfb051f2011-02-09 08:49:14 +0000269 wsi->xor_mask = xor_mask_05;
270 break;
271 default:
272 fprintf(stderr,
273 "Client ietf version %d not supported\n",
274 wsi->ietf_spec_revision);
Andy Greenbe93fef2011-02-14 20:25:43 +0000275 goto oom4;
Andy Greenbfb051f2011-02-09 08:49:14 +0000276 }
277
278 /* force no mask if he asks for that though */
279
Peter Hinz56885f32011-03-02 22:03:47 +0000280 if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
Andy Greenbfb051f2011-02-09 08:49:14 +0000281 wsi->xor_mask = xor_no_mask;
282
Andy Green4739e5c2011-01-22 12:51:57 +0000283 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
284 wsi->utf8_token[n].token = NULL;
285 wsi->utf8_token[n].token_len = 0;
286 }
287
288 /*
Andy Greena41314f2011-05-23 10:00:03 +0100289 * Check with each extension if it is able to route and proxy this
290 * connection for us. For example, an extension like x-google-mux
291 * can handle this and then we don't need an actual socket for this
292 * connection.
Andy Green9659f372011-01-27 22:01:43 +0000293 */
294
Andy Greena41314f2011-05-23 10:00:03 +0100295 handled = 0;
296 ext = context->extensions;
297 n = 0;
Andy Green9659f372011-01-27 22:01:43 +0000298
Andy Greena41314f2011-05-23 10:00:03 +0100299 while (ext && ext->callback && !handled) {
300 m = ext->callback(context, ext, wsi,
301 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
302 (void *)(long)n, (void *)address, port);
303 if (m)
304 handled = 1;
Andy Green9659f372011-01-27 22:01:43 +0000305
Andy Greena41314f2011-05-23 10:00:03 +0100306 ext++;
307 n++;
Andy Green9659f372011-01-27 22:01:43 +0000308 }
309
Andy Greena41314f2011-05-23 10:00:03 +0100310 if (handled) {
Andy Greencc012472011-11-07 19:53:23 +0800311 debug("libwebsocket_client_connect: ext handling conn\n");
Andy Green5b9a4c02011-01-28 09:39:29 +0000312
Andy Greenbe93fef2011-02-14 20:25:43 +0000313 libwebsocket_set_timeout(wsi,
Andy Greena41314f2011-05-23 10:00:03 +0100314 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, 5);
Andy Green5b9a4c02011-01-28 09:39:29 +0000315
Andy Greena41314f2011-05-23 10:00:03 +0100316 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
Andy Greenbe93fef2011-02-14 20:25:43 +0000317 return wsi;
Andy Green9659f372011-01-27 22:01:43 +0000318 }
319
Andy Greencc012472011-11-07 19:53:23 +0800320 debug("libwebsocket_client_connect: direct conn\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000321
Andy Greena41314f2011-05-23 10:00:03 +0100322 return __libwebsocket_client_connect_2(context, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000323
Andy Green4739e5c2011-01-22 12:51:57 +0000324
Andy Greenbe93fef2011-02-14 20:25:43 +0000325oom4:
326 if (wsi->c_protocol)
327 free(wsi->c_protocol);
Andy Green4739e5c2011-01-22 12:51:57 +0000328
Andy Greenbe93fef2011-02-14 20:25:43 +0000329oom3:
Andy Green08d33922011-02-26 10:22:49 +0000330 if (wsi->c_origin)
331 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000332
333oom2:
334 free(wsi->c_host);
335
336oom1:
337 free(wsi->c_path);
338
Andy Green4739e5c2011-01-22 12:51:57 +0000339bail1:
340 free(wsi);
341
342 return NULL;
343}