From 687b0188bcabd04adb07a935c3a95302db042988 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sat, 26 Feb 2011 11:04:01 +0000 Subject: [PATCH] require close reason argument on close and free session Signed-off-by: Andy Green --- lib/handshake.c | 3 ++- lib/libwebsockets.c | 65 +++++++++++++++++++++++++++----------------- lib/libwebsockets.h | 47 ++++++++++++++++++++++++++++++-- lib/parsers.c | 66 ++++++++++++++++++++++++++++----------------- lib/private-libwebsockets.h | 40 ++------------------------- 5 files changed, 130 insertions(+), 91 deletions(-) diff --git a/lib/handshake.c b/lib/handshake.c index 91214b8..b4779f4 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -611,7 +611,8 @@ libwebsocket_read(struct libwebsocket_context *this, struct libwebsocket *wsi, return 0; bail: - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return -1; } diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 397dc70..12c8778 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -131,7 +131,7 @@ interface_to_sa(const char* ifname, struct sockaddr_in *addr, size_t addrlen) void libwebsocket_close_and_free_session(struct libwebsocket_context *this, - struct libwebsocket *wsi) + struct libwebsocket *wsi, enum lws_close_status reason) { int n; int old_state; @@ -169,6 +169,8 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *this, this->protocols[0].callback(this, wsi, LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0); + wsi->close_reason = reason; + /* * signal we are closing, libsocket_write will * add any necessary version-specific stuff. If the write fails, @@ -244,7 +246,7 @@ libwebsockets_hangup_on_client(struct libwebsocket_context *this, int fd) this->fds_count--; } - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, 0); } @@ -375,7 +377,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this, */ if (tv.tv_sec > wsi->pending_timeout_limit) - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); } } @@ -590,7 +593,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this, debug("Session Socket %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NORMAL); return 1; } @@ -676,20 +680,23 @@ libwebsocket_service_fd(struct libwebsocket_context *this, fprintf(stderr, "Proxy connection %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; } n = recv(wsi->sock, pkt, sizeof pkt, 0); if (n < 0) { - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); fprintf(stderr, "ERROR reading from proxy socket\n"); return 1; } pkt[13] = '\0'; if (strcmp(pkt, "HTTP/1.0 200 ") != 0) { - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); fprintf(stderr, "ERROR from proxy: %s\n", pkt); return 1; } @@ -714,21 +721,23 @@ libwebsocket_service_fd(struct libwebsocket_context *this, if (SSL_connect(wsi->ssl) <= 0) { fprintf(stderr, "SSL connect error %s\n", - ERR_error_string(ERR_get_error(), ssl_err_buf)); - libwebsocket_close_and_free_session(this, wsi); + ERR_error_string(ERR_get_error(), + ssl_err_buf)); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; } n = SSL_get_verify_result(wsi->ssl); - if (n != X509_V_OK) { - if (n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || - wsi->use_ssl != 2) { - - fprintf(stderr, "server's cert didn't " - "look good %d\n", n); - libwebsocket_close_and_free_session(this, wsi); - return 1; - } + if (n != X509_V_OK) && ( + n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || + wsi->use_ssl != 2)) { + + fprintf(stderr, "server's cert didn't " + "look good %d\n", n); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + return 1; } } else { wsi->ssl = NULL; @@ -753,7 +762,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this, free(wsi->c_origin); if (wsi->c_protocol) free(wsi->c_protocol); - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -819,7 +829,8 @@ libwebsocket_service_fd(struct libwebsocket_context *this, if (n < 0) { fprintf(stderr, "ERROR writing to client socket\n"); - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -890,7 +901,7 @@ libwebsocket_service_fd(struct libwebsocket_context *this, (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len && wsi->c_protocol != NULL)) { fprintf(stderr, "libwebsocket_client_handshake " - "missing required header(s)\n"); + "missing required header(s)\n"); pkt[len] = '\0'; fprintf(stderr, "%s", pkt); goto bail3; @@ -1061,7 +1072,8 @@ bail3: free(wsi->c_protocol); bail2: - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; @@ -1075,7 +1087,8 @@ bail2: fprintf(stderr, "Session Socket %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -1113,7 +1126,8 @@ bail2: break; } if (!n) { - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_NOSTATUS); return 1; } @@ -1150,7 +1164,8 @@ libwebsocket_context_destroy(struct libwebsocket_context *this) for (n = 0; n < FD_HASHTABLE_MODULUS; n++) for (m = 0; m < this->fd_hashtable[n].length; m++) { wsi = this->fd_hashtable[n].wsi[m]; - libwebsocket_close_and_free_session(this, wsi); + libwebsocket_close_and_free_session(this, wsi, + LWS_CLOSE_STATUS_GOINGAWAY); } close(this->fd_random); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 620c576..fe7238f 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -123,6 +123,45 @@ enum lws_token_indexes { WSI_PARSING_COMPLETE }; +/* + * From 06 sped + 1000 + + 1000 indicates a normal closure, meaning whatever purpose the + connection was established for has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down, or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g. an + endpoint that understands only text data may send this if it + receives a binary message.) + + 1004 + + 1004 indicates that an endpoint is terminating the connection + because it has received a message that is too large. +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_PAYLOAD_TOO_LARGE = 1004, +}; + struct libwebsocket; struct libwebsocket_context; @@ -367,7 +406,11 @@ libwebsocket_service_fd(struct libwebsocket_context *context, * use the whole buffer without taking care of the above. */ -/* this is the frame nonce plus two header plus 8 length */ +/* + * this is the frame nonce plus two header plus 8 length + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ #define LWS_SEND_BUFFER_PRE_PADDING (4 + 10) #define LWS_SEND_BUFFER_POST_PADDING 1 @@ -430,6 +473,6 @@ libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd); extern void libwebsocket_close_and_free_session(struct libwebsocket_context *context, - struct libwebsocket *wsi); + struct libwebsocket *wsi, enum lws_close_status); #endif diff --git a/lib/parsers.c b/lib/parsers.c index d6cae1c..481caf1 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -1139,8 +1139,11 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, * in both client and server directions */ - if (wsi->ietf_spec_revision >= 5) { - + switch (wsi->ietf_spec_revision) { + case 0: + case 4: + break; + case 5: /* we can do this because we demand post-buf */ if (len < 1) @@ -1162,6 +1165,19 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, default: break; } + break; + default: + /* + * 06 has a 2-byte status code in network order + * we can do this because we demand post-buf + */ + + if (wsi->close_reason) { + buf[pre - 2] = wsi->close_reason >> 8; + buf[pre - 1] = wsi->close_reason; + pre += 2; + } + break; } break; case LWS_WRITE_PING: @@ -1181,35 +1197,35 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, n |= 1 << 7; if (len < 126) { - buf[-2] = n; - buf[-1] = len; - pre = 2; + buf[pre - 2] = n; + buf[pre - 1] = len; + pre += 2; } else { if (len < 65536) { - buf[-4] = n; - buf[-3] = 126; - buf[-2] = len >> 8; - buf[-1] = len; - pre = 4; + buf[pre - 4] = n; + buf[pre - 3] = 126; + buf[pre - 2] = len >> 8; + buf[pre - 1] = len; + pre += 4; } else { - buf[-10] = n; - buf[-9] = 127; + buf[pre - 10] = n; + buf[pre - 9] = 127; #if defined __LP64__ - buf[-8] = (len >> 56) & 0x7f; - buf[-7] = len >> 48; - buf[-6] = len >> 40; - buf[-5] = len >> 32; + buf[pre - 8] = (len >> 56) & 0x7f; + buf[pre - 7] = len >> 48; + buf[pre - 6] = len >> 40; + buf[pre - 5] = len >> 32; #else - buf[-8] = 0; - buf[-7] = 0; - buf[-6] = 0; - buf[-5] = 0; + buf[pre - 8] = 0; + buf[pre - 7] = 0; + buf[pre - 6] = 0; + buf[pre - 5] = 0; #endif - buf[-4] = len >> 24; - buf[-3] = len >> 16; - buf[-2] = len >> 8; - buf[-1] = len; - pre = 10; + buf[pre - 4] = len >> 24; + buf[pre - 3] = len >> 16; + buf[pre - 2] = len >> 8; + buf[pre - 1] = len; + pre += 10; } } break; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 9d3723e..493fd22 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -93,44 +93,6 @@ static inline void debug(const char *format, ...) #define MAX_WEBSOCKET_04_KEY_LEN 128 #define SYSTEM_RANDOM_FILEPATH "/dev/urandom" -/* - * From 06 sped - 1000 - - 1000 indicates a normal closure, meaning whatever purpose the - connection was established for has been fulfilled. - - 1001 - - 1001 indicates that an endpoint is "going away", such as a server - going down, or a browser having navigated away from a page. - - 1002 - - 1002 indicates that an endpoint is terminating the connection due - to a protocol error. - - 1003 - - 1003 indicates that an endpoint is terminating the connection - because it has received a type of data it cannot accept (e.g. an - endpoint that understands only text data may send this if it - receives a binary message.) - - 1004 - - 1004 indicates that an endpoint is terminating the connection - because it has received a message that is too large. -*/ - -enum lws_close_status { - LWS_CLOSE_STATUS_NORMAL = 1000, - LWS_CLOSE_STATUS_GOINGAWAY = 1001, - LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, - LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, - LWS_CLOSE_STATUS_PAYLOAD_TOO_LARGE = 1004, -}; - enum lws_websocket_opcodes_04 { LWS_WS_OPCODE_04__CONTINUATION = 0, LWS_WS_OPCODE_04__CLOSE = 1, @@ -278,6 +240,8 @@ struct libwebsocket { unsigned char (*xor_mask)(struct libwebsocket *, unsigned char); char all_zero_nonce; + enum lws_close_status close_reason; + /* client support */ char initial_handshake_hash_base64[30]; enum connection_mode mode; -- 2.7.4