1 #include "private-libwebsockets.h"
3 struct libwebsocket *libwebsocket_client_connect_2(
4 struct libwebsocket_context *context,
5 struct libwebsocket *wsi
8 struct hostent *server_hostent;
9 struct sockaddr_in server_addr;
10 struct sockaddr_in client_addr;
15 lwsl_client("libwebsocket_client_connect_2\n");
21 if (context->http_proxy_port) {
22 plen = sprintf((char *)context->service_buffer,
23 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
24 "User-agent: libwebsockets\x0d\x0a"
25 /*Proxy-authorization: basic aGVsbG86d29ybGQ= */
27 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
28 wsi->u.hdr.ah->c_port);
29 ads = context->http_proxy_address;
30 server_addr.sin_port = htons(context->http_proxy_port);
32 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
33 server_addr.sin_port = htons(wsi->u.hdr.ah->c_port);
37 * prepare the actual connection (to the proxy, if any)
39 lwsl_client("libwebsocket_client_connect_2: address %s\n", ads);
41 server_hostent = gethostbyname(ads);
42 if (server_hostent == NULL) {
43 lwsl_err("Unable to get host name from %s\n", ads);
49 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
52 lwsl_warn("Unable to open socket\n");
56 if (lws_set_socket_options(context, wsi->sock)) {
57 lwsl_err("Failed to set wsi socket options\n");
58 compatible_close(wsi->sock);
62 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT;
64 insert_wsi_socket_into_fds(context, wsi);
66 libwebsocket_set_timeout(wsi,
67 PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
70 bzero((char *) &client_addr, sizeof(client_addr));
71 client_addr.sin_family = AF_INET;
73 if (context->iface != NULL) {
74 if (interface_to_sa(context->iface, &client_addr,
75 sizeof(client_addr)) < 0) {
76 lwsl_err("Unable to find interface %s\n", context->iface);
77 compatible_close(wsi->sock);
81 if (bind(wsi->sock, (struct sockaddr *) &client_addr,
82 sizeof(client_addr)) < 0) {
83 lwsl_err("Error binding to interface %s", context->iface);
84 compatible_close(wsi->sock);
90 server_addr.sin_family = AF_INET;
91 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
93 bzero(&server_addr.sin_zero, 8);
95 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
96 sizeof(struct sockaddr)) == -1 || LWS_ERRNO == LWS_EISCONN) {
98 if (LWS_ERRNO == LWS_EALREADY || LWS_ERRNO == LWS_EINPROGRESS) {
99 lwsl_client("nonblocking connect retry\n");
102 * must do specifically a POLLOUT poll to hear
103 * about the connect completion
105 lws_change_pollfd(wsi, 0, POLLOUT);
110 if (LWS_ERRNO != LWS_EISCONN) {
112 lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
117 lwsl_client("connected\n");
119 /* we are connected to server, or proxy */
121 if (context->http_proxy_port) {
123 /* OK from now on we talk via the proxy, so connect to that */
126 * (will overwrite existing pointer,
127 * leaving old string/frag there but unreferenced)
129 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
130 context->http_proxy_address))
132 wsi->u.hdr.ah->c_port = context->http_proxy_port;
134 n = send(wsi->sock, context->service_buffer, plen, MSG_NOSIGNAL);
136 lwsl_debug("ERROR writing to proxy socket\n");
140 libwebsocket_set_timeout(wsi,
141 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
144 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
150 * provoke service to issue the handshake directly
151 * we need to do it this way because in the proxy case, this is the
152 * next state and executed only if and when we get a good proxy
153 * response inside the state machine... but notice in SSL case this
154 * may not have sent anything yet with 0 return, and won't until some
155 * many retries from main loop. To stop that becoming endless,
156 * cover with a timeout.
159 libwebsocket_set_timeout(wsi,
160 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
162 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
164 pfd.revents = POLLIN;
166 n = libwebsocket_service_fd(context, &pfd);
171 if (n) /* returns 1 on failure after closing wsi */
182 libwebsocket_close_and_free_session(context, wsi,
183 LWS_CLOSE_STATUS_NOSTATUS);
188 * libwebsocket_client_connect() - Connect to another websocket server
189 * @context: Websocket context
190 * @address: Remote server address, eg, "myserver.com"
191 * @port: Port to connect to on the remote server, eg, 80
192 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
194 * @path: Websocket path on server
195 * @host: Hostname on server
196 * @origin: Socket origin name
197 * @protocol: Comma-separated list of protocols being asked for from
198 * the server, or just one. The server will pick the one it
200 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
201 * protocol supported, or the specific protocol ordinal
203 * This function creates a connection to a remote server
206 LWS_VISIBLE struct libwebsocket *
207 libwebsocket_client_connect(struct libwebsocket_context *context,
214 const char *protocol,
215 int ietf_version_or_minus_one)
217 struct libwebsocket *wsi;
218 #ifndef LWS_NO_EXTENSIONS
221 struct libwebsocket_extension *ext;
225 #ifndef LWS_OPENSSL_SUPPORT
226 if (ssl_connection) {
227 lwsl_err("libwebsockets not configured for ssl\n");
232 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
236 memset(wsi, 0, sizeof(*wsi));
239 /* -1 means just use latest supported */
241 if (ietf_version_or_minus_one == -1)
242 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
244 wsi->ietf_spec_revision = ietf_version_or_minus_one;
245 wsi->user_space = NULL;
246 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
247 wsi->protocol = NULL;
248 wsi->pending_timeout = NO_PENDING_TIMEOUT;
249 #ifndef LWS_NO_EXTENSIONS
250 wsi->count_active_extensions = 0;
252 #ifdef LWS_OPENSSL_SUPPORT
253 wsi->use_ssl = ssl_connection;
256 if (lws_allocate_header_table(wsi))
260 * we're not necessarily in a position to action these right away,
261 * stash them... we only need during connect phase so u.hdr is fine
263 wsi->u.hdr.ah->c_port = port;
264 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
267 /* these only need u.hdr lifetime as well */
269 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
272 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
276 if (lws_hdr_simple_create(wsi,
277 _WSI_TOKEN_CLIENT_ORIGIN, origin))
280 * this is a list of protocols we tell the server we're okay with
281 * stash it for later when we compare server response with it
284 if (lws_hdr_simple_create(wsi,
285 _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
288 wsi->protocol = &context->protocols[0];
290 #ifndef LWS_NO_EXTENSIONS
292 * Check with each extension if it is able to route and proxy this
293 * connection for us. For example, an extension like x-google-mux
294 * can handle this and then we don't need an actual socket for this
299 ext = context->extensions;
302 while (ext && ext->callback && !handled) {
303 m = ext->callback(context, ext, wsi,
304 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
305 (void *)(long)n, (void *)address, port);
314 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
316 libwebsocket_set_timeout(wsi,
317 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
320 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
324 lwsl_client("libwebsocket_client_connect: direct conn\n");
326 return libwebsocket_client_connect_2(context, wsi);
338 * libwebsocket_client_connect_extended() - Connect to another websocket server
339 * @context: Websocket context
340 * @address: Remote server address, eg, "myserver.com"
341 * @port: Port to connect to on the remote server, eg, 80
342 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
344 * @path: Websocket path on server
345 * @host: Hostname on server
346 * @origin: Socket origin name
347 * @protocol: Comma-separated list of protocols being asked for from
348 * the server, or just one. The server will pick the one it
350 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
351 * protocol supported, or the specific protocol ordinal
352 * @userdata: Pre-allocated user data
354 * This function creates a connection to a remote server
357 LWS_VISIBLE struct libwebsocket *
358 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
365 const char *protocol,
366 int ietf_version_or_minus_one,
369 struct libwebsocket *ws =
370 libwebsocket_client_connect(context, address, port,
371 ssl_connection, path, host, origin, protocol,
372 ietf_version_or_minus_one);
374 if (ws && !ws->user_space && userdata)
375 ws->user_space = userdata ;