blob: d41777ce15940a5d831ea23f378f2d36be58f806 [file] [log] [blame]
Andy Green4739e5c2011-01-22 12:51:57 +00001#include "private-libwebsockets.h"
2#include <netdb.h>
3
4
Andy Greena41314f2011-05-23 10:00:03 +01005struct libwebsocket * __libwebsocket_client_connect_2(
6 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;
17
18 fprintf(stderr, "__libwebsocket_client_connect_2\n");
19
20 wsi->candidate_children_list = NULL;
21
22 /*
23 * proxy?
24 */
25
26 if (context->http_proxy_port) {
27 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
28 "User-agent: libwebsockets\x0d\x0a"
29/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
30 "\x0d\x0a", wsi->c_address, wsi->c_port);
31
32 /* OK from now on we talk via the proxy */
33
34 free(wsi->c_address);
35 wsi->c_address = strdup(context->http_proxy_address);
36 wsi->c_port = context->http_proxy_port;
37 }
38
39 /*
40 * prepare the actual connection (to the proxy, if any)
41 */
42
43 server_hostent = gethostbyname(wsi->c_address);
44 if (server_hostent == NULL) {
45 fprintf(stderr, "Unable to get host name from %s\n",
46 wsi->c_address);
47 goto oom4;
48 }
49
50 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
51
52 if (wsi->sock < 0) {
53 fprintf(stderr, "Unable to open socket\n");
54 goto oom4;
55 }
56
57 server_addr.sin_family = AF_INET;
58 server_addr.sin_port = htons(wsi->c_port);
59 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
60 bzero(&server_addr.sin_zero, 8);
61
62 /* Disable Nagle */
63 setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt));
64
65 /* Set receiving timeout */
66 tv.tv_sec = 0;
67 tv.tv_usec = 100 * 1000;
68 setsockopt(wsi->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv);
69
70 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
71 sizeof(struct sockaddr)) == -1) {
72 fprintf(stderr, "Connect failed\n");
73 goto oom4;
74 }
75
76 fprintf(stderr, "connected\n");
77
78 /* into fd -> wsi hashtable */
79
80 insert_wsi(context, wsi);
81
82 /* into internal poll list */
83
84 context->fds[context->fds_count].fd = wsi->sock;
85 context->fds[context->fds_count].revents = 0;
86 context->fds[context->fds_count++].events = POLLIN;
87
88 /* external POLL support via protocol 0 */
89 context->protocols[0].callback(context, wsi,
90 LWS_CALLBACK_ADD_POLL_FD,
91 (void *)(long)wsi->sock, NULL, POLLIN);
92
93 /* we are connected to server, or proxy */
94
95 if (context->http_proxy_port) {
96
97 n = send(wsi->sock, pkt, plen, 0);
98 if (n < 0) {
99#ifdef WIN32
100 closesocket(wsi->sock);
101#else
102 close(wsi->sock);
103#endif
104 fprintf(stderr, "ERROR writing to proxy socket\n");
105 goto bail1;
106 }
107
108 libwebsocket_set_timeout(wsi,
109 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, 5);
110
111 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
112
113 return wsi;
114 }
115
116 /*
117 * provoke service to issue the handshake directly
118 * we need to do it this way because in the proxy case, this is the
119 * next state and executed only if and when we get a good proxy
120 * response inside the state machine
121 */
122
123 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
124 pfd.fd = wsi->sock;
125 pfd.revents = POLLIN;
126 libwebsocket_service_fd(context, &pfd);
127
128 return wsi;
129
130oom4:
131 if (wsi->c_protocol)
132 free(wsi->c_protocol);
133
134 if (wsi->c_origin)
135 free(wsi->c_origin);
136
137 free(wsi->c_host);
138 free(wsi->c_path);
139
140bail1:
141 free(wsi);
142
143 return NULL;
144}
145
Andy Green90c7cbc2011-01-27 06:26:52 +0000146/**
147 * libwebsocket_client_connect() - Connect to another websocket server
Peter Hinz56885f32011-03-02 22:03:47 +0000148 * @context: Websocket context
Andy Green90c7cbc2011-01-27 06:26:52 +0000149 * @address: Remote server address, eg, "myserver.com"
150 * @port: Port to connect to on the remote server, eg, 80
151 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
152 * signed certs
153 * @path: Websocket path on server
154 * @host: Hostname on server
155 * @origin: Socket origin name
156 * @protocol: Comma-separated list of protocols being asked for from
157 * the server, or just one. The server will pick the one it
158 * likes best.
Andy Greenbfb051f2011-02-09 08:49:14 +0000159 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
160 * protocol supported, or the specific protocol ordinal
Andy Green90c7cbc2011-01-27 06:26:52 +0000161 *
162 * This function creates a connection to a remote server
163 */
164
Andy Green4739e5c2011-01-22 12:51:57 +0000165struct libwebsocket *
Peter Hinz56885f32011-03-02 22:03:47 +0000166libwebsocket_client_connect(struct libwebsocket_context *context,
Andy Green4739e5c2011-01-22 12:51:57 +0000167 const char *address,
168 int port,
Andy Green90c7cbc2011-01-27 06:26:52 +0000169 int ssl_connection,
Andy Green4739e5c2011-01-22 12:51:57 +0000170 const char *path,
171 const char *host,
172 const char *origin,
Andy Greenbfb051f2011-02-09 08:49:14 +0000173 const char *protocol,
174 int ietf_version_or_minus_one)
Andy Green4739e5c2011-01-22 12:51:57 +0000175{
Andy Green4739e5c2011-01-22 12:51:57 +0000176 struct libwebsocket *wsi;
177 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100178 int m;
179 struct libwebsocket_extension *ext;
180 int handled;
Andy Greenbe93fef2011-02-14 20:25:43 +0000181#ifndef LWS_OPENSSL_SUPPORT
Andy Green90c7cbc2011-01-27 06:26:52 +0000182 if (ssl_connection) {
183 fprintf(stderr, "libwebsockets not configured for ssl\n");
184 return NULL;
185 }
186#endif
Andy Green4739e5c2011-01-22 12:51:57 +0000187
Andy Green6964bb52011-01-23 16:50:33 +0000188 wsi = malloc(sizeof(struct libwebsocket));
Andy Greenbe93fef2011-02-14 20:25:43 +0000189 if (wsi == NULL)
190 goto bail1;
Andy Green4739e5c2011-01-22 12:51:57 +0000191
Darin Willitsc19456f2011-02-14 17:52:39 +0000192 memset(wsi, 0, sizeof *wsi);
193
Andy Greenbfb051f2011-02-09 08:49:14 +0000194 /* -1 means just use latest supported */
195
196 if (ietf_version_or_minus_one == -1)
Andy Green193306c2011-02-26 11:08:46 +0000197 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
Andy Greenbfb051f2011-02-09 08:49:14 +0000198
199 wsi->ietf_spec_revision = ietf_version_or_minus_one;
Andy Green4739e5c2011-01-22 12:51:57 +0000200 wsi->name_buffer_pos = 0;
201 wsi->user_space = NULL;
202 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
203 wsi->pings_vs_pongs = 0;
Andy Green927eb7b2011-02-01 08:52:55 +0000204 wsi->protocol = NULL;
Andy Greena71eafc2011-02-14 17:59:43 +0000205 wsi->pending_timeout = NO_PENDING_TIMEOUT;
Andy Greend6e09112011-03-05 16:12:15 +0000206 wsi->count_active_extensions = 0;
Andy Greenbe93fef2011-02-14 20:25:43 +0000207#ifdef LWS_OPENSSL_SUPPORT
208 wsi->use_ssl = ssl_connection;
209#endif
210
Andy Greena41314f2011-05-23 10:00:03 +0100211 wsi->c_port = port;
212 wsi->c_address = strdup(address);
213
Andy Greenbe93fef2011-02-14 20:25:43 +0000214 /* copy parameters over so state machine has access */
215
216 wsi->c_path = malloc(strlen(path) + 1);
217 if (wsi->c_path == NULL)
218 goto bail1;
219 strcpy(wsi->c_path, path);
220 wsi->c_host = malloc(strlen(host) + 1);
221 if (wsi->c_host == NULL)
222 goto oom1;
223 strcpy(wsi->c_host, host);
Andy Green08d33922011-02-26 10:22:49 +0000224 if (origin) {
225 wsi->c_origin = malloc(strlen(origin) + 1);
226 strcpy(wsi->c_origin, origin);
227 if (wsi->c_origin == NULL)
228 goto oom2;
229 } else
230 wsi->c_origin = NULL;
Andy Greenbe93fef2011-02-14 20:25:43 +0000231 if (protocol) {
232 wsi->c_protocol = malloc(strlen(protocol) + 1);
233 if (wsi->c_protocol == NULL)
234 goto oom3;
235 strcpy(wsi->c_protocol, protocol);
236 } else
237 wsi->c_protocol = NULL;
238
Andy Green4739e5c2011-01-22 12:51:57 +0000239
Andy Greenbfb051f2011-02-09 08:49:14 +0000240 /* set up appropriate masking */
241
242 wsi->xor_mask = xor_no_mask;
243
244 switch (wsi->ietf_spec_revision) {
Andy Greeneeaacb32011-03-01 20:44:24 +0000245 case 0:
246 break;
Andy Greenbfb051f2011-02-09 08:49:14 +0000247 case 4:
248 wsi->xor_mask = xor_mask_04;
249 break;
250 case 5:
Andy Green9514bf82011-02-26 11:13:56 +0000251 case 6:
Andy Green33872cd2011-04-24 05:49:44 +0100252 case 7:
Andy Greenbfb051f2011-02-09 08:49:14 +0000253 wsi->xor_mask = xor_mask_05;
254 break;
255 default:
256 fprintf(stderr,
257 "Client ietf version %d not supported\n",
258 wsi->ietf_spec_revision);
Andy Greenbe93fef2011-02-14 20:25:43 +0000259 goto oom4;
Andy Greenbfb051f2011-02-09 08:49:14 +0000260 }
261
262 /* force no mask if he asks for that though */
263
Peter Hinz56885f32011-03-02 22:03:47 +0000264 if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
Andy Greenbfb051f2011-02-09 08:49:14 +0000265 wsi->xor_mask = xor_no_mask;
266
Andy Green4739e5c2011-01-22 12:51:57 +0000267 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
268 wsi->utf8_token[n].token = NULL;
269 wsi->utf8_token[n].token_len = 0;
270 }
271
272 /*
Andy Greena41314f2011-05-23 10:00:03 +0100273 * Check with each extension if it is able to route and proxy this
274 * connection for us. For example, an extension like x-google-mux
275 * can handle this and then we don't need an actual socket for this
276 * connection.
Andy Green9659f372011-01-27 22:01:43 +0000277 */
278
Andy Greena41314f2011-05-23 10:00:03 +0100279 handled = 0;
280 ext = context->extensions;
281 n = 0;
Andy Green9659f372011-01-27 22:01:43 +0000282
Andy Greena41314f2011-05-23 10:00:03 +0100283 while (ext && ext->callback && !handled) {
284 m = ext->callback(context, ext, wsi,
285 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
286 (void *)(long)n, (void *)address, port);
287 if (m)
288 handled = 1;
Andy Green9659f372011-01-27 22:01:43 +0000289
Andy Greena41314f2011-05-23 10:00:03 +0100290 ext++;
291 n++;
Andy Green9659f372011-01-27 22:01:43 +0000292 }
293
Andy Greena41314f2011-05-23 10:00:03 +0100294 if (handled) {
295 fprintf(stderr, "libwebsocket_client_connect: "
296 "ext handling conn\n");
Andy Green5b9a4c02011-01-28 09:39:29 +0000297
Andy Greenbe93fef2011-02-14 20:25:43 +0000298 libwebsocket_set_timeout(wsi,
Andy Greena41314f2011-05-23 10:00:03 +0100299 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, 5);
Andy Green5b9a4c02011-01-28 09:39:29 +0000300
Andy Greena41314f2011-05-23 10:00:03 +0100301 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
Andy Greenbe93fef2011-02-14 20:25:43 +0000302 return wsi;
Andy Green9659f372011-01-27 22:01:43 +0000303 }
304
Andy Greena41314f2011-05-23 10:00:03 +0100305 fprintf(stderr, "libwebsocket_client_connect: direct conn\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000306
Andy Greena41314f2011-05-23 10:00:03 +0100307 return __libwebsocket_client_connect_2(context, wsi);
Andy Green4739e5c2011-01-22 12:51:57 +0000308
Andy Green4739e5c2011-01-22 12:51:57 +0000309
Andy Greenbe93fef2011-02-14 20:25:43 +0000310oom4:
311 if (wsi->c_protocol)
312 free(wsi->c_protocol);
Andy Green4739e5c2011-01-22 12:51:57 +0000313
Andy Greenbe93fef2011-02-14 20:25:43 +0000314oom3:
Andy Green08d33922011-02-26 10:22:49 +0000315 if (wsi->c_origin)
316 free(wsi->c_origin);
Andy Greenbe93fef2011-02-14 20:25:43 +0000317
318oom2:
319 free(wsi->c_host);
320
321oom1:
322 free(wsi->c_path);
323
Andy Green4739e5c2011-01-22 12:51:57 +0000324bail1:
325 free(wsi);
326
327 return NULL;
328}