mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-29 08:39:42 +08:00
Merge pull request #3670 from somdoron/ws_host_path
problem: ws_engine doesn't send correct host and path
This commit is contained in:
commit
df1bec03c0
@ -785,6 +785,7 @@ set(cxx-sources
|
||||
gather.cpp
|
||||
ip_resolver.cpp
|
||||
zap_client.cpp
|
||||
ws_address.cpp
|
||||
ws_connecter.cpp
|
||||
ws_decoder.cpp
|
||||
ws_encoder.cpp
|
||||
@ -923,6 +924,7 @@ set(cxx-sources
|
||||
vmci_listener.hpp
|
||||
windows.hpp
|
||||
wire.hpp
|
||||
ws_address.hpp
|
||||
ws_connecter.hpp
|
||||
ws_decoder.hpp
|
||||
ws_encoder.hpp
|
||||
|
@ -250,6 +250,8 @@ src_libzmq_la_SOURCES = \
|
||||
src/vmci_listener.hpp \
|
||||
src/windows.hpp \
|
||||
src/wire.hpp \
|
||||
src/ws_address.cpp \
|
||||
src/ws_address.hpp \
|
||||
src/ws_connecter.cpp \
|
||||
src/ws_connecter.hpp \
|
||||
src/ws_decoder.cpp \
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "udp_address.hpp"
|
||||
#include "ipc_address.hpp"
|
||||
#include "tipc_address.hpp"
|
||||
#include "ws_address.hpp"
|
||||
|
||||
#if defined ZMQ_HAVE_VMCI
|
||||
#include "vmci_address.hpp"
|
||||
@ -56,10 +57,12 @@ zmq::address_t::address_t (const std::string &protocol_,
|
||||
|
||||
zmq::address_t::~address_t ()
|
||||
{
|
||||
if (protocol == protocol_name::tcp || protocol == protocol_name::ws) {
|
||||
if (protocol == protocol_name::tcp) {
|
||||
LIBZMQ_DELETE (resolved.tcp_addr);
|
||||
} else if (protocol == protocol_name::udp) {
|
||||
LIBZMQ_DELETE (resolved.udp_addr);
|
||||
} else if (protocol == protocol_name::ws) {
|
||||
LIBZMQ_DELETE (resolved.ws_addr);
|
||||
}
|
||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||
&& !defined ZMQ_HAVE_VXWORKS
|
||||
@ -85,6 +88,8 @@ int zmq::address_t::to_string (std::string &addr_) const
|
||||
return resolved.tcp_addr->to_string (addr_);
|
||||
if (protocol == protocol_name::udp && resolved.udp_addr)
|
||||
return resolved.udp_addr->to_string (addr_);
|
||||
if (protocol == protocol_name::ws && resolved.ws_addr)
|
||||
return resolved.ws_addr->to_string (addr_);
|
||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||
&& !defined ZMQ_HAVE_VXWORKS
|
||||
if (protocol == protocol_name::ipc && resolved.ipc_addr)
|
||||
|
@ -45,6 +45,7 @@ namespace zmq
|
||||
class ctx_t;
|
||||
class tcp_address_t;
|
||||
class udp_address_t;
|
||||
class ws_address_t;
|
||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
|
||||
class ipc_address_t;
|
||||
#endif
|
||||
@ -92,6 +93,7 @@ struct address_t
|
||||
void *dummy;
|
||||
tcp_address_t *tcp_addr;
|
||||
udp_address_t *udp_addr;
|
||||
ws_address_t *ws_addr;
|
||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||
&& !defined ZMQ_HAVE_VXWORKS
|
||||
ipc_address_t *ipc_addr;
|
||||
|
@ -97,7 +97,8 @@ zmq::ip_resolver_options_t::ip_resolver_options_t () :
|
||||
_nic_name_allowed (false),
|
||||
_ipv6_wanted (false),
|
||||
_port_expected (false),
|
||||
_dns_allowed (false)
|
||||
_dns_allowed (false),
|
||||
_path_allowed (false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -141,6 +142,13 @@ zmq::ip_resolver_options_t &zmq::ip_resolver_options_t::allow_dns (bool allow_)
|
||||
return *this;
|
||||
}
|
||||
|
||||
zmq::ip_resolver_options_t &zmq::ip_resolver_options_t::allow_path (bool allow_)
|
||||
{
|
||||
_path_allowed = allow_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool zmq::ip_resolver_options_t::bindable ()
|
||||
{
|
||||
return _bindable_wanted;
|
||||
@ -166,6 +174,11 @@ bool zmq::ip_resolver_options_t::allow_dns ()
|
||||
return _dns_allowed;
|
||||
}
|
||||
|
||||
bool zmq::ip_resolver_options_t::allow_path ()
|
||||
{
|
||||
return _path_allowed;
|
||||
}
|
||||
|
||||
zmq::ip_resolver_t::ip_resolver_t (ip_resolver_options_t opts_) :
|
||||
_options (opts_)
|
||||
{
|
||||
@ -214,6 +227,13 @@ int zmq::ip_resolver_t::resolve (ip_addr_t *ip_addr_, const char *name_)
|
||||
port = 0;
|
||||
}
|
||||
|
||||
// Check if path is allowed in ip address, if allowed it must be truncated
|
||||
if (_options.allow_path ()) {
|
||||
size_t pos = addr.find ('/');
|
||||
if (pos != std::string::npos)
|
||||
addr = addr.substr (0, pos);
|
||||
}
|
||||
|
||||
// Trim any square brackets surrounding the address. Used for
|
||||
// IPv6 addresses to remove the confusion with the port
|
||||
// delimiter.
|
||||
|
@ -68,12 +68,14 @@ class ip_resolver_options_t
|
||||
ip_resolver_options_t &ipv6 (bool ipv6_);
|
||||
ip_resolver_options_t &expect_port (bool expect_);
|
||||
ip_resolver_options_t &allow_dns (bool allow_);
|
||||
ip_resolver_options_t &allow_path (bool allow_);
|
||||
|
||||
bool bindable ();
|
||||
bool allow_nic_name ();
|
||||
bool ipv6 ();
|
||||
bool expect_port ();
|
||||
bool allow_dns ();
|
||||
bool allow_path ();
|
||||
|
||||
private:
|
||||
bool _bindable_wanted;
|
||||
@ -81,6 +83,7 @@ class ip_resolver_options_t
|
||||
bool _ipv6_wanted;
|
||||
bool _port_expected;
|
||||
bool _dns_allowed;
|
||||
bool _path_allowed;
|
||||
};
|
||||
|
||||
class ip_resolver_t
|
||||
|
@ -65,6 +65,7 @@
|
||||
#include "address.hpp"
|
||||
#include "ipc_address.hpp"
|
||||
#include "tcp_address.hpp"
|
||||
#include "ws_address.hpp"
|
||||
#include "udp_address.hpp"
|
||||
#include "tipc_address.hpp"
|
||||
#include "mailbox.hpp"
|
||||
@ -889,46 +890,14 @@ int zmq::socket_base_t::connect (const char *endpoint_uri_)
|
||||
// Defer resolution until a socket is opened
|
||||
paddr->resolved.tcp_addr = NULL;
|
||||
} else if (protocol == protocol_name::ws) {
|
||||
// Do some basic sanity checks on ws:// address syntax
|
||||
// - hostname starts with digit or letter, with embedded '-' or '.'
|
||||
// - IPv6 address may contain hex chars and colons.
|
||||
// - IPv6 link local address may contain % followed by interface name / zone_id
|
||||
// (Reference: https://tools.ietf.org/html/rfc4007)
|
||||
// - IPv4 address may contain decimal digits and dots.
|
||||
// - Address must end in ":port" where port is *, or numeric
|
||||
// - Address may contain two parts separated by ':'
|
||||
// Following code is quick and dirty check to catch obvious errors,
|
||||
// without trying to be fully accurate.
|
||||
const char *check = address.c_str ();
|
||||
if (isalnum (*check) || isxdigit (*check) || *check == '['
|
||||
|| *check == ':') {
|
||||
check++;
|
||||
while (isalnum (*check) || isxdigit (*check) || *check == '.'
|
||||
|| *check == '-' || *check == ':' || *check == '%'
|
||||
|| *check == ';' || *check == '[' || *check == ']'
|
||||
|| *check == '_' || *check == '*') {
|
||||
check++;
|
||||
}
|
||||
}
|
||||
// Assume the worst, now look for success
|
||||
rc = -1;
|
||||
// Did we reach the end of the address safely?
|
||||
if (*check == 0) {
|
||||
// Do we have a valid port string? (cannot be '*' in connect
|
||||
check = strrchr (address.c_str (), ':');
|
||||
if (check) {
|
||||
check++;
|
||||
if (*check && (isdigit (*check)))
|
||||
rc = 0; // Valid
|
||||
}
|
||||
}
|
||||
if (rc == -1) {
|
||||
errno = EINVAL;
|
||||
paddr->resolved.ws_addr = new (std::nothrow) ws_address_t ();
|
||||
alloc_assert (paddr->resolved.ws_addr);
|
||||
rc = paddr->resolved.ws_addr->resolve (address.c_str (), false,
|
||||
options.ipv6);
|
||||
if (rc != 0) {
|
||||
LIBZMQ_DELETE (paddr);
|
||||
return -1;
|
||||
}
|
||||
// Defer resolution until a socket is opened
|
||||
paddr->resolved.tcp_addr = NULL;
|
||||
}
|
||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||
&& !defined ZMQ_HAVE_VXWORKS
|
||||
|
159
src/ws_address.cpp
Normal file
159
src/ws_address.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.hpp"
|
||||
#include "ws_address.hpp"
|
||||
#include "stdint.hpp"
|
||||
#include "err.hpp"
|
||||
#include "ip.hpp"
|
||||
|
||||
#ifndef ZMQ_HAVE_WINDOWS
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
zmq::ws_address_t::ws_address_t ()
|
||||
{
|
||||
memset (&_address, 0, sizeof (_address));
|
||||
}
|
||||
|
||||
zmq::ws_address_t::ws_address_t (const sockaddr *sa_, socklen_t sa_len_)
|
||||
{
|
||||
zmq_assert (sa_ && sa_len_ > 0);
|
||||
|
||||
memset (&_address, 0, sizeof (_address));
|
||||
if (sa_->sa_family == AF_INET
|
||||
&& sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv4)))
|
||||
memcpy (&_address.ipv4, sa_, sizeof (_address.ipv4));
|
||||
else if (sa_->sa_family == AF_INET6
|
||||
&& sa_len_ >= static_cast<socklen_t> (sizeof (_address.ipv6)))
|
||||
memcpy (&_address.ipv6, sa_, sizeof (_address.ipv6));
|
||||
|
||||
_path = std::string ("/");
|
||||
|
||||
char hbuf[NI_MAXHOST];
|
||||
const int rc = getnameinfo (addr (), addrlen (), hbuf, sizeof (hbuf), NULL,
|
||||
0, NI_NUMERICHOST);
|
||||
if (rc != 0)
|
||||
_host = std::string ("localhost");
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
if (_address.family () == AF_INET6)
|
||||
os << std::string ("[");
|
||||
|
||||
os << std::string (hbuf);
|
||||
|
||||
if (_address.family () == AF_INET6)
|
||||
os << std::string ("]");
|
||||
|
||||
_host = os.str ();
|
||||
}
|
||||
|
||||
int zmq::ws_address_t::resolve (const char *name_, bool local_, bool ipv6_)
|
||||
{
|
||||
// find the host part, It's important to use str*r*chr to only get
|
||||
// the latest colon since IPv6 addresses use colons as delemiters.
|
||||
const char *delim = strrchr (name_, ':');
|
||||
if (delim == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
_host = std::string (name_, delim - name_);
|
||||
|
||||
// find the path part, which is optional
|
||||
delim = strrchr (name_, '/');
|
||||
if (delim)
|
||||
_path = std::string (delim);
|
||||
else
|
||||
_path = std::string ("/");
|
||||
|
||||
ip_resolver_options_t resolver_opts;
|
||||
resolver_opts.bindable (local_)
|
||||
.allow_dns (!local_)
|
||||
.allow_nic_name (local_)
|
||||
.ipv6 (ipv6_)
|
||||
.allow_path (true)
|
||||
.expect_port (true);
|
||||
|
||||
ip_resolver_t resolver (resolver_opts);
|
||||
|
||||
return resolver.resolve (&_address, name_);
|
||||
}
|
||||
|
||||
int zmq::ws_address_t::to_string (std::string &addr_) const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << std::string ("ws://") << host () << std::string (":")
|
||||
<< _address.port ();
|
||||
addr_ = os.str ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const sockaddr *zmq::ws_address_t::addr () const
|
||||
{
|
||||
return _address.as_sockaddr ();
|
||||
}
|
||||
|
||||
socklen_t zmq::ws_address_t::addrlen () const
|
||||
{
|
||||
return _address.sockaddr_len ();
|
||||
}
|
||||
|
||||
const char *zmq::ws_address_t::host () const
|
||||
{
|
||||
return _host.c_str ();
|
||||
}
|
||||
|
||||
const char *zmq::ws_address_t::path () const
|
||||
{
|
||||
return _path.c_str ();
|
||||
}
|
||||
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
unsigned short zmq::ws_address_t::family () const
|
||||
#else
|
||||
sa_family_t zmq::ws_address_t::family () const
|
||||
#endif
|
||||
{
|
||||
return _address.family ();
|
||||
}
|
75
src/ws_address.hpp
Normal file
75
src/ws_address.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ZMQ_WS_ADDRESS_HPP_INCLUDED__
|
||||
#define __ZMQ_WS_ADDRESS_HPP_INCLUDED__
|
||||
|
||||
#if !defined ZMQ_HAVE_WINDOWS
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "ip_resolver.hpp"
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
class ws_address_t
|
||||
{
|
||||
public:
|
||||
ws_address_t ();
|
||||
ws_address_t (const sockaddr *sa_, socklen_t sa_len_);
|
||||
|
||||
// This function translates textual WS address into an address
|
||||
// structure. If 'local' is true, names are resolved as local interface
|
||||
// names. If it is false, names are resolved as remote hostnames.
|
||||
// If 'ipv6' is true, the name may resolve to IPv6 address.
|
||||
int resolve (const char *name_, bool local_, bool ipv6_);
|
||||
|
||||
// The opposite to resolve()
|
||||
int to_string (std::string &addr_) const;
|
||||
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
unsigned short family () const;
|
||||
#else
|
||||
sa_family_t family () const;
|
||||
#endif
|
||||
const sockaddr *addr () const;
|
||||
socklen_t addrlen () const;
|
||||
|
||||
const char *host () const;
|
||||
const char *path () const;
|
||||
|
||||
private:
|
||||
ip_addr_t _address;
|
||||
std::string _host;
|
||||
std::string _path;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -38,7 +38,7 @@
|
||||
#include "ip.hpp"
|
||||
#include "tcp.hpp"
|
||||
#include "address.hpp"
|
||||
#include "tcp_address.hpp"
|
||||
#include "ws_address.hpp"
|
||||
#include "session_base.hpp"
|
||||
#include "ws_engine.hpp"
|
||||
|
||||
@ -111,7 +111,7 @@ void zmq::ws_connecter_t::out_event ()
|
||||
return;
|
||||
}
|
||||
|
||||
create_engine (fd, get_socket_name<tcp_address_t> (fd, socket_end_local));
|
||||
create_engine (fd, get_socket_name<ws_address_t> (fd, socket_end_local));
|
||||
}
|
||||
|
||||
void zmq::ws_connecter_t::timer_event (int id_)
|
||||
@ -167,63 +167,20 @@ int zmq::ws_connecter_t::open ()
|
||||
{
|
||||
zmq_assert (_s == retired_fd);
|
||||
|
||||
// Resolve the address
|
||||
if (_addr->resolved.tcp_addr != NULL) {
|
||||
LIBZMQ_DELETE (_addr->resolved.tcp_addr);
|
||||
}
|
||||
|
||||
_addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t ();
|
||||
alloc_assert (_addr->resolved.tcp_addr);
|
||||
tcp_address_t tcp_addr;
|
||||
_s = tcp_open_socket (_addr->address.c_str (), options, false, true,
|
||||
_addr->resolved.tcp_addr);
|
||||
if (_s == retired_fd) {
|
||||
// TODO we should emit some event in this case!
|
||||
|
||||
LIBZMQ_DELETE (_addr->resolved.tcp_addr);
|
||||
&tcp_addr);
|
||||
if (_s == retired_fd)
|
||||
return -1;
|
||||
}
|
||||
zmq_assert (_addr->resolved.tcp_addr != NULL);
|
||||
|
||||
// Set the socket to non-blocking mode so that we get async connect().
|
||||
unblock_socket (_s);
|
||||
|
||||
const tcp_address_t *const tcp_addr = _addr->resolved.tcp_addr;
|
||||
|
||||
int rc;
|
||||
|
||||
// Set a source address for conversations
|
||||
if (tcp_addr->has_src_addr ()) {
|
||||
// Allow reusing of the address, to connect to different servers
|
||||
// using the same source port on the client.
|
||||
int flag = 1;
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR,
|
||||
reinterpret_cast<const char *> (&flag), sizeof (int));
|
||||
wsa_assert (rc != SOCKET_ERROR);
|
||||
#elif defined ZMQ_HAVE_VXWORKS
|
||||
rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, (char *) &flag,
|
||||
sizeof (int));
|
||||
errno_assert (rc == 0);
|
||||
#else
|
||||
rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int));
|
||||
errno_assert (rc == 0);
|
||||
#endif
|
||||
|
||||
#if defined ZMQ_HAVE_VXWORKS
|
||||
rc = ::bind (_s, (sockaddr *) tcp_addr->src_addr (),
|
||||
tcp_addr->src_addrlen ());
|
||||
#else
|
||||
rc = ::bind (_s, tcp_addr->src_addr (), tcp_addr->src_addrlen ());
|
||||
#endif
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Connect to the remote peer.
|
||||
#if defined ZMQ_HAVE_VXWORKS
|
||||
rc = ::connect (_s, (sockaddr *) tcp_addr->addr (), tcp_addr->addrlen ());
|
||||
int rc = ::connect (_s, (sockaddr *) tcp_addr.addr (), tcp_addr.addrlen ());
|
||||
#else
|
||||
rc = ::connect (_s, tcp_addr->addr (), tcp_addr->addrlen ());
|
||||
int rc = ::connect (_s, tcp_addr.addr (), tcp_addr.addrlen ());
|
||||
#endif
|
||||
// Connect was successful immediately.
|
||||
if (rc == 0) {
|
||||
@ -307,8 +264,8 @@ void zmq::ws_connecter_t::create_engine (fd_t fd,
|
||||
endpoint_type_connect);
|
||||
|
||||
// Create the engine object for this connection.
|
||||
ws_engine_t *engine =
|
||||
new (std::nothrow) ws_engine_t (fd, options, endpoint_pair, true);
|
||||
ws_engine_t *engine = new (std::nothrow)
|
||||
ws_engine_t (fd, options, endpoint_pair, *_addr->resolved.ws_addr, true);
|
||||
alloc_assert (engine);
|
||||
|
||||
// Attach the engine to the corresponding session object.
|
||||
|
@ -69,9 +69,11 @@ encode_base64 (const unsigned char *in, int in_len, char *out, int out_len);
|
||||
zmq::ws_engine_t::ws_engine_t (fd_t fd_,
|
||||
const options_t &options_,
|
||||
const endpoint_uri_pair_t &endpoint_uri_pair_,
|
||||
ws_address_t &address_,
|
||||
bool client_) :
|
||||
stream_engine_base_t (fd_, options_, endpoint_uri_pair_),
|
||||
_client (client_),
|
||||
_address (address_),
|
||||
_client_handshake_state (client_handshake_initial),
|
||||
_server_handshake_state (handshake_initial),
|
||||
_header_name_position (0),
|
||||
@ -109,16 +111,15 @@ void zmq::ws_engine_t::plug_internal ()
|
||||
encode_base64 (nonce, 16, _websocket_key, MAX_HEADER_VALUE_LENGTH);
|
||||
assert (size > 0);
|
||||
|
||||
size = snprintf (
|
||||
(char *) _write_buffer, WS_BUFFER_SIZE,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: server.example.com\r\n" // TODO: we need the address here
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: %s\r\n"
|
||||
"Sec-WebSocket-Protocol: ZWS2.0\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||
_websocket_key);
|
||||
size = snprintf ((char *) _write_buffer, WS_BUFFER_SIZE,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: %s\r\n"
|
||||
"Sec-WebSocket-Protocol: ZWS2.0\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||
_address.path (), _address.host (), _websocket_key);
|
||||
assert (size > 0 && size < WS_BUFFER_SIZE);
|
||||
_outpos = _write_buffer;
|
||||
_outsize = size;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "address.hpp"
|
||||
#include "msg.hpp"
|
||||
#include "stream_engine_base.hpp"
|
||||
#include "ws_address.hpp"
|
||||
|
||||
|
||||
#define WS_BUFFER_SIZE 8192
|
||||
@ -130,6 +131,7 @@ class ws_engine_t : public stream_engine_base_t
|
||||
ws_engine_t (fd_t fd_,
|
||||
const options_t &options_,
|
||||
const endpoint_uri_pair_t &endpoint_uri_pair_,
|
||||
ws_address_t &address_,
|
||||
bool client_);
|
||||
~ws_engine_t ();
|
||||
|
||||
@ -145,6 +147,7 @@ class ws_engine_t : public stream_engine_base_t
|
||||
bool server_handshake ();
|
||||
|
||||
bool _client;
|
||||
ws_address_t _address;
|
||||
|
||||
ws_client_handshake_state_t _client_handshake_state;
|
||||
ws_server_handshake_state_t _server_handshake_state;
|
||||
|
@ -100,7 +100,8 @@ std::string zmq::ws_listener_t::get_socket_name (zmq::fd_t fd_,
|
||||
|
||||
int zmq::ws_listener_t::create_socket (const char *addr_)
|
||||
{
|
||||
_s = tcp_open_socket (addr_, options, true, true, &_address);
|
||||
tcp_address_t address;
|
||||
_s = tcp_open_socket (addr_, options, true, true, &address);
|
||||
if (_s == retired_fd) {
|
||||
return -1;
|
||||
}
|
||||
@ -133,7 +134,7 @@ int zmq::ws_listener_t::create_socket (const char *addr_)
|
||||
#if defined ZMQ_HAVE_VXWORKS
|
||||
rc = bind (_s, (sockaddr *) _address.addr (), _address.addrlen ());
|
||||
#else
|
||||
rc = bind (_s, _address.addr (), _address.addrlen ());
|
||||
rc = bind (_s, address.addr (), address.addrlen ());
|
||||
#endif
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
if (rc == SOCKET_ERROR) {
|
||||
@ -173,6 +174,10 @@ int zmq::ws_listener_t::set_local_address (const char *addr_)
|
||||
// socket was already created by the application
|
||||
_s = options.use_fd;
|
||||
} else {
|
||||
int rc = _address.resolve (addr_, true, options.ipv6);
|
||||
if (rc != 0)
|
||||
return -1;
|
||||
|
||||
if (create_socket (addr_) == -1)
|
||||
return -1;
|
||||
}
|
||||
@ -251,8 +256,8 @@ void zmq::ws_listener_t::create_engine (fd_t fd)
|
||||
get_socket_name (fd, socket_end_local),
|
||||
get_socket_name (fd, socket_end_remote), endpoint_type_bind);
|
||||
|
||||
ws_engine_t *engine =
|
||||
new (std::nothrow) ws_engine_t (fd, options, endpoint_pair, false);
|
||||
ws_engine_t *engine = new (std::nothrow)
|
||||
ws_engine_t (fd, options, endpoint_pair, _address, false);
|
||||
alloc_assert (engine);
|
||||
|
||||
// Choose I/O thread to run connecter in. Given that we are already
|
||||
|
@ -31,7 +31,7 @@
|
||||
#define __ZMQ_WS_LISTENER_HPP_INCLUDED__
|
||||
|
||||
#include "fd.hpp"
|
||||
#include "tcp_address.hpp"
|
||||
#include "ws_address.hpp"
|
||||
#include "stream_listener_base.hpp"
|
||||
|
||||
namespace zmq
|
||||
@ -63,7 +63,7 @@ class ws_listener_t : public stream_listener_base_t
|
||||
int create_socket (const char *addr_);
|
||||
|
||||
// Address to listen on.
|
||||
tcp_address_t _address;
|
||||
ws_address_t _address;
|
||||
|
||||
ws_listener_t (const ws_listener_t &);
|
||||
const ws_listener_t &operator= (const ws_listener_t &);
|
||||
|
@ -35,10 +35,11 @@ SETUP_TEARDOWN_TESTCONTEXT
|
||||
void test_roundtrip ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "ws://*:5556"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "ws://*:5556/roundtrip"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "ws://127.0.0.1:5556"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (sc, "ws://127.0.0.1:5556/roundtrip"));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
@ -49,10 +50,10 @@ void test_roundtrip ()
|
||||
void test_short_message ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "ws://*:5557"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "ws://*:5557/short"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "ws://127.0.0.1:5557"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "ws://127.0.0.1:5557/short"));
|
||||
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 255));
|
||||
@ -78,10 +79,10 @@ void test_short_message ()
|
||||
void test_large_message ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "ws://*:5557"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "ws://*:5557/large"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "ws://127.0.0.1:5557"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "ws://127.0.0.1:5557/large"));
|
||||
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 65536));
|
||||
|
Loading…
x
Reference in New Issue
Block a user