1 #include "private-libwebsockets.h"
3 struct libwebsocket *__libwebsocket_client_connect_2(
4 struct libwebsocket_context *context,
5 struct libwebsocket *wsi
9 struct hostent *server_hostent;
10 struct sockaddr_in server_addr;
15 #if defined(__APPLE__)
16 struct protoent *tcp_proto;
19 lwsl_client("__libwebsocket_client_connect_2\n");
20 #ifndef LWS_NO_EXTENSIONS
21 wsi->candidate_children_list = NULL;
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);
34 /* OK from now on we talk via the proxy */
37 wsi->c_address = strdup(context->http_proxy_address);
38 wsi->c_port = context->http_proxy_port;
42 * prepare the actual connection (to the proxy, if any)
45 lwsl_client("__libwebsocket_client_connect_2: address %s", wsi->c_address);
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);
53 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
56 lwsl_warn("Unable to open socket\n");
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);
66 #if !defined(__APPLE__)
67 setsockopt(wsi->sock, SOL_TCP, TCP_NODELAY,
68 (const void *)&opt, sizeof(opt));
70 tcp_proto = getprotobyname("TCP");
71 setsockopt(wsi->sock, tcp_proto->p_proto, TCP_NODELAY,
75 /* Set receiving timeout */
77 tv.tv_usec = 100 * 1000;
78 setsockopt(wsi->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv);
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);
87 lwsl_client("connected\n");
89 insert_wsi_socket_into_fds(context, wsi);
91 /* we are connected to server, or proxy */
93 if (context->http_proxy_port) {
95 n = send(wsi->sock, pkt, plen, 0);
97 compatible_close(wsi->sock);
98 lwsl_debug("ERROR writing to proxy socket\n");
102 libwebsocket_set_timeout(wsi,
103 PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT);
105 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
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.
120 libwebsocket_set_timeout(wsi,
121 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
123 wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
125 pfd.revents = POLLIN;
127 n = libwebsocket_service_fd(context, &pfd);
132 if (n) /* returns 1 on failure after closing wsi */
139 free(wsi->c_protocol);
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
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
166 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
167 * protocol supported, or the specific protocol ordinal
169 * This function creates a connection to a remote server
172 struct libwebsocket *
173 libwebsocket_client_connect(struct libwebsocket_context *context,
180 const char *protocol,
181 int ietf_version_or_minus_one)
183 struct libwebsocket *wsi;
185 #ifndef LWS_NO_EXTENSIONS
187 struct libwebsocket_extension *ext;
191 #ifndef LWS_OPENSSL_SUPPORT
192 if (ssl_connection) {
193 lwsl_err("libwebsockets not configured for ssl\n");
198 wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
202 memset(wsi, 0, sizeof *wsi);
204 /* -1 means just use latest supported */
206 if (ietf_version_or_minus_one == -1)
207 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
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;
219 #ifdef LWS_OPENSSL_SUPPORT
220 wsi->use_ssl = ssl_connection;
224 wsi->c_address = strdup(address);
226 /* copy parameters over so state machine has access */
228 wsi->c_path = (char *)malloc(strlen(path) + 1);
229 if (wsi->c_path == NULL)
231 strcpy(wsi->c_path, path);
233 wsi->c_host = (char *)malloc(strlen(host) + 1);
234 if (wsi->c_host == NULL)
236 strcpy(wsi->c_host, host);
239 wsi->c_origin = (char *)malloc(strlen(origin) + 1);
240 if (wsi->c_origin == NULL)
242 strcpy(wsi->c_origin, origin);
244 wsi->c_origin = NULL;
246 wsi->c_callback = NULL;
249 struct libwebsocket_protocols *pp;
251 wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
252 if (wsi->c_protocol == NULL)
255 strcpy(wsi->c_protocol, protocol);
258 while (*pc && *pc != ',')
261 pp = context->protocols;
262 while (pp->name && !wsi->c_callback) {
263 if (!strncmp(protocol, pp->name, n))
264 wsi->c_callback = pp->callback;
268 wsi->c_protocol = NULL;
270 if (!wsi->c_callback)
271 wsi->c_callback = context->protocols[0].callback;
273 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
274 wsi->utf8_token[n].token = NULL;
275 wsi->utf8_token[n].token_len = 0;
278 #ifndef LWS_NO_EXTENSIONS
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
287 ext = context->extensions;
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);
302 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
304 libwebsocket_set_timeout(wsi,
305 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT);
307 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
311 lwsl_client("libwebsocket_client_connect: direct conn\n");
313 return __libwebsocket_client_connect_2(context, wsi);
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
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
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
349 * This function creates a connection to a remote server
352 struct libwebsocket *
353 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
360 const char *protocol,
361 int ietf_version_or_minus_one,
364 struct libwebsocket *ws =
365 libwebsocket_client_connect(context, address, port, ssl_connection, path, host, origin, protocol, ietf_version_or_minus_one) ;
367 if (ws && !ws->user_space && userdata)
368 ws->user_space = userdata ;