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;
14 lwsl_client("libwebsocket_client_connect_2\n");
20 if (context->http_proxy_port) {
21 plen = sprintf((char *)context->service_buffer,
22 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
23 "User-agent: libwebsockets\x0d\x0a"
24 /*Proxy-authorization: basic aGVsbG86d29ybGQ= */
26 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
27 wsi->u.hdr.ah->c_port);
28 ads = context->http_proxy_address;
29 server_addr.sin_port = htons(context->http_proxy_port);
31 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
32 server_addr.sin_port = htons(wsi->u.hdr.ah->c_port);
36 * prepare the actual connection (to the proxy, if any)
38 lwsl_client("libwebsocket_client_connect_2: address %s\n", ads);
40 server_hostent = gethostbyname(ads);
41 if (server_hostent == NULL) {
42 lwsl_err("Unable to get host name from %s\n", ads);
48 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
51 lwsl_warn("Unable to open socket\n");
55 if (lws_set_socket_options(context, wsi->sock)) {
56 lwsl_err("Failed to set wsi socket options\n");
57 compatible_close(wsi->sock);
61 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT;
63 insert_wsi_socket_into_fds(context, wsi);
65 libwebsocket_set_timeout(wsi,
66 PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
70 server_addr.sin_family = AF_INET;
71 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
73 bzero(&server_addr.sin_zero, 8);
75 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
76 sizeof(struct sockaddr)) == -1 || errno == EISCONN) {
78 if (errno == EALREADY || errno == EINPROGRESS) {
79 lwsl_client("nonblocking connect retry\n");
82 * must do specifically a POLLOUT poll to hear
83 * about the connect completion
85 lws_change_pollfd(wsi, 0, POLLOUT);
90 if (errno != EISCONN) {
92 lwsl_debug("Connect failed errno=%d\n", errno);
97 lwsl_client("connected\n");
99 /* we are connected to server, or proxy */
101 if (context->http_proxy_port) {
103 /* OK from now on we talk via the proxy, so connect to that */
106 * (will overwrite existing pointer,
107 * leaving old string/frag there but unreferenced)
109 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
110 context->http_proxy_address))
112 wsi->u.hdr.ah->c_port = context->http_proxy_port;
114 n = send(wsi->sock, context->service_buffer, plen, MSG_NOSIGNAL);
116 lwsl_debug("ERROR writing to proxy socket\n");
120 libwebsocket_set_timeout(wsi,
121 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
124 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
130 * provoke service to issue the handshake directly
131 * we need to do it this way because in the proxy case, this is the
132 * next state and executed only if and when we get a good proxy
133 * response inside the state machine... but notice in SSL case this
134 * may not have sent anything yet with 0 return, and won't until some
135 * many retries from main loop. To stop that becoming endless,
136 * cover with a timeout.
139 libwebsocket_set_timeout(wsi,
140 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
142 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
144 pfd.revents = POLLIN;
146 n = libwebsocket_service_fd(context, &pfd);
151 if (n) /* returns 1 on failure after closing wsi */
162 libwebsocket_close_and_free_session(context, wsi,
163 LWS_CLOSE_STATUS_NOSTATUS);
168 * libwebsocket_client_connect() - Connect to another websocket server
169 * @context: Websocket context
170 * @address: Remote server address, eg, "myserver.com"
171 * @port: Port to connect to on the remote server, eg, 80
172 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
174 * @path: Websocket path on server
175 * @host: Hostname on server
176 * @origin: Socket origin name
177 * @protocol: Comma-separated list of protocols being asked for from
178 * the server, or just one. The server will pick the one it
180 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
181 * protocol supported, or the specific protocol ordinal
183 * This function creates a connection to a remote server
186 LWS_VISIBLE struct libwebsocket *
187 libwebsocket_client_connect(struct libwebsocket_context *context,
194 const char *protocol,
195 int ietf_version_or_minus_one)
197 struct libwebsocket *wsi;
198 #ifndef LWS_NO_EXTENSIONS
201 struct libwebsocket_extension *ext;
205 #ifndef LWS_OPENSSL_SUPPORT
206 if (ssl_connection) {
207 lwsl_err("libwebsockets not configured for ssl\n");
212 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
216 memset(wsi, 0, sizeof(*wsi));
219 /* -1 means just use latest supported */
221 if (ietf_version_or_minus_one == -1)
222 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
224 wsi->ietf_spec_revision = ietf_version_or_minus_one;
225 wsi->user_space = NULL;
226 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
227 wsi->protocol = NULL;
228 wsi->pending_timeout = NO_PENDING_TIMEOUT;
229 #ifndef LWS_NO_EXTENSIONS
230 wsi->count_active_extensions = 0;
232 #ifdef LWS_OPENSSL_SUPPORT
233 wsi->use_ssl = ssl_connection;
236 if (lws_allocate_header_table(wsi))
240 * we're not necessarily in a position to action these right away,
241 * stash them... we only need during connect phase so u.hdr is fine
243 wsi->u.hdr.ah->c_port = port;
244 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
247 /* these only need u.hdr lifetime as well */
249 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
252 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
256 if (lws_hdr_simple_create(wsi,
257 _WSI_TOKEN_CLIENT_ORIGIN, origin))
260 * this is a list of protocols we tell the server we're okay with
261 * stash it for later when we compare server response with it
264 if (lws_hdr_simple_create(wsi,
265 _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
268 wsi->protocol = &context->protocols[0];
270 #ifndef LWS_NO_EXTENSIONS
272 * Check with each extension if it is able to route and proxy this
273 * connection for us. For example, an extension like x-google-mux
274 * can handle this and then we don't need an actual socket for this
279 ext = context->extensions;
282 while (ext && ext->callback && !handled) {
283 m = ext->callback(context, ext, wsi,
284 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
285 (void *)(long)n, (void *)address, port);
294 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
296 libwebsocket_set_timeout(wsi,
297 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
300 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
304 lwsl_client("libwebsocket_client_connect: direct conn\n");
306 return libwebsocket_client_connect_2(context, wsi);
318 * libwebsocket_client_connect_extended() - Connect to another websocket server
319 * @context: Websocket context
320 * @address: Remote server address, eg, "myserver.com"
321 * @port: Port to connect to on the remote server, eg, 80
322 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
324 * @path: Websocket path on server
325 * @host: Hostname on server
326 * @origin: Socket origin name
327 * @protocol: Comma-separated list of protocols being asked for from
328 * the server, or just one. The server will pick the one it
330 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
331 * protocol supported, or the specific protocol ordinal
332 * @userdata: Pre-allocated user data
334 * This function creates a connection to a remote server
337 LWS_VISIBLE struct libwebsocket *
338 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
345 const char *protocol,
346 int ietf_version_or_minus_one,
349 struct libwebsocket *ws =
350 libwebsocket_client_connect(context, address, port,
351 ssl_connection, path, host, origin, protocol,
352 ietf_version_or_minus_one);
354 if (ws && !ws->user_space && userdata)
355 ws->user_space = userdata ;