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);
29 /* OK from now on we talk via the proxy, so connect to that */
32 * (will overwrite existing pointer,
33 * leaving old string/frag there but unreferenced)
35 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
36 context->http_proxy_address))
38 wsi->u.hdr.ah->c_port = context->http_proxy_port;
42 * prepare the actual connection (to the proxy, if any)
45 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
47 lwsl_client("__libwebsocket_client_connect_2: address %s\n", ads);
49 server_hostent = gethostbyname(ads);
50 if (server_hostent == NULL) {
51 lwsl_err("Unable to get host name from %s\n", ads);
55 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
58 lwsl_warn("Unable to open socket\n");
62 server_addr.sin_family = AF_INET;
63 server_addr.sin_port = htons(wsi->u.hdr.ah->c_port);
64 server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
65 bzero(&server_addr.sin_zero, 8);
67 if (connect(wsi->sock, (struct sockaddr *)&server_addr,
68 sizeof(struct sockaddr)) == -1) {
69 lwsl_debug("Connect failed\n");
70 compatible_close(wsi->sock);
74 lwsl_client("connected\n");
76 if (lws_set_socket_options(context, wsi->sock)) {
77 lwsl_err("Failed to set wsi socket options\n");
82 insert_wsi_socket_into_fds(context, wsi);
84 /* we are connected to server, or proxy */
86 if (context->http_proxy_port) {
88 n = send(wsi->sock, context->service_buffer, plen, 0);
90 compatible_close(wsi->sock);
91 lwsl_debug("ERROR writing to proxy socket\n");
95 libwebsocket_set_timeout(wsi,
96 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
99 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
105 * provoke service to issue the handshake directly
106 * we need to do it this way because in the proxy case, this is the
107 * next state and executed only if and when we get a good proxy
108 * response inside the state machine... but notice in SSL case this
109 * may not have sent anything yet with 0 return, and won't until some
110 * many retries from main loop. To stop that becoming endless,
111 * cover with a timeout.
114 libwebsocket_set_timeout(wsi,
115 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
117 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
119 pfd.revents = POLLIN;
121 n = libwebsocket_service_fd(context, &pfd);
126 if (n) /* returns 1 on failure after closing wsi */
139 * libwebsocket_client_connect() - Connect to another websocket server
140 * @context: Websocket context
141 * @address: Remote server address, eg, "myserver.com"
142 * @port: Port to connect to on the remote server, eg, 80
143 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
145 * @path: Websocket path on server
146 * @host: Hostname on server
147 * @origin: Socket origin name
148 * @protocol: Comma-separated list of protocols being asked for from
149 * the server, or just one. The server will pick the one it
151 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
152 * protocol supported, or the specific protocol ordinal
154 * This function creates a connection to a remote server
157 struct libwebsocket *
158 libwebsocket_client_connect(struct libwebsocket_context *context,
165 const char *protocol,
166 int ietf_version_or_minus_one)
168 struct libwebsocket *wsi;
169 #ifndef LWS_NO_EXTENSIONS
172 struct libwebsocket_extension *ext;
176 #ifndef LWS_OPENSSL_SUPPORT
177 if (ssl_connection) {
178 lwsl_err("libwebsockets not configured for ssl\n");
183 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
187 memset(wsi, 0, sizeof(*wsi));
189 /* -1 means just use latest supported */
191 if (ietf_version_or_minus_one == -1)
192 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
194 wsi->ietf_spec_revision = ietf_version_or_minus_one;
195 wsi->user_space = NULL;
196 wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
197 wsi->protocol = NULL;
198 wsi->pending_timeout = NO_PENDING_TIMEOUT;
199 #ifndef LWS_NO_EXTENSIONS
200 wsi->count_active_extensions = 0;
202 #ifdef LWS_OPENSSL_SUPPORT
203 wsi->use_ssl = ssl_connection;
206 if (lws_allocate_header_table(wsi))
210 * we're not necessarily in a position to action these right away,
211 * stash them... we only need during connect phase so u.hdr is fine
213 wsi->u.hdr.ah->c_port = port;
214 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
217 /* these only need u.hdr lifetime as well */
219 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
222 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
226 if (lws_hdr_simple_create(wsi,
227 _WSI_TOKEN_CLIENT_ORIGIN, origin))
230 * this is a list of protocols we tell the server we're okay with
231 * stash it for later when we compare server response with it
234 if (lws_hdr_simple_create(wsi,
235 _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
238 wsi->protocol = &context->protocols[0];
240 #ifndef LWS_NO_EXTENSIONS
242 * Check with each extension if it is able to route and proxy this
243 * connection for us. For example, an extension like x-google-mux
244 * can handle this and then we don't need an actual socket for this
249 ext = context->extensions;
252 while (ext && ext->callback && !handled) {
253 m = ext->callback(context, ext, wsi,
254 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
255 (void *)(long)n, (void *)address, port);
264 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
266 libwebsocket_set_timeout(wsi,
267 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
270 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
274 lwsl_client("libwebsocket_client_connect: direct conn\n");
276 return __libwebsocket_client_connect_2(context, wsi);
288 * libwebsocket_client_connect_extended() - Connect to another websocket server
289 * @context: Websocket context
290 * @address: Remote server address, eg, "myserver.com"
291 * @port: Port to connect to on the remote server, eg, 80
292 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
294 * @path: Websocket path on server
295 * @host: Hostname on server
296 * @origin: Socket origin name
297 * @protocol: Comma-separated list of protocols being asked for from
298 * the server, or just one. The server will pick the one it
300 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
301 * protocol supported, or the specific protocol ordinal
302 * @userdata: Pre-allocated user data
304 * This function creates a connection to a remote server
307 struct libwebsocket *
308 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
315 const char *protocol,
316 int ietf_version_or_minus_one,
319 struct libwebsocket *ws =
320 libwebsocket_client_connect(context, address, port,
321 ssl_connection, path, host, origin, protocol,
322 ietf_version_or_minus_one);
324 if (ws && !ws->user_space && userdata)
325 ws->user_space = userdata ;