throw out lws_websocket_related cruft
[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->protocol = NULL;
201         wsi->pending_timeout = NO_PENDING_TIMEOUT;
202 #ifndef LWS_NO_EXTENSIONS
203         wsi->count_active_extensions = 0;
204 #endif
205 #ifdef LWS_OPENSSL_SUPPORT
206         wsi->use_ssl = ssl_connection;
207 #endif
208
209         wsi->c_port = port;
210         wsi->c_address = strdup(address);
211
212         /* copy parameters over so state machine has access */
213
214         wsi->c_path = (char *)malloc(strlen(path) + 1);
215         if (wsi->c_path == NULL)
216                 goto bail1;
217         strcpy(wsi->c_path, path);
218
219         wsi->c_host = (char *)malloc(strlen(host) + 1);
220         if (wsi->c_host == NULL)
221                 goto oom1;
222         strcpy(wsi->c_host, host);
223
224         if (origin) {
225                 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
226                 if (wsi->c_origin == NULL)
227                         goto oom2;
228                 strcpy(wsi->c_origin, origin);
229         } else
230                 wsi->c_origin = NULL;
231
232         wsi->c_callback = NULL;
233         if (protocol) {
234                 const char *pc;
235                 struct libwebsocket_protocols *pp;
236
237                 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
238                 if (wsi->c_protocol == NULL)
239                         goto oom3;
240
241                 strcpy(wsi->c_protocol, protocol);
242
243                 pc = protocol;
244                 while (*pc && *pc != ',')
245                         pc++;
246                 n = pc - protocol;
247                 pp = context->protocols;
248                 while (pp->name && !wsi->c_callback) {
249                         if (!strncmp(protocol, pp->name, n))
250                                 wsi->c_callback = pp->callback;
251                         pp++;
252                 }
253         } else
254                 wsi->c_protocol = NULL;
255
256         if (!wsi->c_callback)
257                 wsi->c_callback = context->protocols[0].callback;
258
259         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
260                 wsi->u.hdr.hdrs[n].token = NULL;
261                 wsi->u.hdr.hdrs[n].token_len = 0;
262         }
263
264 #ifndef LWS_NO_EXTENSIONS
265         /*
266          * Check with each extension if it is able to route and proxy this
267          * connection for us.  For example, an extension like x-google-mux
268          * can handle this and then we don't need an actual socket for this
269          * connection.
270          */
271
272         handled = 0;
273         ext = context->extensions;
274         n = 0;
275
276         while (ext && ext->callback && !handled) {
277                 m = ext->callback(context, ext, wsi,
278                         LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
279                                  (void *)(long)n, (void *)address, port);
280                 if (m)
281                         handled = 1;
282
283                 ext++;
284                 n++;
285         }
286
287         if (handled) {
288                 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
289
290                 libwebsocket_set_timeout(wsi,
291                         PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
292
293                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
294                 return wsi;
295         }
296 #endif
297         lwsl_client("libwebsocket_client_connect: direct conn\n");
298
299         return __libwebsocket_client_connect_2(context, wsi);
300
301 oom3:
302         if (wsi->c_origin)
303                 free(wsi->c_origin);
304
305 oom2:
306         free(wsi->c_host);
307
308 oom1:
309         free(wsi->c_path);
310
311 bail1:
312         free(wsi);
313
314         return NULL;
315 }
316
317
318 /**
319  * libwebsocket_client_connect_extended() - Connect to another websocket server
320  * @context:    Websocket context
321  * @address:    Remote server address, eg, "myserver.com"
322  * @port:       Port to connect to on the remote server, eg, 80
323  * @ssl_connection:     0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
324  *                      signed certs
325  * @path:       Websocket path on server
326  * @host:       Hostname on server
327  * @origin:     Socket origin name
328  * @protocol:   Comma-separated list of protocols being asked for from
329  *              the server, or just one.  The server will pick the one it
330  *              likes best.
331  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
332  *              protocol supported, or the specific protocol ordinal
333  * @userdata: Pre-allocated user data
334  *
335  *      This function creates a connection to a remote server
336  */
337
338 struct libwebsocket *
339 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
340                               const char *address,
341                               int port,
342                               int ssl_connection,
343                               const char *path,
344                               const char *host,
345                               const char *origin,
346                               const char *protocol,
347                               int ietf_version_or_minus_one,
348             void *userdata)
349 {
350         struct libwebsocket *ws =
351                 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
352
353         if (ws && !ws->user_space && userdata)
354                 ws->user_space = userdata ;
355
356         return ws ;
357   }