Skip to content

Commit 1061879

Browse files
authored
Merge branch 'master' into realloc_crash
2 parents 3551509 + a8f9394 commit 1061879

File tree

5 files changed

+123
-17
lines changed

5 files changed

+123
-17
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ if (KS_PLAT_WIN OR WITH_KS_TEST)
4040
endif()
4141

4242
# Declare our project, libks2
43-
project(LibKS2 VERSION 2.0.2 LANGUAGES C CXX)
43+
project(LibKS2 VERSION 2.0.3 LANGUAGES C CXX)
4444
message("LibKS2 Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
4545

4646
# Set package version

src/include/libks/ks.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@
3030
#endif
3131

3232
/* libks version as a string */
33-
#define KS_VERSION "2.0.2"
33+
#define KS_VERSION "2.0.3"
3434

3535
/* libks version as a number */
36-
#define KS_VERSION_NUM 20002
36+
#define KS_VERSION_NUM 20003
3737

3838
/* Use this to allow enabling TCP_KEEPIDLE and TCP_KEEPINTVL socket options */
3939
//#define KS_KEEP_IDLE_INTVL 1

src/include/libks/kws.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ typedef enum {
3535
WS_DATA_TOO_BIG = 1009
3636
} kws_cause_t;
3737

38+
#define WS_NORMAL_CLOSE 1000
39+
3840
typedef enum {
3941
WSOC_CONTINUATION = 0x0,
4042
WSOC_TEXT = 0x1,

src/kws.c

Lines changed: 117 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
#pragma warning(disable: 4706)
2929
#endif
3030

31-
#define WS_BLOCK 1
31+
#define WS_BLOCK 10000 /* ms, blocks read operation for 10 seconds */
32+
#define WS_SOFT_BLOCK 1000 /* ms, blocks read operation for 1 second */
3233
#define WS_NOBLOCK 0
3334

3435
#define WS_INIT_SANITY 5000
@@ -70,6 +71,7 @@ struct kws_s {
7071
char cipher_name[128];
7172
kws_flag_t flags;
7273
int x;
74+
int ssl_io_error;
7375
void *write_buffer;
7476
ks_size_t write_buffer_len;
7577
char *req_uri;
@@ -397,12 +399,14 @@ static int ws_server_handshake(kws_t *kws)
397399

398400
}
399401

402+
#define SSL_IO_ERROR(err) (err == SSL_ERROR_SYSCALL || err == SSL_ERROR_SSL)
400403
#define SSL_ERROR_WANT_READ_WRITE(err) (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
401404

402405
KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int block)
403406
{
404407
int r;
405408
int ssl_err = 0;
409+
int block_n = block / 10;
406410

407411
if (kws->unprocessed_buffer_len > 0) {
408412
if (kws->unprocessed_buffer_len > bytes) {
@@ -430,6 +434,9 @@ KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int
430434
ssl_err = SSL_get_error(kws->ssl, r);
431435
if (ssl_err != SSL_ERROR_ZERO_RETURN) {
432436
ks_log(KS_LOG_WARNING, "Weird SSL_read error: %d\n", ssl_err);
437+
if (SSL_IO_ERROR(ssl_err)) {
438+
kws->ssl_io_error = 1;
439+
}
433440
}
434441
}
435442

@@ -444,12 +451,16 @@ KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int
444451
kws->x++;
445452
ks_sleep_ms(10);
446453
} else {
454+
if (SSL_IO_ERROR(ssl_err)) {
455+
kws->ssl_io_error = 1;
456+
}
457+
447458
r = -1;
448459
goto end;
449460
}
450461
}
451462

452-
} while (r < 0 && SSL_ERROR_WANT_READ_WRITE(ssl_err) && kws->x < 1000);
463+
} while (r < 0 && SSL_ERROR_WANT_READ_WRITE(ssl_err) && kws->x < block_n);
453464

454465
goto end;
455466
}
@@ -468,11 +479,11 @@ KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int
468479
ks_sleep_ms(10);
469480
}
470481
}
471-
} while (r == -1 && ks_errno_is_blocking(ks_errno()) && kws->x < 1000);
482+
} while (r == -1 && ks_errno_is_blocking(ks_errno()) && kws->x < block_n);
472483

