Skip to content

Commit

Permalink
merge https://github.com/warmcat/libwebsockets.git and git://git.libw…
Browse files Browse the repository at this point in the history
…ebsockets.org/libwebsockets
  • Loading branch information
u0u0 committed Sep 22, 2013
2 parents 4e6621a + 5dc62ea commit 18cfbcc
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 177 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ endif(UNIX)


if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set( CMAKE_C_FLAGS "-Wall -O4 -fvisibility=hidden " )
set( CMAKE_C_FLAGS "-Wall -Werror -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" )
endif ()

source_group("Headers Private" FILES ${HDR_PRIVATE})
Expand Down
20 changes: 20 additions & 0 deletions README.coding
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,23 @@ is too computationally expensive. To use it, point it to a string like

if left NULL, then the "DEFAULT" set of ciphers are all possible to select.


Async nature of client connections
----------------------------------

When you call libwebsocket_client_connect(..) and get a wsi back, it does not
mean your connection is active. It just mean it started trying to connect.

Your client connection is actually active only when you receive
LWS_CALLBACK_CLIENT_ESTABLISHED for it.

There's a 5 second timeout for the connection, and it may give up or die for
other reasons, if any of that happens you'll get a
LWS_CALLBACK_CLIENT_CONNECTION_ERROR callback on protocol 0 instead for the
wsi.

After attempting the connection and getting back a non-NULL wsi you should
loop calling libwebsocket_service() until one of the above callbacks occurs.

As usual, see test-client.c for example code.

10 changes: 10 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ User api additions
- there's a new, optional callback LWS_CALLBACK_CLOSED_HTTP which gets
called when an HTTP protocol socket closes

- for LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION callback, the user_space alloc
has already been done before the callback happens. That means we can
use the user parameter to the callback to contain the user pointer, and
move the protocol name to the "in" parameter. The docs for this
callback are also updated to reflect how to check headers in there.

- libwebsocket_client_connect() is now properly nonblocking and async. See
README.coding and test-client.c for information on the callbacks you
can rely on controlling the async connection period with.


User api changes
----------------
Expand Down
96 changes: 0 additions & 96 deletions lib/base64-decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,99 +91,3 @@ lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)

return done;
}

/*
* returns length of decoded string in out, or -1 if out was too small
* according to out_size
*/

LWS_VISIBLE int
lws_b64_decode_string(const char *in, char *out, int out_size)
{
int len;
int i;
int done = 0;
unsigned char v;
unsigned char quad[4];

while (*in) {

len = 0;
for (i = 0; i < 4 && *in; i++) {

v = 0;
while (*in && !v) {

v = *in++;
v = (v < 43 || v > 122) ? 0 : decode[v - 43];
if (v)
v = (v == '$') ? 0 : v - 61;
if (*in) {
len++;
if (v)
quad[i] = v - 1;
} else
quad[i] = 0;
}
}
if (!len)
continue;

if (out_size < (done + len - 1))
/* out buffer is too small */
return -1;

if (len >= 2)
*out++ = quad[0] << 2 | quad[1] >> 4;
if (len >= 3)
*out++ = quad[1] << 4 | quad[2] >> 2;
if (len >= 4)
*out++ = ((quad[2] << 6) & 0xc0) | quad[3];

done += len - 1;
}

if (done + 1 >= out_size)
return -1;

*out++ = '\0';

return done;
}

int
lws_b64_selftest(void)
{
char buf[64];
int n;
int test;
static const char * const plaintext[] = {
"sanity check base 64"
};
static const char * const coded[] = {
"c2FuaXR5IGNoZWNrIGJhc2UgNjQ="
};

for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) {

buf[sizeof(buf) - 1] = '\0';
n = lws_b64_encode_string(plaintext[test],
strlen(plaintext[test]), buf, sizeof buf);
if (n != strlen(coded[test]) || strcmp(buf, coded[test])) {
lwsl_err("Failed lws_b64 encode selftest "
"%d result '%s' %d\n", test, buf, n);
return -1;
}

buf[sizeof(buf) - 1] = '\0';
n = lws_b64_decode_string(coded[test], buf, sizeof buf);
if (n != strlen(plaintext[test]) ||
strcmp(buf, plaintext[test])) {
lwsl_err("Failed lws_b64 decode selftest "
"%d result '%s' %d\n", test, buf, n);
return -1;
}
}

return 0;
}
65 changes: 48 additions & 17 deletions lib/client-handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,28 @@ struct libwebsocket *__libwebsocket_client_connect_2(
goto oom4;
}

wsi->sock = socket(AF_INET, SOCK_STREAM, 0);

