const char *cce = NULL;
unsigned char c;
char *sb = p;
- int n, len;
+ int n = 0, len = 0;
+#if defined(LWS_WITH_SOCKS5)
+ char conn_mode = 0, pending_timeout = 0;
+#endif
switch (wsi->mode) {
/* either still pending connection, or changed mode */
return 0;
+#if defined(LWS_WITH_SOCKS5)
+ /* SOCKS Greeting Reply */
+ case LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:
+
+ /* handle proxy hung up on us */
+
+ if (pollfd->revents & LWS_POLLHUP) {
+
+ lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ return 0;
+ }
+
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+ if (n < 0) {
+ if (LWS_ERRNO == LWS_EAGAIN) {
+ lwsl_debug("SOCKS read returned EAGAIN..."
+ "retrying\n");
+ return 0;
+ }
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_err("ERROR reading from SOCKS socket\n");
+ return 0;
+ }
+
+ /* processing greeting reply */
+ if (pt->serv_buf[0] == SOCKS_VERSION_5
+ && pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH)
+ {
+ lwsl_client("%s\n", "SOCKS greeting reply received "
+ "- No Authentication Method");
+ socks_generate_msg(wsi, SOCKS_MSG_CONNECT, (size_t *)&len);
+
+ conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;
+ pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+ lwsl_client("%s\n", "Sending SOCKS connect command");
+ }
+ else if (pt->serv_buf[0] == SOCKS_VERSION_5
+ && pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD)
+ {
+ lwsl_client("%s\n", "SOCKS greeting reply received "
+ "- User Name Password Method");
+ socks_generate_msg(wsi, SOCKS_MSG_USERNAME_PASSWORD,
+ (size_t *)&len);
+
+ conn_mode = LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY;
+ pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
+ lwsl_client("%s\n", "Sending SOCKS user/password");
+ }
+ else
+ {
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_err("ERROR SOCKS greeting reply failed, method "
+ "code: %d\n", pt->serv_buf[1]);
+ return 0;
+ }
+
+ n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
+ MSG_NOSIGNAL);
+ if (n < 0) {
+ lwsl_debug("ERROR writing socks command to socks proxy "
+ "socket\n");
+ return 0;
+ }
+
+ lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
+ wsi->mode = conn_mode;
+
+ break;
+ /* SOCKS auth Reply */
+ case LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:
+
+ /* handle proxy hung up on us */
+
+ if (pollfd->revents & LWS_POLLHUP) {
+
+ lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ return 0;
+ }
+
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+ if (n < 0) {
+ if (LWS_ERRNO == LWS_EAGAIN) {
+ lwsl_debug("SOCKS read returned EAGAIN... "
+ "retrying\n");
+ return 0;
+ }
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_err("ERROR reading from socks socket\n");
+ return 0;
+ }
+
+ /* processing auth reply */
+ if (pt->serv_buf[0] == SOCKS_SUBNEGOTIATION_VERSION_1
+ && pt->serv_buf[1] == SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
+ {
+ lwsl_client("%s\n", "SOCKS password reply recieved - "
+ "successful");
+ socks_generate_msg(wsi, SOCKS_MSG_CONNECT, (size_t *)&len);
+
+ conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;
+ pending_timeout =
+ PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+ lwsl_client("%s\n", "Sending SOCKS connect command");
+ }
+ else
+ {
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_err("ERROR : SOCKS user/password reply failed, "
+ "error code: %d\n", pt->serv_buf[1]);
+ return 0;
+ }
+
+ n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
+ MSG_NOSIGNAL);
+ if (n < 0) {
+ lwsl_debug("ERROR writing connect command to SOCKS "
+ "socket\n");
+ return 0;
+ }
+
+ lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
+ wsi->mode = conn_mode;
+
+ break;
+
+ /* SOCKS connect command Reply */
+ case LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:
+
+ /* handle proxy hung up on us */
+
+ if (pollfd->revents & LWS_POLLHUP) {
+
+ lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ return 0;
+ }
+
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+ if (n < 0) {
+ if (LWS_ERRNO == LWS_EAGAIN) {
+ lwsl_debug("SOCKS read returned EAGAIN... "
+ "retrying\n");
+ return 0;
+ }
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_err("ERROR reading from socks socket\n");
+ return 0;
+ }
+
+ /* processing connect reply */
+ if (pt->serv_buf[0] == SOCKS_VERSION_5
+ && pt->serv_buf[1] == SOCKS_REQUEST_REPLY_SUCCESS)
+ {
+ lwsl_client("%s\n", "SOCKS connect reply recieved - "
+ "successful");
+ }
+ else
+ {
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_err("ERROR SOCKS connect reply failed, error "
+ "code: %d\n", pt->serv_buf[1]);
+ return 0;
+ }
+
+ /* free stash since we are done with it */
+ lws_free_set_NULL(wsi->u.hdr.stash);
+
+ if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+ wsi->vhost->socks_proxy_address))
+ goto bail3;
+ wsi->c_port = wsi->vhost->socks_proxy_port;
+
+ /* clear his proxy connection timeout */
+
+ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+ goto start_ws_hanshake;
+#endif
case LWSCM_WSCL_WAITING_PROXY_REPLY:
/* handle proxy hung up on us */
return 0;
}
- n = recv(wsi->sock, sb, context->pt_serv_buf_size, 0);
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
if (n < 0) {
if (LWS_ERRNO == LWS_EAGAIN) {
lwsl_debug("Proxy read returned EAGAIN... retrying\n");
* take care of our lws_callback_on_writable
* happening at a time when there's no real connection yet
*/
+#if defined(LWS_WITH_SOCKS5)
+start_ws_hanshake:
+#endif
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
return -1;
case LWSCM_WSCL_ISSUE_HANDSHAKE2:
p = lws_generate_client_handshake(wsi, p);
if (p == NULL) {
+ if (wsi->mode == LWSCM_RAW)
+ return 0;
+
lwsl_err("Failed to generate handshake for client\n");
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return 0;
bail3:
lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
- wsi->vhost->protocols[0].callback(wsi,
+ if (cce)
+ lwsl_info("reason: %s\n", cce);
+ wsi->protocol->callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, (void *)cce, cce ? strlen(cce) : 0);
wsi->already_did_cce = 1;
return 1;
}
+ /* we don't support chained client connections yet */
+ return 1;
+
/* otherwise set ourselves up ready to go again */
wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
wsi->mode = LWSCM_HTTP_CLIENT_ACCEPTED;
struct lws_context *context = wsi->context;
const char *pc, *prot, *ads = NULL, *path, *cce = NULL;
struct allocated_headers *ah = NULL;
- char *p;
+ char *p, *q;
+ char new_path[300];
#ifndef LWS_NO_EXTENSIONS
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
char *sb = (char *)&pt->serv_buf[0];
void *v;
#endif
+ ah = wsi->u.hdr.ah;
if (!wsi->do_ws) {
/* we are being an http client...
*/
- ah = wsi->u.hdr.ah;
lws_union_transition(wsi, LWSCM_HTTP_CLIENT_ACCEPTED);
wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
wsi->u.http.ah = ah;
goto bail3;
}
- if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
- cce = "HS: URI did not parse";
- goto bail3;
+ /* Relative reference absolute path */
+ if (p[0] == '/')
+ {
+#ifdef LWS_OPENSSL_SUPPORT
+ ssl = wsi->use_ssl;
+#endif
+ ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+ port = wsi->c_port;
+ path = p + 1; /* +1 as lws_client_reset expects leading / to be omitted */
}
+ /* Absolute (Full) URI */
+ else if (strchr(p, ':'))
+ {
+ if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
+ cce = "HS: URI did not parse";
+ goto bail3;
+ }
- if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
- ssl = 1;
+ if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
+ ssl = 1;
+ }
+ /* Relative reference relative path */
+ else
+ {
+ /* This doesn't try to calculate an absolute path, that will be left to the server */
+#ifdef LWS_OPENSSL_SUPPORT
+ ssl = wsi->use_ssl;
+#endif
+ ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+ port = wsi->c_port;
+ path = new_path + 1; /* +1 as lws_client_reset expects leading / to be omitted */
+ strncpy(new_path, lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), sizeof(new_path));
+ new_path[sizeof(new_path) - 1] = '\0';
+ q = strrchr(new_path, '/');
+ if (q)
+ {
+ strncpy(q + 1, p, sizeof(new_path) - (q - new_path) - 1);
+ new_path[sizeof(new_path) - 1] = '\0';
+ }
+ else
+ {
+ path = p;
+ }
+ }
- lwsl_notice("ssl %d %s\n", ssl, prot);
+#ifdef LWS_OPENSSL_SUPPORT
+ if (wsi->use_ssl && !ssl) {
+ cce = "HS: Redirect attempted SSL downgrade";
+ goto bail3;
+ }
+#endif
- if (!lws_client_reset(wsi, ssl, ads, port, path, ads)) {
+ if (!lws_client_reset(&wsi, ssl, ads, port, path, ads)) {
+ /* there are two ways to fail out with NULL return...
+ * simple, early problem where the wsi is intact, or
+ * we went through with the reconnect attempt and the
+ * wsi is already closed. In the latter case, the wsi
+ * has beet set to NULL additionally.
+ */
lwsl_err("Redirect failed\n");
cce = "HS: Redirect failed";
- goto bail3;
+ if (wsi)
+ goto bail3;
+
+ return 1;
}
return 0;
}
if (!wsi->do_ws) {
- if (n != 200 && n != 304) {
+ if (n != 200 && n != 201 && n != 304 && n != 401) {
lwsl_notice("Connection failed with code %d\n", n);
- cce = "HS: Server did not return 200 or 304";
+ cce = "HS: Server unrecognized response code";
goto bail2;
}
wsi->u.http.content_length =
atoi(lws_hdr_simple_ptr(wsi,
WSI_TOKEN_HTTP_CONTENT_LENGTH));
- lwsl_notice("%s: incoming content length %d\n", __func__,
- wsi->u.http.content_length);
+ lwsl_notice("%s: incoming content length %llu\n", __func__,
+ (unsigned long long)wsi->u.http.content_length);
wsi->u.http.content_remain = wsi->u.http.content_length;
} else /* can't do 1.1 without a content length or chunked */
if (!wsi->chunked)
wsi->u.ws.rx_ubuf_alloc = n;
lwsl_info("Allocating client RX buffer %d\n", n);
- if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n,
+#if !defined(LWS_WITH_ESP32)
+ if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&n,
sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
cce = "HS: SO_SNDBUF failed";
goto bail3;
}
+#endif
lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
const struct lws_extension *ext;
int ext_count = 0;
#endif
+ const char *pp = lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
if (!meth) {
meth = "GET";
wsi->do_ws = 1;
- } else
+ } else {
wsi->do_ws = 0;
+ }
+
+ if (!strcmp(meth, "RAW")) {
+ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+ lwsl_notice("client transition to raw\n");
+
+ if (pp) {
+ const struct lws_protocols *pr;
+
+ pr = lws_vhost_name_to_protocol(wsi->vhost, pp);
+
+ if (!pr) {
+ lwsl_err("protocol %s not enabled on vhost\n",
+ pp);
+ return NULL;
+ }
+
+ lws_bind_protocol(wsi, pr);
+ }
+
+ if ((wsi->protocol->callback)(wsi,
+ LWS_CALLBACK_RAW_ADOPT,
+ wsi->user_space, NULL, 0))
+ return NULL;
+
+ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
+ lws_union_transition(wsi, LWSCM_RAW);
+ lws_header_table_detach(wsi, 1);
+
+ return NULL;
+ }
if (wsi->do_ws) {
/*
/* give userland a chance to append, eg, cookies */
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
+ wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
wsi->user_space, &p, (pkt + context->pt_serv_buf_size) - p - 12);
p += sprintf(p, "\x0d\x0a");