473484
end:
474485

475-
if (kws->x >= 10000 || (block && kws->x >= 1000)) {
486+
if (kws->x >= 10000 || (block && kws->x >= block_n)) {
476487
r = -1;
477488
}
478489

@@ -555,6 +566,11 @@ KS_DECLARE(ks_ssize_t) kws_raw_write(kws_t *kws, void *data, ks_size_t bytes)
555566
r = SSL_write(kws->ssl, (void *)((unsigned char *)data + wrote), (int)(bytes - wrote));
556567

557568
if (r == 0) {
569+
ssl_err = SSL_get_error(kws->ssl, r);
570+
if (SSL_IO_ERROR(ssl_err)) {
571+
kws->ssl_io_error = 1;
572+
}
573+
558574
ssl_err = 42;
559575
break;
560576
}
@@ -573,15 +589,21 @@ KS_DECLARE(ks_ssize_t) kws_raw_write(kws_t *kws, void *data, ks_size_t bytes)
573589
ms = 25;
574590
}
575591
}
592+
576593
ks_sleep_ms(ms);
577594
}
578595

579596
if (r < 0) {
580597
ssl_err = SSL_get_error(kws->ssl, r);
581598

582599
if (!SSL_ERROR_WANT_READ_WRITE(ssl_err)) {
600+
if (SSL_IO_ERROR(ssl_err)) {
601+
kws->ssl_io_error = 1;
602+
}
603+
583604
break;
584605
}
606+
585607
ssl_err = 0;
586608
}
587609

@@ -873,7 +895,7 @@ KS_DECLARE(ks_status_t) kws_init_ex(kws_t **kwsP, ks_socket_t sock, SSL_CTX *ssl
873895
kws->payload_size_max = ks_json_get_object_number_int(params, "payload_size_max", 0);
874896

875897
if ((flags & KWS_BLOCK)) {
876-
kws->block = 1;
898+
kws->block = WS_BLOCK;
877899
}
878900

879901
if (client_data) {
@@ -1037,27 +1059,109 @@ KS_DECLARE(ks_ssize_t) kws_close(kws_t *kws, int16_t reason)
10371059
kws->uri = NULL;
10381060
}
10391061

1040-
if (reason && kws->sock != KS_SOCK_INVALID) {
1062+
if (kws->handshake && kws->sock != KS_SOCK_INVALID) {
10411063
uint16_t *u16;
1042-
uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0};
1064+
int16_t got_reason = reason ? reason : WS_NORMAL_CLOSE /* regular close initiated by us */;
10431065

1044-
u16 = (uint16_t *) &fr[2];
1045-
*u16 = htons((int16_t)reason);
1046-
kws_raw_write(kws, fr, 4);
1066+
if (kws->type == KWS_CLIENT) {
1067+
const uint8_t maskb = 0x80;
1068+
uint8_t size = 0x02, fr[8] = {WSOC_CLOSE | 0x80, size | maskb, 0, 0, 0, 0, 0, 0}, masking_key[4], i;
1069+
uint8_t *p;
1070+
1071+
u16 = (uint16_t *) &fr[6];
1072+
*u16 = htons((int16_t)got_reason);
1073+
p = (uint8_t *)u16; /*use p for masking the reason which is the payload */
1074+
1075+
gen_nonce(masking_key, 4);
1076+
memcpy((uint8_t *)fr + 2, &masking_key, 4);
1077+
1078+
for (i = 0; i < size; i++) {
1079+
*(p + i) = (*((uint8_t *)p + i)) ^ (*(masking_key + (i % 4)));
1080+
}
1081+
1082+
kws_raw_write(kws, fr, 8);
1083+
} else {
1084+
uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0};
1085+
1086+
u16 = (uint16_t *) &fr[2];
1087+
*u16 = htons((int16_t)got_reason);
1088+
kws_raw_write(kws, fr, 4);
1089+
}
10471090
}
10481091

