remove all support for pre v13 protocols
[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 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;
15 #if defined(__APPLE__)
16         struct protoent *tcp_proto;
17 #endif
18
19         lwsl_client("__libwebsocket_client_connect_2\n");
20 #ifndef LWS_NO_EXTENSIONS
21         wsi->candidate_children_list = NULL;
22 #endif
23
24         /*
25          * proxy?
26          */
27
28         if (context->http_proxy_port) {
29                 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
30                         "User-agent: libwebsockets\x0d\x0a"
31 /*Proxy-authorization: basic aGVsbG86d29ybGQ= */
32                         "\x0d\x0a", wsi->c_address, wsi->c_port);
33
34                 /* OK from now on we talk via the proxy */
35
36                 free(wsi->c_address);
37                 wsi->c_address = strdup(context->http_proxy_address);
38                 wsi->c_port = context->http_proxy_port;
39         }
40
41         /*
42          * prepare the actual connection (to the proxy, if any)
43          */
44
45         lwsl_client("__libwebsocket_client_connect_2: address %s", wsi->c_address);
46
47         server_hostent = gethostbyname(wsi->c_address);
48         if (server_hostent == NULL) {
49                 lwsl_err("Unable to get host name from %s\n", wsi->c_address);
50                 goto oom4;
51         }
52
53         wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
54
55         if (wsi->sock < 0) {
56                 lwsl_warn("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 */
66 #if !defined(__APPLE__)
67         setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY,
68                                               (const void *)&opt, sizeof(opt));
69 #else
70         tcp_proto = getprotobyname("TCP");
71         setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY,
72                                                             &opt, sizeof(opt));
73 #endif
74
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,
81                                              sizeof(struct sockaddr)) == -1)  {
82                 lwsl_debug("Connect failed\n");
83                 compatible_close(wsi->sock);
84                 goto oom4;
85         }
86
87         lwsl_client("connected\n");
88
89         insert_wsi_socket_into_fds(context, wsi);
90
91         /* we are connected to server, or proxy */
92
93         if (context->http_proxy_port) {
94
95                 n = send(wsi->sock, pkt, plen, 0);
96                 if (n < 0) {
97                         compatible_close(wsi->sock);
98                         lwsl_debug("ERROR writing to proxy socket\n");
99                         goto bail1;
100                 }
101
102                 libwebsocket_set_timeout(wsi,
103                         PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
104
105                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
106
107                 return wsi;
108         }
109
110         /*
111          * provoke service to issue the handshake directly
112          * we need to do it this way because in the proxy case, this is the
113          * next state and executed only if and when we get a good proxy
114          * response inside the state machine... but notice in SSL case this
115          * may not have sent anything yet with 0 return, and won't until some
116          * many retries from main loop.  To stop that becoming endless,
117          * cover with a timeout.
118          */
119
120         libwebsocket_set_timeout(wsi,
121                 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
122
123         wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
124         pfd.fd = wsi->sock;
125         pfd.revents = POLLIN;
126
127         n = libwebsocket_service_fd(context, &pfd);
128
129         if (n < 0)
130                 goto oom4;
131
132         if (n) /* returns 1 on failure after closing wsi */
133                 return NULL;
134
135         return wsi;
136
137 oom4:
138         if (wsi->c_protocol)
139                 free(wsi->c_protocol);
140
141         if (wsi->c_origin)
142                 free(wsi->c_origin);
143
144         free(wsi->c_host);
145         free(wsi->c_path);
146
147 bail1:
148         free(wsi);
149
150         return NULL;
151 }
152
153 /**
154  * libwebsocket_client_connect() - Connect to another websocket server
155  * @context:    Websocket context
156  * @address:    Remote server address, eg, "myserver.com"
157  * @port:       Port to connect to on the remote server, eg, 80
158  * @ssl_connection:     0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
159  *                      signed certs
160  * @path:       Websocket path on server
161  * @host:       Hostname on server
162  * @origin:     Socket origin name
163  * @protocol:   Comma-separated list of protocols being asked for from
164  *              the server, or just one.  The server will pick the one it
165  *              likes best.
166  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
167  *              protocol supported, or the specific protocol ordinal
168  *
169  *      This function creates a connection to a remote server
170  */
171
172 struct libwebsocket *
173 libwebsocket_client_connect(struct libwebsocket_context *context,
174                               const char *address,
175                               int port,
176                               int ssl_connection,
177                               const char *path,
178                               const char *host,
179                               const char *origin,
180                               const char *protocol,
181                               int ietf_version_or_minus_one)
182 {
183         struct libwebsocket *wsi;
184         int n;
185 #ifndef LWS_NO_EXTENSIONS
186         int m;
187         struct libwebsocket_extension *ext;
188         int handled;
189 #endif
190
191 #ifndef LWS_OPENSSL_SUPPORT
192         if (ssl_connection) {
193                 lwsl_err("libwebsockets not configured for ssl\n");
194                 return NULL;
195         }
196 #endif
197
198         wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
199         if (wsi == NULL)
200                 goto bail1;
201
202         memset(wsi, 0, sizeof *wsi);
203
204         /* -1 means just use latest supported */
205
206         if (ietf_version_or_minus_one == -1)
207                 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
208
209         wsi->ietf_spec_revision = ietf_version_or_minus_one;
210         wsi->name_buffer_pos = 0;
211         wsi->user_space = NULL;
212         wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
213         wsi->pings_vs_pongs = 0;
214         wsi->protocol = NULL;
215         wsi->pending_timeout = NO_PENDING_TIMEOUT;
216 #ifndef LWS_NO_EXTENSIONS
217         wsi->count_active_extensions = 0;
218 #endif
219 #ifdef LWS_OPENSSL_SUPPORT
220         wsi->use_ssl = ssl_connection;
221 #endif
222
223         wsi->c_port = port;
224         wsi->c_address = strdup(address);
225
226         /* copy parameters over so state machine has access */
227
228         wsi->c_path = (char *)malloc(strlen(path) + 1);
229         if (wsi->c_path == NULL)
230                 goto bail1;
231         strcpy(wsi->c_path, path);
232
233         wsi->c_host = (char *)malloc(strlen(host) + 1);
234         if (wsi->c_host == NULL)
235                 goto oom1;
236         strcpy(wsi->c_host, host);
237
238         if (origin) {
239                 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
240                 if (wsi->c_origin == NULL)
241                         goto oom2;
242                 strcpy(wsi->c_origin, origin);
243         } else
244                 wsi->c_origin = NULL;
245
246         wsi->c_callback = NULL;
247         if (protocol) {
248                 const char *pc;
249                 struct libwebsocket_protocols *pp;
250
251                 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
252                 if (wsi->c_protocol == NULL)
253                         goto oom3;
254
255                 strcpy(wsi->c_protocol, protocol);
256
257                 pc = protocol;
258                 while (*pc && *pc != ',')
259                         pc++;
260                 n = pc - protocol;
261                 pp = context->protocols;
262                 while (pp->name && !wsi->c_callback) {
263                         if (!strncmp(protocol, pp->name, n))
264                                 wsi->c_callback = pp->callback;
265                         pp++;
266                 }
267         } else
268                 wsi->c_protocol = NULL;
269
270         if (!wsi->c_callback)
271                 wsi->c_callback = context->protocols[0].callback;
272
273         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
274                 wsi->utf8_token[n].token = NULL;
275                 wsi->utf8_token[n].token_len = 0;
276         }
277
278 #ifndef LWS_NO_EXTENSIONS
279         /*
280          * Check with each extension if it is able to route and proxy this
281          * connection for us.  For example, an extension like x-google-mux
282          * can handle this and then we don't need an actual socket for this
283          * connection.
284          */
285
286         handled = 0;
287         ext = context->extensions;
288         n = 0;
289
290         while (ext && ext->callback && !handled) {
291                 m = ext->callback(context, ext, wsi,
292                         LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
293                                  (void *)(long)n, (void *)address, port);
294                 if (m)
295                         handled = 1;
296
297                 ext++;
298                 n++;
299         }
300
301         if (handled) {
302                 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
303
304                 libwebsocket_set_timeout(wsi,
305                         PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
306
307                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
308                 return wsi;
309         }
310 #endif
311         lwsl_client("libwebsocket_client_connect: direct conn\n");
312
313         return __libwebsocket_client_connect_2(context, wsi);
314
315 oom3:
316         if (wsi->c_origin)
317                 free(wsi->c_origin);
318
319 oom2:
320         free(wsi->c_host);
321
322 oom1:
323         free(wsi->c_path);
324
325 bail1:
326         free(wsi);
327
328         return NULL;
329 }
330
331
332 /**
333  * libwebsocket_client_connect_extended() - Connect to another websocket server
334  * @context:    Websocket context
335  * @address:    Remote server address, eg, "myserver.com"
336  * @port:       Port to connect to on the remote server, eg, 80
337  * @ssl_connection:     0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
338  *                      signed certs
339  * @path:       Websocket path on server
340  * @host:       Hostname on server
341  * @origin:     Socket origin name
342  * @protocol:   Comma-separated list of protocols being asked for from
343  *              the server, or just one.  The server will pick the one it
344  *              likes best.
345  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
346  *              protocol supported, or the specific protocol ordinal
347  * @userdata: Pre-allocated user data
348  *
349  *      This function creates a connection to a remote server
350  */
351
352 struct libwebsocket *
353 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
354                               const char *address,
355                               int port,
356                               int ssl_connection,
357                               const char *path,
358                               const char *host,
359                               const char *origin,
360                               const char *protocol,
361                               int ietf_version_or_minus_one,
362             void *userdata)
363 {
364         struct libwebsocket *ws =
365                 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
366
367         if (ws && !ws->user_space && userdata)
368                 ws->user_space = userdata ;
369
370         return ws ;
371   }