8 #define SHA_DIGEST_LENGTH 20
9 #elif defined ZMQ_USE_BUILTIN_SHA1
10 #include "../external/sha1/sha1.h"
11 #elif defined ZMQ_USE_GNUTLS
12 #define SHA_DIGEST_LENGTH 20
13 #include <gnutls/gnutls.h>
14 #include <gnutls/crypto.h>
17 #if !defined ZMQ_HAVE_WINDOWS
18 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #ifdef ZMQ_HAVE_VXWORKS
49 #ifndef IPV6_ADD_MEMBERSHIP
50 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
54 #include <TargetConditionals.h>
58 encode_base64 (
const unsigned char *in_,
int in_len_,
char *out_,
int out_len_);
73 _header_name_position (0),
74 _header_value_position (0),
75 _header_upgrade_websocket (
false),
76 _header_connection_upgrade (
false),
77 _heartbeat_timeout (0)
102 const char *protocol;
104 protocol =
"ZWS2.0/NULL,ZWS2.0";
105 else if (_options.mechanism ==
ZMQ_PLAIN)
106 protocol =
"ZWS2.0/PLAIN";
107 #ifdef ZMQ_HAVE_CURVE
108 else if (_options.mechanism ==
ZMQ_CURVE)
109 protocol =
"ZWS2.0/CURVE";
117 unsigned char nonce[16];
118 int *
p =
reinterpret_cast<int *
> (nonce);
132 "GET %s HTTP/1.1\r\n"
134 "Upgrade: websocket\r\n"
135 "Connection: Upgrade\r\n"
136 "Sec-WebSocket-Key: %s\r\n"
137 "Sec-WebSocket-Protocol: %s\r\n"
138 "Sec-WebSocket-Version: 13\r\n\r\n",
139 _address.path (), _address.host (), _websocket_key, protocol);
141 _outpos = _write_buffer;
149 start_ws_handshake ();
156 const int rc = msg_->
init_size (_options.routing_id_size);
158 if (_options.routing_id_size > 0)
159 memcpy (msg_->
data (), _options.routing_id, _options.routing_id_size);
167 if (_options.recv_routing_id) {
169 const int rc = session ()->push_msg (msg_);
172 int rc = msg_->
close ();
185 if (_options.mechanism ==
ZMQ_NULL && (strcmp (
"ZWS2.0", protocol_) == 0)) {
192 if (_options.heartbeat_interval > 0 && !_has_heartbeat_timer) {
193 add_timer (_options.heartbeat_interval, heartbeat_ivl_timer_id);
194 _has_heartbeat_timer =
true;
200 && strcmp (
"ZWS2.0/NULL", protocol_) == 0) {
201 _mechanism =
new (std::nothrow)
202 null_mechanism_t (session (), _peer_address, _options);
205 }
else if (_options.mechanism ==
ZMQ_PLAIN
206 && strcmp (
"ZWS2.0/PLAIN", protocol_) == 0) {
207 if (_options.as_server)
208 _mechanism =
new (std::nothrow)
209 plain_server_t (session (), _peer_address, _options);
212 new (std::nothrow) plain_client_t (session (), _options);
216 #ifdef ZMQ_HAVE_CURVE
218 && strcmp (
"ZWS2.0/CURVE", protocol_) == 0) {
219 if (_options.as_server)
220 _mechanism =
new (std::nothrow)
221 curve_server_t (session (), _peer_address, _options,
false);
224 new (std::nothrow) curve_client_t (session (), _options,
false);
238 complete = client_handshake ();
240 complete = server_handshake ();
244 new (std::nothrow) ws_encoder_t (_options.out_batch_size, _client);
247 _decoder =
new (std::nothrow)
248 ws_decoder_t (_options.in_batch_size, _options.maxmsgsize,
249 _options.zero_copy, !_client);
252 socket ()->event_handshake_succeeded (_endpoint_uri_pair, 0);
269 _inpos = _read_buffer;
272 while (_insize > 0) {
273 const char c =
static_cast<char> (*_inpos);
275 switch (_server_handshake_state) {
301 if (c ==
'\r' || c ==
'\n')
310 if (c ==
'\r' || c ==
'\n')
387 _header_name_position = 1;
393 if (c ==
'\r' || c ==
'\n')
396 _header_name[_header_name_position] =
'\0';
401 _header_name[_header_name_position] = c;
402 _header_name_position++;
415 _header_value[0] = c;
416 _header_value_position = 1;
423 else if (c ==
'\r') {
424 _header_value[_header_value_position] =
'\0';
426 if (strcasecmp (
"upgrade", _header_name) == 0)
427 _header_upgrade_websocket =
428 strcasecmp (
"websocket", _header_value) == 0;
429 else if (strcasecmp (
"connection", _header_name) == 0) {
431 char *element = strtok_r (_header_value,
",", &rest);
432 while (element !=
NULL) {
433 while (*element ==
' ')
435 if (strcasecmp (
"upgrade", element) == 0) {
436 _header_connection_upgrade =
true;
439 element = strtok_r (
NULL,
",", &rest);
441 }
else if (strcasecmp (
"Sec-WebSocket-Key", _header_name)
443 strcpy_s (_websocket_key, _header_value);
444 else if (strcasecmp (
"Sec-WebSocket-Protocol", _header_name)
449 if (_websocket_protocol[0] ==
'\0') {
451 char *
p = strtok_r (_header_value,
",", &rest);
456 if (select_protocol (
p)) {
461 p = strtok_r (
NULL,
",", &rest);
470 _header_value[_header_value_position] = c;
471 _header_value_position++;
483 if (_header_connection_upgrade && _header_upgrade_websocket
484 && _websocket_protocol[0] !=
'\0'
485 && _websocket_key[0] !=
'\0') {
494 assert (accept_key_len > 0);
495 _websocket_accept[accept_key_len] =
'\0';
498 snprintf (
reinterpret_cast<char *
> (_write_buffer),
500 "HTTP/1.1 101 Switching Protocols\r\n"
501 "Upgrade: websocket\r\n"
502 "Connection: Upgrade\r\n"
503 "Sec-WebSocket-Accept: %s\r\n"
504 "Sec-WebSocket-Protocol: %s\r\n"
506 _websocket_accept, _websocket_protocol);
508 _outpos = _write_buffer;
530 socket ()->event_handshake_failed_protocol (
549 _inpos = _read_buffer;
552 while (_insize > 0) {
553 const char c =
static_cast<char> (*_inpos);
555 switch (_client_handshake_state) {
606 _client_handshake_state =
613 _client_handshake_state =
776 _header_name_position = 1;
782 if (c ==
'\r' || c ==
'\n')
785 _header_name[_header_name_position] =
'\0';
790 _header_name[_header_name_position] = c;
791 _header_name_position++;
802 _client_handshake_state =
805 _header_value[0] = c;
806 _header_value_position = 1;
813 else if (c ==
'\r') {
814 _header_value[_header_value_position] =
'\0';
816 if (strcasecmp (
"upgrade", _header_name) == 0)
817 _header_upgrade_websocket =
818 strcasecmp (
"websocket", _header_value) == 0;
819 else if (strcasecmp (
"connection", _header_name) == 0)
820 _header_connection_upgrade =
821 strcasecmp (
"upgrade", _header_value) == 0;
822 else if (strcasecmp (
"Sec-WebSocket-Accept", _header_name)
824 strcpy_s (_websocket_accept, _header_value);
825 else if (strcasecmp (
"Sec-WebSocket-Protocol", _header_name)
831 if (select_protocol (_header_value))
832 strcpy_s (_websocket_protocol, _header_value);
838 _header_value[_header_value_position] = c;
839 _header_value_position++;
851 if (_header_connection_upgrade && _header_upgrade_websocket
852 && _websocket_protocol[0] !=
'\0'
853 && _websocket_accept[0] !=
'\0') {
875 socket ()->event_handshake_failed_protocol (
892 if (process_command_message (msg_) == -1)
894 }
else if (_mechanism->decode (msg_) == -1)
897 if (_has_timeout_timer) {
898 _has_timeout_timer =
false;
899 cancel_timer (heartbeat_timeout_timer_id);
904 process_command_message (msg_);
908 if (session ()->push_msg (msg_) == -1) {
918 int rc = msg_->
move (_close_msg);
940 error (connection_error);
947 int rc = msg_->
init ();
952 if (!_has_timeout_timer && _heartbeat_timeout > 0) {
953 add_timer (_heartbeat_timeout, heartbeat_timeout_timer_id);
954 _has_timeout_timer =
true;
963 int rc = msg_->
init ();
979 int rc = _close_msg.copy (*msg_);
990 encode_base64 (
const unsigned char *in_,
int in_len_,
char *out_,
int out_len_)
992 static const unsigned char base64enc_tab[65] =
993 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
999 for (
int ii = 0; ii < in_len_; ii++) {
1008 out_[io++] = base64enc_tab[(
v >> rem) & 63];
1015 out_[io++] = base64enc_tab[
v & 63];
1030 const char *magic_string =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
1033 HASH_HashType
type = HASH_GetHashTypeByOidTag (SEC_OID_SHA1);
1034 HASHContext *ctx = HASH_Create (
type);
1038 HASH_Update (ctx, (
unsigned char *) key_, (
unsigned int) strlen (key_));
1039 HASH_Update (ctx, (
unsigned char *) magic_string,
1040 (
unsigned int) strlen (magic_string));
1043 #elif defined ZMQ_USE_BUILTIN_SHA1
1046 SHA1_Update (&ctx, (
unsigned char *) key_, strlen (key_));
1047 SHA1_Update (&ctx, (
unsigned char *) magic_string, strlen (magic_string));
1050 #elif defined ZMQ_USE_GNUTLS
1051 gnutls_hash_hd_t hd;
1052 gnutls_hash_init (&hd, GNUTLS_DIG_SHA1);
1053 gnutls_hash (hd, key_, strlen (key_));
1054 gnutls_hash (hd, magic_string, strlen (magic_string));
1055 gnutls_hash_deinit (hd, hash_);
1057 #error "No sha1 implementation set"