10491092
if (kws->ssl && kws->sock != KS_SOCK_INVALID) {
1050-
/* first invocation of SSL_shutdown() would normally return 0 and just try to send SSL protocol close request.
1093+
/* first invocation of SSL_shutdown() would normally return 0 and just try to send SSL protocol close request (close_notify_alert).
10511094
we just slightly polite, since we want to close socket fast and
10521095
not bother waiting for SSL protocol close response before closing socket,
10531096
since we want cleanup to be done fast for scenarios like:
10541097
client change NAT (like jump from one WiFi to another) and now unreachable from old ip:port, however
10551098
immidiately reconnect with new ip:port but old session id (and thus should replace the old session/channel)
1099+
However it is recommended to do bidirectional shutdown
1100+
and also to read all the remaining data sent by the client
1101+
before it indicates EOF (SSL_ERROR_ZERO_RETURN).
1102+
To avoid stuck in this process in case of dead peers,
1103+
we wait for WS_SOFT_BLOCK time (1s) before we give up.
10561104
*/
1057-
ERR_clear_error();
1058-
SSL_shutdown(kws->ssl);
1105+
int code = 0, rcode = 0;
1106+
int ssl_error = 0;
1107+
int n = 0, block_n = WS_SOFT_BLOCK / 10;
1108+
1109+
/* SSL layer was never established or underlying IO error occured */
1110+
if (!kws->secure_established || kws->ssl_io_error) {
1111+
goto end;
1112+
}
1113+
1114+
/* connection has been already closed */
1115+
if (SSL_get_shutdown(kws->ssl) & SSL_SENT_SHUTDOWN) {
1116+
goto end;
1117+
}
1118+
1119+
/* peer closes the connection */
1120+
if (SSL_get_shutdown(kws->ssl) & SSL_RECEIVED_SHUTDOWN) {
1121+
ERR_clear_error();
1122+
SSL_shutdown(kws->ssl);
1123+
goto end;
1124+
}
1125+
1126+
/* us closes the connection. We do bidirection shutdown handshake */
1127+
for(;;) {
1128+
ERR_clear_error();
1129+
code = SSL_shutdown(kws->ssl);
1130+
ssl_error = SSL_get_error(kws->ssl, code);
1131+
if (code <= 0 && ssl_error == SSL_ERROR_WANT_READ) {
1132+
/* need to make sure there are no more data to read */
1133+
for(;;) {
1134+
ERR_clear_error();
1135+
if ((rcode = SSL_read(kws->ssl, kws->buffer, 9)) <= 0) {
1136+
ssl_error = SSL_get_error(kws->ssl, rcode);
1137+
if (ssl_error == SSL_ERROR_ZERO_RETURN) {
1138+
break;
1139+
} else if (SSL_IO_ERROR(ssl_error)) {
1140+
goto end;
1141+
} else if (ssl_error == SSL_ERROR_WANT_READ) {
1142+
if (++n == block_n) {
1143+
goto end;
1144+
}
1145+
1146+
ks_sleep_ms(10);
1147+
} else {
1148+
goto end;
1149+
}
1150+
}
1151+
}
1152+
} else if (code == 0 || (code < 0 && ssl_error == SSL_ERROR_WANT_WRITE)) {
1153+
if (++n == block_n) {
1154+
goto end;
1155+
}
1156+
1157+
ks_sleep_ms(10);
1158+
} else { /* code != 0 */
1159+
goto end;
1160+
}
1161+
}
10591162
}
10601163

1164+
end:
10611165
/* restore to blocking here, so any further read/writes will block */
10621166
restore_socket(kws->sock);
10631167

win/libks-version.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Import Project="basedir.props" Condition=" '$(BaseDirImported)' == ''"/>
55
</ImportGroup>
66
<PropertyGroup Label="UserMacros">
7-
<libksVersion>2.0.2</libksVersion>
7+
<libksVersion>2.0.3</libksVersion>
88
<libksBuildNumber>0</libksBuildNumber>
99
<libksLibDir>$(BaseDir)../</libksLibDir>
1010
</PropertyGroup>

0 commit comments

Comments
 (0)