9292c031677c750b1811cde21829276915d31b2f
[profile/ivi/libwebsockets.git] / lib / client-handshake.c
1 #include "private-libwebsockets.h"
2
3 struct libwebsocket *__libwebsocket_client_connect_2(
4         struct libwebsocket_context *context,
5         struct libwebsocket *wsi
6 ) {
7         struct pollfd pfd;
8         struct hostent *server_hostent;
9         struct sockaddr_in server_addr;
10         int n;
11         int plen = 0;
12
13         lwsl_client("__libwebsocket_client_connect_2\n");
14 #ifndef LWS_NO_EXTENSIONS
15         wsi->candidate_children_list = NULL;
16 #endif
17
18         /*
19          * proxy?
20          */
21
22         if (context->http_proxy_port) {
23                 plen = sprintf((char *)context->service_buffer,
24                         "CONNECT %s:%u HTTP/1.0\x0d\x0a"
25                         "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
40         lwsl_client("__libwebsocket_client_connect_2: address %s\n",
41                                                                 wsi->c_address);
42
43         server_hostent = gethostbyname(wsi->c_address);
44         if (server_hostent == NULL) {
45                 lwsl_err("Unable to get host name from %s\n", wsi->c_address);
46                 goto oom4;
47         }
48
49         wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
50
51         if (wsi->sock < 0) {
52                 lwsl_warn("Unable to open socket\n");
53                 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
61         if (connect(wsi->sock, (struct sockaddr *)&server_addr,
62                                              sizeof(struct sockaddr)) == -1)  {
63                 lwsl_debug("Connect failed\n");
64                 compatible_close(wsi->sock);
65                 goto oom4;
66         }
67
68         lwsl_client("connected\n");
69
70         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
76         insert_wsi_socket_into_fds(context, wsi);
77
78         /* we are connected to server, or proxy */
79
80         if (context->http_proxy_port) {
81
82                 n = send(wsi->sock, context->service_buffer, plen, 0);
83                 if (n < 0) {
84                         compatible_close(wsi->sock);
85                         lwsl_debug("ERROR writing to proxy socket\n");
86                         goto bail1;
87                 }
88
89                 libwebsocket_set_timeout(wsi,
90                         PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
91
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
101          * 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.
105          */
106
107         libwebsocket_set_timeout(wsi,
108                 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
109
110         wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
111         pfd.fd = wsi->sock;
112         pfd.revents = POLLIN;
113
114         n = libwebsocket_service_fd(context, &pfd);
115
116         if (n < 0)
117                 goto oom4;
118
119         if (n) /* returns 1 on failure after closing wsi */
120                 return NULL;
121
122         return wsi;
123
124 oom4:
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
134 bail1:
135         free(wsi);
136
137         return NULL;
138 }
139
140 /**
141  * libwebsocket_client_connect() - Connect to another websocket server
142  * @context:    Websocket context
143  * @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.
153  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
154  *              protocol supported, or the specific protocol ordinal
155  *
156  *      This function creates a connection to a remote server
157  */
158
159 struct libwebsocket *
160 libwebsocket_client_connect(struct libwebsocket_context *context,
161                               const char *address,
162                               int port,
163                               int ssl_connection,
164                               const char *path,
165                               const char *host,
166                               const char *origin,
167                               const char *protocol,
168                               int ietf_version_or_minus_one)
169 {
170         struct libwebsocket *wsi;
171         int n;
172 #ifndef LWS_NO_EXTENSIONS
173         int m;
174         struct libwebsocket_extension *ext;
175         int handled;
176 #endif
177
178 #ifndef LWS_OPENSSL_SUPPORT
179         if (ssl_connection) {
180                 lwsl_err("libwebsockets not configured for ssl\n");
181                 return NULL;
182         }
183 #endif
184
185         wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
186         if (wsi == NULL)
187                 goto bail1;
188
189         memset(wsi, 0, sizeof *wsi);
190
191         /* -1 means just use latest supported */
192
193         if (ietf_version_or_minus_one == -1)
194                 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
195
196         wsi->ietf_spec_revision = ietf_version_or_minus_one;
197         wsi->u.hdr.name_buffer_pos = 0;
198         wsi->user_space = NULL;
199         wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
200         wsi->u.ws.pings_vs_pongs = 0;
201         wsi->protocol = NULL;
202         wsi->pending_timeout = NO_PENDING_TIMEOUT;
203 #ifndef LWS_NO_EXTENSIONS
204         wsi->count_active_extensions = 0;
205 #endif
206 #ifdef LWS_OPENSSL_SUPPORT
207         wsi->use_ssl = ssl_connection;
208 #endif
209
210         wsi->c_port = port;
211         wsi->c_address = strdup(address);
212
213         /* copy parameters over so state machine has access */
214
215         wsi->c_path = (char *)malloc(strlen(path) + 1);
216         if (wsi->c_path == NULL)
217                 goto bail1;
218         strcpy(wsi->c_path, path);
219
220         wsi->c_host = (char *)malloc(strlen(host) + 1);
221         if (wsi->c_host == NULL)
222                 goto oom1;
223         strcpy(wsi->c_host, host);
224
225         if (origin) {
226                 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
227                 if (wsi->c_origin == NULL)
228                         goto oom2;
229                 strcpy(wsi->c_origin, origin);
230         } else
231                 wsi->c_origin = NULL;
232
233         wsi->c_callback = NULL;
234         if (protocol) {
235                 const char *pc;
236                 struct libwebsocket_protocols *pp;
237
238                 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
239                 if (wsi->c_protocol == NULL)
240                         goto oom3;
241
242                 strcpy(wsi->c_protocol, protocol);
243
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                 }
254         } else
255                 wsi->c_protocol = NULL;
256
257         if (!wsi->c_callback)
258                 wsi->c_callback = context->protocols[0].callback;
259
260         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
261                 wsi->u.hdr.hdrs[n].token = NULL;
262                 wsi->u.hdr.hdrs[n].token_len = 0;
263         }
264
265 #ifndef LWS_NO_EXTENSIONS
266         /*
267          * 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.
271          */
272
273         handled = 0;
274         ext = context->extensions;
275         n = 0;
276
277         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;
283
284                 ext++;
285                 n++;
286         }
287
288         if (handled) {
289                 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
290
291                 libwebsocket_set_timeout(wsi,
292                         PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
293
294                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
295                 return wsi;
296         }
297 #endif
298         lwsl_client("libwebsocket_client_connect: direct conn\n");
299
300         return __libwebsocket_client_connect_2(context, wsi);
301
302 oom3:
303         if (wsi->c_origin)
304                 free(wsi->c_origin);
305
306 oom2:
307         free(wsi->c_host);
308
309 oom1:
310         free(wsi->c_path);
311
312 bail1:
313         free(wsi);
314
315         return NULL;
316 }
317
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
339 struct libwebsocket *
340 libwebsocket_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   }