if (wsi->sock < 0) {
lwsl_warn("Unable to open socket\n");
goto oom4;

wsi->sock = socket(AF_INET, SOCK_STREAM, 0);

if (wsi->sock < 0) {
lwsl_warn("Unable to open socket\n");
goto oom4;
}

if (lws_set_socket_options(context, wsi->sock)) {
lwsl_err("Failed to set wsi socket options\n");
compatible_close(wsi->sock);
goto oom4;
}

wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT;

insert_wsi_socket_into_fds(context, wsi);

libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
}

server_addr.sin_family = AF_INET;
Expand All @@ -66,30 +83,39 @@ struct libwebsocket *__libwebsocket_client_connect_2(

if (connect(wsi->sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1) {
lwsl_debug("Connect failed\n");
compatible_close(wsi->sock);
goto oom4;
}

lwsl_client("connected\n");
if (errno == EALREADY || errno == EINPROGRESS) {
lwsl_client("nonblocking connect retry\n");

if (lws_set_socket_options(context, wsi->sock)) {
lwsl_err("Failed to set wsi socket options\n");
compatible_close(wsi->sock);
goto oom4;
/*
* must do specifically a POLLOUT poll to hear
* about the connect completion
*/

context->fds[wsi->position_in_fds_table].events |= POLLOUT;

/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_SET_MODE_POLL_FD,
wsi->user_space, (void *)(long)wsi->sock, POLLOUT);

return wsi;
}

lwsl_debug("Connect failed errno=%d\n", errno);
goto failed;
}

insert_wsi_socket_into_fds(context, wsi);
lwsl_client("connected\n");

/* we are connected to server, or proxy */

if (context->http_proxy_port) {

n = send(wsi->sock, context->service_buffer, plen, MSG_NOSIGNAL);
if (n < 0) {
compatible_close(wsi->sock);
lwsl_debug("ERROR writing to proxy socket\n");
goto oom4;
goto failed;
}

libwebsocket_set_timeout(wsi,
Expand Down Expand Up @@ -121,7 +147,7 @@ struct libwebsocket *__libwebsocket_client_connect_2(
n = libwebsocket_service_fd(context, &pfd);

if (n < 0)
goto oom4;
goto failed;

if (n) /* returns 1 on failure after closing wsi */
return NULL;
Expand All @@ -131,7 +157,11 @@ struct libwebsocket *__libwebsocket_client_connect_2(
oom4:
free(wsi->u.hdr.ah);
free(wsi);
return NULL;

failed:
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return NULL;
}

Expand Down Expand Up @@ -185,6 +215,7 @@ libwebsocket_client_connect(struct libwebsocket_context *context,
goto bail;

memset(wsi, 0, sizeof(*wsi));
wsi->sock = -1;

/* -1 means just use latest supported */

Expand Down
18 changes: 17 additions & 1 deletion lib/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ int lws_client_socket_service(struct libwebsocket_context *context,

switch (wsi->mode) {

case LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT:

/*
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
* timeout protection set in client-handshake.c
*/

if (__libwebsocket_client_connect_2(context, wsi) == NULL) {
/* closed */
lwsl_client("closed\n");
return -1;
}

/* either still pending connection, or changed mode */
return 0;

case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:

/* handle proxy hung up on us */
Expand Down Expand Up @@ -333,7 +349,7 @@ int lws_client_socket_service(struct libwebsocket_context *context,
"closing connection at LWS_CONNMODE...SERVER_REPLY\n");
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
return -1;

case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
lwsl_ext("LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT\n");
Expand Down
18 changes: 11 additions & 7 deletions lib/handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ libwebsocket_read(struct libwebsocket_context *context,

if (n) {
lwsl_info("LWS_CALLBACK_HTTP closing\n");
goto bail;
goto bail; /* struct ah ptr already nuked */
}

return 0;
Expand Down Expand Up @@ -196,17 +196,21 @@ libwebsocket_read(struct libwebsocket_context *context,
}
}

/* allocate wsi->user storage */
if (libwebsocket_ensure_user_space(wsi))
goto bail_nuke_ah;

/*
* Give the user code a chance to study the request and
* have the opportunity to deny it
*/

if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL),
NULL, 0)) {
wsi->user_space,
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
lwsl_warn("User code denied connection\n");
goto bail;
goto bail_nuke_ah;
}


Expand All @@ -220,17 +224,17 @@ libwebsocket_read(struct libwebsocket_context *context,
lwsl_parser("lws_parse calling handshake_04\n");
if (handshake_0405(context, wsi)) {
lwsl_info("hs0405 has failed the connection\n");
goto bail;
goto bail_nuke_ah;
}
break;

default:
lwsl_warn("Unknown client spec version %d\n",
wsi->ietf_spec_revision);
goto bail;
goto bail_nuke_ah;
}

/* drop the header info */
/* drop the header info -- no bail_nuke_ah after this */

if (wsi->u.hdr.ah)
free(wsi->u.hdr.ah);
Expand Down
Loading

0 comments on commit 18cfbcc

Please sign in to comment.