Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 1 | #include "private-libwebsockets.h" |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 2 | |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 3 | struct lws *lws_client_connect_2( |
| 4 | struct lws_context *context, |
| 5 | struct lws *wsi |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 6 | ) { |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 7 | struct lws_pollfd pfd; |
Andy Green | 055f297 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 8 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 9 | struct sockaddr_in6 server_addr6; |
| 10 | struct sockaddr_in6 client_addr6; |
| 11 | struct addrinfo hints, *result; |
| 12 | #endif |
| 13 | struct sockaddr_in server_addr4; |
| 14 | struct sockaddr_in client_addr4; |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 15 | |
| 16 | struct sockaddr *v; |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 17 | int n; |
| 18 | int plen = 0; |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 19 | const char *ads; |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 20 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 21 | lwsl_client("lws_client_connect_2\n"); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 22 | |
| 23 | /* |
| 24 | * proxy? |
| 25 | */ |
| 26 | |
| 27 | if (context->http_proxy_port) { |
Andy Green | e48ba31 | 2013-02-10 15:34:59 +0800 | [diff] [blame] | 28 | plen = sprintf((char *)context->service_buffer, |
Andy Green | f54a94b | 2013-02-10 15:19:39 +0800 | [diff] [blame] | 29 | "CONNECT %s:%u HTTP/1.0\x0d\x0a" |
Andy Green | 6e40556 | 2015-11-08 10:15:01 +0800 | [diff] [blame] | 30 | "User-agent: libwebsockets\x0d\x0a", |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 31 | lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS), |
Andy Green | a7521de | 2013-02-18 10:38:45 +0800 | [diff] [blame] | 32 | wsi->u.hdr.ah->c_port); |
Andy Green | 6e40556 | 2015-11-08 10:15:01 +0800 | [diff] [blame] | 33 | |
Andy Green | f2280d6 | 2015-11-18 19:32:01 +0800 | [diff] [blame] | 34 | if (context->proxy_basic_auth_token[0]) |
Andy Green | 6e40556 | 2015-11-08 10:15:01 +0800 | [diff] [blame] | 35 | plen += sprintf((char *)context->service_buffer + plen, |
| 36 | "Proxy-authorization: basic %s\x0d\x0a", |
| 37 | context->proxy_basic_auth_token); |
| 38 | |
| 39 | plen += sprintf((char *)context->service_buffer + plen, |
| 40 | "\x0d\x0a"); |
| 41 | |
Andy Green | 36efd82 | 2013-10-25 22:07:57 +0800 | [diff] [blame] | 42 | ads = context->http_proxy_address; |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 43 | |
Andy Green | 055f297 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 44 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 45 | if (LWS_IPV6_ENABLED(context)) |
| 46 | server_addr6.sin6_port = htons(context->http_proxy_port); |
| 47 | else |
| 48 | #endif |
| 49 | server_addr4.sin_port = htons(context->http_proxy_port); |
| 50 | |
Andy Green | 36efd82 | 2013-10-25 22:07:57 +0800 | [diff] [blame] | 51 | } else { |
| 52 | ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS); |
Andy Green | 7844d04 | 2014-03-25 14:08:21 +0800 | [diff] [blame] | 53 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 54 | if (LWS_IPV6_ENABLED(context)) |
| 55 | server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port); |
| 56 | else |
| 57 | #endif |
| 58 | server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | /* |
| 62 | * prepare the actual connection (to the proxy, if any) |
| 63 | */ |
Andy Green | 6e40556 | 2015-11-08 10:15:01 +0800 | [diff] [blame] | 64 | lwsl_client("%s: address %s\n", __func__, ads); |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 65 | |
Andy Green | 055f297 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 66 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 67 | if (LWS_IPV6_ENABLED(context)) { |
| 68 | memset(&hints, 0, sizeof(struct addrinfo)); |
| 69 | n = getaddrinfo(ads, NULL, &hints, &result); |
| 70 | if (n) { |
Patrick Gansterer | fb9dc57 | 2014-04-15 18:42:57 +0200 | [diff] [blame] | 71 | #ifdef _WIN32 |
| 72 | lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n)); |
| 73 | #else |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 74 | lwsl_err("getaddrinfo: %s\n", gai_strerror(n)); |
Patrick Gansterer | fb9dc57 | 2014-04-15 18:42:57 +0200 | [diff] [blame] | 75 | #endif |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 76 | goto oom4; |
| 77 | } |
| 78 | |
| 79 | server_addr6.sin6_family = AF_INET6; |
| 80 | switch (result->ai_family) { |
| 81 | case AF_INET: |
| 82 | /* map IPv4 to IPv6 */ |
| 83 | bzero((char *)&server_addr6.sin6_addr, |
| 84 | sizeof(struct in6_addr)); |
Patrick Gansterer | 0447329 | 2014-03-28 08:28:02 +0100 | [diff] [blame] | 85 | server_addr6.sin6_addr.s6_addr[10] = 0xff; |
| 86 | server_addr6.sin6_addr.s6_addr[11] = 0xff; |
| 87 | memcpy(&server_addr6.sin6_addr.s6_addr[12], |
| 88 | &((struct sockaddr_in *)result->ai_addr)->sin_addr, |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 89 | sizeof(struct in_addr)); |
| 90 | break; |
| 91 | case AF_INET6: |
| 92 | memcpy(&server_addr6.sin6_addr, |
| 93 | &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr, |
| 94 | sizeof(struct in6_addr)); |
| 95 | break; |
| 96 | default: |
| 97 | lwsl_err("Unknown address family\n"); |
| 98 | freeaddrinfo(result); |
| 99 | goto oom4; |
| 100 | } |
| 101 | |
| 102 | freeaddrinfo(result); |
| 103 | } else |
| 104 | #endif |
| 105 | { |
Danomi Czaski | 7fb366a | 2015-04-11 07:00:51 +0800 | [diff] [blame] | 106 | struct addrinfo ai, *res, *result; |
Andy Green | 7e37d10 | 2015-01-28 21:03:49 +0800 | [diff] [blame] | 107 | void *p = NULL; |
| 108 | |
| 109 | memset (&ai, 0, sizeof ai); |
| 110 | ai.ai_family = PF_UNSPEC; |
| 111 | ai.ai_socktype = SOCK_STREAM; |
| 112 | ai.ai_flags = AI_CANONNAME; |
| 113 | |
Danomi Czaski | 7fb366a | 2015-04-11 07:00:51 +0800 | [diff] [blame] | 114 | if (getaddrinfo(ads, NULL, &ai, &result)) |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 115 | goto oom4; |
Andy Green | 7e37d10 | 2015-01-28 21:03:49 +0800 | [diff] [blame] | 116 | |
Danomi Czaski | 7fb366a | 2015-04-11 07:00:51 +0800 | [diff] [blame] | 117 | res = result; |
Andy Green | 7e37d10 | 2015-01-28 21:03:49 +0800 | [diff] [blame] | 118 | while (!p && res) { |
| 119 | switch (res->ai_family) { |
| 120 | case AF_INET: |
| 121 | p = &((struct sockaddr_in *)res->ai_addr)->sin_addr; |
| 122 | break; |
| 123 | } |
| 124 | |
| 125 | res = res->ai_next; |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 126 | } |
Andy Green | 7e37d10 | 2015-01-28 21:03:49 +0800 | [diff] [blame] | 127 | |
Danomi Czaski | 7fb366a | 2015-04-11 07:00:51 +0800 | [diff] [blame] | 128 | if (!p) { |
| 129 | freeaddrinfo(result); |
Andy Green | 7e37d10 | 2015-01-28 21:03:49 +0800 | [diff] [blame] | 130 | goto oom4; |
Danomi Czaski | 7fb366a | 2015-04-11 07:00:51 +0800 | [diff] [blame] | 131 | } |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 132 | |
| 133 | server_addr4.sin_family = AF_INET; |
Andy Green | 7e37d10 | 2015-01-28 21:03:49 +0800 | [diff] [blame] | 134 | server_addr4.sin_addr = *((struct in_addr *)p); |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 135 | bzero(&server_addr4.sin_zero, 8); |
Danomi Czaski | 7fb366a | 2015-04-11 07:00:51 +0800 | [diff] [blame] | 136 | freeaddrinfo(result); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 137 | } |
| 138 | |
Andy Green | c53f7ca | 2015-11-14 07:35:27 +0800 | [diff] [blame] | 139 | if (!lws_socket_is_valid(wsi->sock)) { |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 140 | |
Andy Green | 055f297 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 141 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 142 | if (LWS_IPV6_ENABLED(context)) |
| 143 | wsi->sock = socket(AF_INET6, SOCK_STREAM, 0); |
| 144 | else |
| 145 | #endif |
| 146 | wsi->sock = socket(AF_INET, SOCK_STREAM, 0); |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 147 | |
Andy Green | c53f7ca | 2015-11-14 07:35:27 +0800 | [diff] [blame] | 148 | if (!lws_socket_is_valid(wsi->sock)) { |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 149 | lwsl_warn("Unable to open socket\n"); |
| 150 | goto oom4; |
| 151 | } |
| 152 | |
Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 153 | if (lws_plat_set_socket_options(context, wsi->sock)) { |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 154 | lwsl_err("Failed to set wsi socket options\n"); |
| 155 | compatible_close(wsi->sock); |
| 156 | goto oom4; |
| 157 | } |
| 158 | |
| 159 | wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT; |
| 160 | |
Pokrovskiy | 20636ec | 2015-04-21 00:53:59 -0700 | [diff] [blame] | 161 | lws_libev_accept(context, wsi, wsi->sock); |
Andy Green | fc772cc | 2015-11-14 13:48:58 +0800 | [diff] [blame] | 162 | if (insert_wsi_socket_into_fds(context, wsi)) { |
| 163 | compatible_close(wsi->sock); |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 164 | goto oom4; |
Andy Green | fc772cc | 2015-11-14 13:48:58 +0800 | [diff] [blame] | 165 | } |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 166 | |
Andy Green | b5cf69f | 2015-10-18 18:47:37 +0800 | [diff] [blame] | 167 | /* |
| 168 | * past here, we can't simply free the structs as error |
| 169 | * handling as oom4 does. We have to run the whole close flow. |
| 170 | */ |
| 171 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 172 | lws_set_timeout(wsi, |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 173 | PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, |
| 174 | AWAITING_TIMEOUT); |
Andy Green | 055f297 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 175 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 176 | if (LWS_IPV6_ENABLED(context)) { |
| 177 | v = (struct sockaddr *)&client_addr6; |
| 178 | n = sizeof(client_addr6); |
| 179 | bzero((char *)v, n); |
| 180 | client_addr6.sin6_family = AF_INET6; |
| 181 | } else |
| 182 | #endif |
| 183 | { |
| 184 | v = (struct sockaddr *)&client_addr4; |
| 185 | n = sizeof(client_addr4); |
| 186 | bzero((char *)v, n); |
| 187 | client_addr4.sin_family = AF_INET; |
| 188 | } |
Mattias Lundberg | 03bb8f9 | 2014-02-18 10:06:57 +0100 | [diff] [blame] | 189 | |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 190 | if (context->iface) { |
| 191 | if (interface_to_sa(context, context->iface, |
| 192 | (struct sockaddr_in *)v, n) < 0) { |
| 193 | lwsl_err("Unable to find interface %s\n", |
| 194 | context->iface); |
Mattias Lundberg | 03bb8f9 | 2014-02-18 10:06:57 +0100 | [diff] [blame] | 195 | goto failed; |
| 196 | } |
| 197 | |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 198 | if (bind(wsi->sock, v, n) < 0) { |
| 199 | lwsl_err("Error binding to interface %s", |
| 200 | context->iface); |
Mattias Lundberg | 03bb8f9 | 2014-02-18 10:06:57 +0100 | [diff] [blame] | 201 | goto failed; |
| 202 | } |
| 203 | } |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 204 | } |
| 205 | |
Andy Green | 055f297 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 206 | #ifdef LWS_USE_IPV6 |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 207 | if (LWS_IPV6_ENABLED(context)) { |
| 208 | v = (struct sockaddr *)&server_addr6; |
| 209 | n = sizeof(struct sockaddr_in6); |
| 210 | } else |
| 211 | #endif |
| 212 | { |
| 213 | v = (struct sockaddr *)&server_addr4; |
| 214 | n = sizeof(struct sockaddr); |
| 215 | } |
Andy Green | 36efd82 | 2013-10-25 22:07:57 +0800 | [diff] [blame] | 216 | |
James Devine | 3f13ea2 | 2014-03-24 16:09:25 +0800 | [diff] [blame] | 217 | if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) { |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 218 | |
Frugality | 92b6963 | 2015-08-26 11:31:28 -0700 | [diff] [blame] | 219 | if (LWS_ERRNO == LWS_EALREADY |
| 220 | || LWS_ERRNO == LWS_EINPROGRESS |
| 221 | || LWS_ERRNO == LWS_EWOULDBLOCK |
| 222 | #ifdef _WIN32 |
| 223 | || LWS_ERRNO == WSAEINVAL |
| 224 | #endif |
| 225 | ) |
| 226 | { |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 227 | lwsl_client("nonblocking connect retry\n"); |
| 228 | |
| 229 | /* |
| 230 | * must do specifically a POLLOUT poll to hear |
| 231 | * about the connect completion |
| 232 | */ |
Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 233 | if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) |
Andy Green | b5cf69f | 2015-10-18 18:47:37 +0800 | [diff] [blame] | 234 | goto failed; |
Pokrovskiy | 20636ec | 2015-04-21 00:53:59 -0700 | [diff] [blame] | 235 | lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE); |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 236 | |
| 237 | return wsi; |
| 238 | } |
| 239 | |
Patrick Gansterer | 2dbd837 | 2014-02-28 12:37:52 +0100 | [diff] [blame] | 240 | if (LWS_ERRNO != LWS_EISCONN) { |
Patrick Gansterer | 2dbd837 | 2014-02-28 12:37:52 +0100 | [diff] [blame] | 241 | lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO); |
shys | 5efcb3f | 2013-10-25 15:49:11 +0200 | [diff] [blame] | 242 | goto failed; |
| 243 | } |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 244 | } |
| 245 | |
Andy Green | 43db045 | 2013-01-10 19:50:35 +0800 | [diff] [blame] | 246 | lwsl_client("connected\n"); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 247 | |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 248 | /* we are connected to server, or proxy */ |
| 249 | |
| 250 | if (context->http_proxy_port) { |
| 251 | |
Andy Green | 36efd82 | 2013-10-25 22:07:57 +0800 | [diff] [blame] | 252 | /* OK from now on we talk via the proxy, so connect to that */ |
| 253 | |
| 254 | /* |
| 255 | * (will overwrite existing pointer, |
| 256 | * leaving old string/frag there but unreferenced) |
| 257 | */ |
| 258 | if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, |
| 259 | context->http_proxy_address)) |
| 260 | goto failed; |
| 261 | wsi->u.hdr.ah->c_port = context->http_proxy_port; |
| 262 | |
Stephan Eberle | b820e2c | 2015-10-23 08:10:55 +0200 | [diff] [blame] | 263 | n = send(wsi->sock, (char *)context->service_buffer, plen, MSG_NOSIGNAL); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 264 | if (n < 0) { |
Andy Green | 43db045 | 2013-01-10 19:50:35 +0800 | [diff] [blame] | 265 | lwsl_debug("ERROR writing to proxy socket\n"); |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 266 | goto failed; |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 267 | } |
| 268 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 269 | lws_set_timeout(wsi, |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 270 | PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, |
| 271 | AWAITING_TIMEOUT); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 272 | |
| 273 | wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY; |
| 274 | |
| 275 | return wsi; |
| 276 | } |
| 277 | |
| 278 | /* |
| 279 | * provoke service to issue the handshake directly |
| 280 | * we need to do it this way because in the proxy case, this is the |
| 281 | * next state and executed only if and when we get a good proxy |
Andy Green | 73abc25 | 2013-01-13 11:05:30 +0800 | [diff] [blame] | 282 | * response inside the state machine... but notice in SSL case this |
| 283 | * may not have sent anything yet with 0 return, and won't until some |
| 284 | * many retries from main loop. To stop that becoming endless, |
| 285 | * cover with a timeout. |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 286 | */ |
| 287 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 288 | lws_set_timeout(wsi, |
Andy Green | 73abc25 | 2013-01-13 11:05:30 +0800 | [diff] [blame] | 289 | PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT); |
| 290 | |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 291 | wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE; |
| 292 | pfd.fd = wsi->sock; |
Patrick Gansterer | b47f87b | 2014-03-30 09:18:05 +0200 | [diff] [blame] | 293 | pfd.revents = LWS_POLLIN; |
David Galeano | 36750b8 | 2013-01-09 16:17:04 +0800 | [diff] [blame] | 294 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 295 | n = lws_service_fd(context, &pfd); |
David Galeano | 36750b8 | 2013-01-09 16:17:04 +0800 | [diff] [blame] | 296 | |
| 297 | if (n < 0) |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 298 | goto failed; |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 299 | |
David Galeano | 36750b8 | 2013-01-09 16:17:04 +0800 | [diff] [blame] | 300 | if (n) /* returns 1 on failure after closing wsi */ |
| 301 | return NULL; |
| 302 | |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 303 | return wsi; |
| 304 | |
| 305 | oom4: |
Alejandro Mery | 6ff2824 | 2014-12-04 23:59:35 +0100 | [diff] [blame] | 306 | lws_free(wsi->u.hdr.ah); |
| 307 | lws_free(wsi); |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 308 | return NULL; |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 309 | |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 310 | failed: |
Andy Green | 3ef579b | 2015-12-04 09:23:56 +0800 | [diff] [blame] | 311 | lws_close_and_free_session(context, wsi, |
Andy Green | 5dc62ea | 2013-09-20 20:26:12 +0800 | [diff] [blame] | 312 | LWS_CLOSE_STATUS_NOSTATUS); |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 313 | return NULL; |
| 314 | } |
| 315 | |
Andy Green | 90c7cbc | 2011-01-27 06:26:52 +0000 | [diff] [blame] | 316 | /** |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 317 | * lws_client_connect() - Connect to another websocket server |
Peter Hinz | 56885f3 | 2011-03-02 22:03:47 +0000 | [diff] [blame] | 318 | * @context: Websocket context |
Andy Green | 90c7cbc | 2011-01-27 06:26:52 +0000 | [diff] [blame] | 319 | * @address: Remote server address, eg, "myserver.com" |
| 320 | * @port: Port to connect to on the remote server, eg, 80 |
| 321 | * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self |
| 322 | * signed certs |
| 323 | * @path: Websocket path on server |
| 324 | * @host: Hostname on server |
| 325 | * @origin: Socket origin name |
| 326 | * @protocol: Comma-separated list of protocols being asked for from |
| 327 | * the server, or just one. The server will pick the one it |
Andy Green | a40760a | 2014-08-07 16:52:15 +0800 | [diff] [blame] | 328 | * likes best. If you don't want to specify a protocol, which is |
| 329 | * legal, use NULL here. |
Andy Green | bfb051f | 2011-02-09 08:49:14 +0000 | [diff] [blame] | 330 | * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 331 | * protocol supported, or the specific protocol ordinal |
Andy Green | 90c7cbc | 2011-01-27 06:26:52 +0000 | [diff] [blame] | 332 | * |
| 333 | * This function creates a connection to a remote server |
| 334 | */ |
| 335 | |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 336 | LWS_VISIBLE struct lws * |
| 337 | lws_client_connect(struct lws_context *context, |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 338 | const char *address, |
| 339 | int port, |
Andy Green | 90c7cbc | 2011-01-27 06:26:52 +0000 | [diff] [blame] | 340 | int ssl_connection, |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 341 | const char *path, |
| 342 | const char *host, |
| 343 | const char *origin, |
Andy Green | bfb051f | 2011-02-09 08:49:14 +0000 | [diff] [blame] | 344 | const char *protocol, |
| 345 | int ietf_version_or_minus_one) |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 346 | { |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 347 | struct lws *wsi; |
Andy Green | 3182ece | 2013-01-20 17:08:31 +0800 | [diff] [blame] | 348 | |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 349 | wsi = lws_zalloc(sizeof(struct lws)); |
Andy Green | be93fef | 2011-02-14 20:25:43 +0000 | [diff] [blame] | 350 | if (wsi == NULL) |
Andy Green | 224149a | 2013-02-11 21:43:41 +0800 | [diff] [blame] | 351 | goto bail; |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 352 | |
Andy Green | fc772cc | 2015-11-14 13:48:58 +0800 | [diff] [blame] | 353 | wsi->sock = LWS_SOCK_INVALID; |
Darin Willits | c19456f | 2011-02-14 17:52:39 +0000 | [diff] [blame] | 354 | |
Andy Green | bfb051f | 2011-02-09 08:49:14 +0000 | [diff] [blame] | 355 | /* -1 means just use latest supported */ |
| 356 | |
| 357 | if (ietf_version_or_minus_one == -1) |
Andy Green | 193306c | 2011-02-26 11:08:46 +0000 | [diff] [blame] | 358 | ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED; |
Andy Green | bfb051f | 2011-02-09 08:49:14 +0000 | [diff] [blame] | 359 | |
| 360 | wsi->ietf_spec_revision = ietf_version_or_minus_one; |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 361 | wsi->user_space = NULL; |
| 362 | wsi->state = WSI_STATE_CLIENT_UNCONNECTED; |
Andy Green | 927eb7b | 2011-02-01 08:52:55 +0000 | [diff] [blame] | 363 | wsi->protocol = NULL; |
Andy Green | a71eafc | 2011-02-14 17:59:43 +0000 | [diff] [blame] | 364 | wsi->pending_timeout = NO_PENDING_TIMEOUT; |
Andy Green | 2c24ec0 | 2014-04-02 19:45:42 +0800 | [diff] [blame] | 365 | |
Andy Green | be93fef | 2011-02-14 20:25:43 +0000 | [diff] [blame] | 366 | #ifdef LWS_OPENSSL_SUPPORT |
| 367 | wsi->use_ssl = ssl_connection; |
Andy Green | c57037a | 2014-04-03 10:17:00 +0800 | [diff] [blame] | 368 | #else |
| 369 | if (ssl_connection) { |
| 370 | lwsl_err("libwebsockets not configured for ssl\n"); |
| 371 | goto bail; |
| 372 | } |
Andy Green | be93fef | 2011-02-14 20:25:43 +0000 | [diff] [blame] | 373 | #endif |
| 374 | |
Andy Green | 16ab318 | 2013-02-10 18:02:31 +0800 | [diff] [blame] | 375 | if (lws_allocate_header_table(wsi)) |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 376 | goto bail; |
| 377 | |
| 378 | /* |
| 379 | * we're not necessarily in a position to action these right away, |
| 380 | * stash them... we only need during connect phase so u.hdr is fine |
| 381 | */ |
Andy Green | a7521de | 2013-02-18 10:38:45 +0800 | [diff] [blame] | 382 | wsi->u.hdr.ah->c_port = port; |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 383 | if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address)) |
| 384 | goto bail1; |
| 385 | |
| 386 | /* these only need u.hdr lifetime as well */ |
| 387 | |
| 388 | if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path)) |
| 389 | goto bail1; |
| 390 | |
| 391 | if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host)) |
| 392 | goto bail1; |
| 393 | |
| 394 | if (origin) |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 395 | if (lws_hdr_simple_create(wsi, |
| 396 | _WSI_TOKEN_CLIENT_ORIGIN, origin)) |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 397 | goto bail1; |
| 398 | /* |
| 399 | * this is a list of protocols we tell the server we're okay with |
| 400 | * stash it for later when we compare server response with it |
| 401 | */ |
| 402 | if (protocol) |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 403 | if (lws_hdr_simple_create(wsi, |
| 404 | _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol)) |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 405 | goto bail1; |
| 406 | |
| 407 | wsi->protocol = &context->protocols[0]; |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 408 | |
| 409 | /* |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 410 | * Check with each extension if it is able to route and proxy this |
| 411 | * connection for us. For example, an extension like x-google-mux |
| 412 | * can handle this and then we don't need an actual socket for this |
| 413 | * connection. |
Andy Green | 9659f37 | 2011-01-27 22:01:43 +0000 | [diff] [blame] | 414 | */ |
Andy Green | 2c24ec0 | 2014-04-02 19:45:42 +0800 | [diff] [blame] | 415 | |
| 416 | if (lws_ext_callback_for_each_extension_type(context, wsi, |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 417 | LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, |
Andy Green | 2c24ec0 | 2014-04-02 19:45:42 +0800 | [diff] [blame] | 418 | (void *)address, port) > 0) { |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 419 | lwsl_client("lws_client_connect: ext handling conn\n"); |
Andy Green | 5b9a4c0 | 2011-01-28 09:39:29 +0000 | [diff] [blame] | 420 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 421 | lws_set_timeout(wsi, |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 422 | PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, |
| 423 | AWAITING_TIMEOUT); |
Andy Green | 5b9a4c0 | 2011-01-28 09:39:29 +0000 | [diff] [blame] | 424 | |
Andy Green | a41314f | 2011-05-23 10:00:03 +0100 | [diff] [blame] | 425 | wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT; |
Andy Green | be93fef | 2011-02-14 20:25:43 +0000 | [diff] [blame] | 426 | return wsi; |
Andy Green | 9659f37 | 2011-01-27 22:01:43 +0000 | [diff] [blame] | 427 | } |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 428 | lwsl_client("lws_client_connect: direct conn\n"); |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 429 | |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 430 | return lws_client_connect_2(context, wsi); |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 431 | |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 432 | bail1: |
Alejandro Mery | 6ff2824 | 2014-12-04 23:59:35 +0100 | [diff] [blame] | 433 | lws_free(wsi->u.hdr.ah); |
Andy Green | e77fb80 | 2013-02-11 13:04:45 +0800 | [diff] [blame] | 434 | bail: |
Alejandro Mery | 6ff2824 | 2014-12-04 23:59:35 +0100 | [diff] [blame] | 435 | lws_free(wsi); |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 436 | |
| 437 | return NULL; |
| 438 | } |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 439 | |
| 440 | |
| 441 | /** |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 442 | * lws_client_connect_extended() - Connect to another websocket server |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 443 | * @context: Websocket context |
| 444 | * @address: Remote server address, eg, "myserver.com" |
| 445 | * @port: Port to connect to on the remote server, eg, 80 |
| 446 | * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self |
| 447 | * signed certs |
| 448 | * @path: Websocket path on server |
| 449 | * @host: Hostname on server |
| 450 | * @origin: Socket origin name |
| 451 | * @protocol: Comma-separated list of protocols being asked for from |
| 452 | * the server, or just one. The server will pick the one it |
| 453 | * likes best. |
| 454 | * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 455 | * protocol supported, or the specific protocol ordinal |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 456 | * @userdata: Pre-allocated user data |
| 457 | * |
| 458 | * This function creates a connection to a remote server |
| 459 | */ |
| 460 | |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 461 | LWS_VISIBLE struct lws * |
| 462 | lws_client_connect_extended(struct lws_context *context, |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 463 | const char *address, |
| 464 | int port, |
| 465 | int ssl_connection, |
| 466 | const char *path, |
| 467 | const char *host, |
| 468 | const char *origin, |
| 469 | const char *protocol, |
| 470 | int ietf_version_or_minus_one, |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 471 | void *userdata) |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 472 | { |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 473 | struct lws *ws = |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 474 | lws_client_connect(context, address, port, |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 475 | ssl_connection, path, host, origin, protocol, |
| 476 | ietf_version_or_minus_one); |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 477 | |
Andy Green | 9785085 | 2014-07-05 10:31:12 +0800 | [diff] [blame] | 478 | if (ws && !ws->user_space && userdata) { |
| 479 | ws->user_space_externally_allocated = 1; |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 480 | ws->user_space = userdata ; |
Andy Green | 9785085 | 2014-07-05 10:31:12 +0800 | [diff] [blame] | 481 | } |
David Brooks | 2c60d95 | 2012-04-20 12:19:01 +0800 | [diff] [blame] | 482 | |
| 483 | return ws ; |
Andy Green | b5b2319 | 2013-02-11 17:13:32 +0800 | [diff] [blame] | 484 | } |