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;
13 lwsl_client("__libwebsocket_client_connect_2\n");
14 #ifndef LWS_NO_EXTENSIONS
15 wsi->candidate_children_list = NULL;
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);
29 /* OK from now on we talk via the proxy */
32 wsi->c_address = strdup(context->http_proxy_address);
33 wsi->c_port = context->http_proxy_port;
37 * prepare the actual connection (to the proxy, if any)
40 lwsl_client("__libwebsocket_client_connect_2: address %s\n",
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);
49 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
52 lwsl_warn("Unable to open socket\n");
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);
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);
68 lwsl_client("connected\n");
70 if (lws_set_socket_options(context, wsi->sock)) {
71 lwsl_err("Failed to set wsi socket options\n");
76 insert_wsi_socket_into_fds(context, wsi);
78 /* we are connected to server, or proxy */
80 if (context->http_proxy_port) {
82 n = send(wsi->sock, context->service_buffer, plen, 0);
84 compatible_close(wsi->sock);
85 lwsl_debug("ERROR writing to proxy socket\n");
89 libwebsocket_set_timeout(wsi,
90 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
92 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
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.
107 libwebsocket_set_timeout(wsi,
108 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
110 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
112 pfd.revents = POLLIN;
114 n = libwebsocket_service_fd(context, &pfd);
119 if (n) /* returns 1 on failure after closing wsi */
126 free(wsi->c_protocol);
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
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
153 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
154 * protocol supported, or the specific protocol ordinal
156 * This function creates a connection to a remote server
159 struct libwebsocket *
160 libwebsocket_client_connect(struct libwebsocket_context *context,
167 const char *protocol,
168 int ietf_version_or_minus_one)
170 struct libwebsocket *wsi;
172 #ifndef LWS_NO_EXTENSIONS
174 struct libwebsocket_extension *ext;
178 #ifndef LWS_OPENSSL_SUPPORT
179 if (ssl_connection) {
180 lwsl_err("libwebsockets not configured for ssl\n");
185 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
189 memset(wsi, 0, sizeof *wsi);
191 /* -1 means just use latest supported */
193 if (ietf_version_or_minus_one == -1)
194 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
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;
205 #ifdef LWS_OPENSSL_SUPPORT
206 wsi->use_ssl = ssl_connection;
210 wsi->c_address = strdup(address);
212 /* copy parameters over so state machine has access */
214 wsi->c_path = (char *)malloc(strlen(path) + 1);
215 if (wsi->c_path == NULL)
217 strcpy(wsi->c_path, path);
219 wsi->c_host = (char *)malloc(strlen(host) + 1);
220 if (wsi->c_host == NULL)
222 strcpy(wsi->c_host, host);
225 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
226 if (wsi->c_origin == NULL)
228 strcpy(wsi->c_origin, origin);
230 wsi->c_origin = NULL;
232 wsi->c_callback = NULL;
235 struct libwebsocket_protocols *pp;
237 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
238 if (wsi->c_protocol == NULL)
241 strcpy(wsi->c_protocol, protocol);
244 while (*pc && *pc != ',')
247 pp = context->protocols;
248 while (pp->name && !wsi->c_callback) {
249 if (!strncmp(protocol, pp->name, n))
250 wsi->c_callback = pp->callback;
254 wsi->c_protocol = NULL;
256 if (!wsi->c_callback)
257 wsi->c_callback = context->protocols[0].callback;
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;
264 #ifndef LWS_NO_EXTENSIONS
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
273 ext = context->extensions;
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);
288 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
290 libwebsocket_set_timeout(wsi,
291 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
293 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
297 lwsl_client("libwebsocket_client_connect: direct conn\n");
299 return __libwebsocket_client_connect_2(context, wsi);
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
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
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
335 * This function creates a connection to a remote server
338 struct libwebsocket *
339 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
346 const char *protocol,
347 int ietf_version_or_minus_one,
350 struct libwebsocket *ws =
351 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
353 if (ws && !ws->user_space && userdata)
354 ws->user_space = userdata ;