mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-31 01:43:02 +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
|
gather.cpp
|
||||||
ip_resolver.cpp
|
ip_resolver.cpp
|
||||||
zap_client.cpp
|
zap_client.cpp
|
||||||
|
ws_address.cpp
|
||||||
ws_connecter.cpp
|
ws_connecter.cpp
|
||||||
ws_decoder.cpp
|
ws_decoder.cpp
|
||||||
ws_encoder.cpp
|
ws_encoder.cpp
|
||||||
@ -923,6 +924,7 @@ set(cxx-sources
|
|||||||
vmci_listener.hpp
|
vmci_listener.hpp
|
||||||
windows.hpp
|
windows.hpp
|
||||||
wire.hpp
|
wire.hpp
|
||||||
|
ws_address.hpp
|
||||||
ws_connecter.hpp
|
ws_connecter.hpp
|
||||||
ws_decoder.hpp
|
ws_decoder.hpp
|
||||||
ws_encoder.hpp
|
ws_encoder.hpp
|
||||||
|
@ -250,6 +250,8 @@ src_libzmq_la_SOURCES = \
|
|||||||
src/vmci_listener.hpp \
|
src/vmci_listener.hpp \
|
||||||
src/windows.hpp \
|
src/windows.hpp \
|
||||||
src/wire.hpp \
|
src/wire.hpp \
|
||||||
|
src/ws_address.cpp \
|
||||||
|
src/ws_address.hpp \
|
||||||
src/ws_connecter.cpp \
|
src/ws_connecter.cpp \
|
||||||
src/ws_connecter.hpp \
|
src/ws_connecter.hpp \
|
||||||
src/ws_decoder.cpp \
|
src/ws_decoder.cpp \
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "udp_address.hpp"
|
#include "udp_address.hpp"
|
||||||
#include "ipc_address.hpp"
|
#include "ipc_address.hpp"
|
||||||
#include "tipc_address.hpp"
|
#include "tipc_address.hpp"
|
||||||
|
#include "ws_address.hpp"
|
||||||
|
|
||||||
#if defined ZMQ_HAVE_VMCI
|
#if defined ZMQ_HAVE_VMCI
|
||||||
#include "vmci_address.hpp"
|
#include "vmci_address.hpp"
|
||||||
@ -56,10 +57,12 @@ zmq::address_t::address_t (const std::string &protocol_,
|
|||||||
|
|
||||||
zmq::address_t::~address_t ()
|
zmq::address_t::~address_t ()
|
||||||
{
|
{
|
||||||
if (protocol == protocol_name::tcp || protocol == protocol_name::ws) {
|
if (protocol == protocol_name::tcp) {
|
||||||
LIBZMQ_DELETE (resolved.tcp_addr);
|
LIBZMQ_DELETE (resolved.tcp_addr);
|
||||||
} else if (protocol == protocol_name::udp) {
|
} else if (protocol == protocol_name::udp) {
|
||||||
LIBZMQ_DELETE (resolved.udp_addr);
|
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 \
|
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||||
&& !defined ZMQ_HAVE_VXWORKS
|
&& !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_);
|
return resolved.tcp_addr->to_string (addr_);
|
||||||
if (protocol == protocol_name::udp && resolved.udp_addr)
|
if (protocol == protocol_name::udp && resolved.udp_addr)
|
||||||
return resolved.udp_addr->to_string (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 \
|
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||||
&& !defined ZMQ_HAVE_VXWORKS
|
&& !defined ZMQ_HAVE_VXWORKS
|
||||||
if (protocol == protocol_name::ipc && resolved.ipc_addr)
|
if (protocol == protocol_name::ipc && resolved.ipc_addr)
|
||||||
|
@ -45,6 +45,7 @@ namespace zmq
|
|||||||
class ctx_t;
|
class ctx_t;
|
||||||
class tcp_address_t;
|
class tcp_address_t;
|
||||||
class udp_address_t;
|
class udp_address_t;
|
||||||
|
class ws_address_t;
|
||||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
|
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
|
||||||
class ipc_address_t;
|
class ipc_address_t;
|
||||||
#endif
|
#endif
|
||||||
@ -92,6 +93,7 @@ struct address_t
|
|||||||
void *dummy;
|
void *dummy;
|
||||||
tcp_address_t *tcp_addr;
|
tcp_address_t *tcp_addr;
|
||||||
udp_address_t *udp_addr;
|
udp_address_t *udp_addr;
|
||||||
|
ws_address_t *ws_addr;
|
||||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||||
&& !defined ZMQ_HAVE_VXWORKS
|
&& !defined ZMQ_HAVE_VXWORKS
|
||||||
ipc_address_t *ipc_addr;
|
ipc_address_t *ipc_addr;
|
||||||
|
@ -97,7 +97,8 @@ zmq::ip_resolver_options_t::ip_resolver_options_t () :
|
|||||||
_nic_name_allowed (false),
|
_nic_name_allowed (false),
|
||||||
_ipv6_wanted (false),
|
_ipv6_wanted (false),
|
||||||
_port_expected (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;
|
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 ()
|
bool zmq::ip_resolver_options_t::bindable ()
|
||||||
{
|
{
|
||||||
return _bindable_wanted;
|
return _bindable_wanted;
|
||||||
@ -166,6 +174,11 @@ bool zmq::ip_resolver_options_t::allow_dns ()
|
|||||||
return _dns_allowed;
|
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_) :
|
zmq::ip_resolver_t::ip_resolver_t (ip_resolver_options_t opts_) :
|
||||||
_options (opts_)
|
_options (opts_)
|
||||||
{
|
{
|
||||||
@ -214,6 +227,13 @@ int zmq::ip_resolver_t::resolve (ip_addr_t *ip_addr_, const char *name_)
|
|||||||
port = 0;
|
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
|
// Trim any square brackets surrounding the address. Used for
|
||||||
// IPv6 addresses to remove the confusion with the port
|
// IPv6 addresses to remove the confusion with the port
|
||||||
// delimiter.
|
// delimiter.
|
||||||
|
@ -68,12 +68,14 @@ class ip_resolver_options_t
|
|||||||
ip_resolver_options_t &ipv6 (bool ipv6_);
|
ip_resolver_options_t &ipv6 (bool ipv6_);
|
||||||
ip_resolver_options_t &expect_port (bool expect_);
|
ip_resolver_options_t &expect_port (bool expect_);
|
||||||
ip_resolver_options_t &allow_dns (bool allow_);
|
ip_resolver_options_t &allow_dns (bool allow_);
|
||||||
|
ip_resolver_options_t &allow_path (bool allow_);
|
||||||
|
|
||||||
bool bindable ();
|
bool bindable ();
|
||||||
bool allow_nic_name ();
|
bool allow_nic_name ();
|
||||||
bool ipv6 ();
|
bool ipv6 ();
|
||||||
bool expect_port ();
|
bool expect_port ();
|
||||||
bool allow_dns ();
|
bool allow_dns ();
|
||||||
|
bool allow_path ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _bindable_wanted;
|
bool _bindable_wanted;
|
||||||
@ -81,6 +83,7 @@ class ip_resolver_options_t
|
|||||||
bool _ipv6_wanted;
|
bool _ipv6_wanted;
|
||||||
bool _port_expected;
|
bool _port_expected;
|
||||||
bool _dns_allowed;
|
bool _dns_allowed;
|
||||||
|
bool _path_allowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ip_resolver_t
|
class ip_resolver_t
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
#include "address.hpp"
|
#include "address.hpp"
|
||||||
#include "ipc_address.hpp"
|
#include "ipc_address.hpp"
|
||||||
#include "tcp_address.hpp"
|
#include "tcp_address.hpp"
|
||||||
|
#include "ws_address.hpp"
|
||||||
#include "udp_address.hpp"
|
#include "udp_address.hpp"
|
||||||
#include "tipc_address.hpp"
|
#include "tipc_address.hpp"
|
||||||
#include "mailbox.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
|
// Defer resolution until a socket is opened
|
||||||
paddr->resolved.tcp_addr = NULL;
|
paddr->resolved.tcp_addr = NULL;
|
||||||
} else if (protocol == protocol_name::ws) {
|
} else if (protocol == protocol_name::ws) {
|
||||||
// Do some basic sanity checks on ws:// address syntax
|
paddr->resolved.ws_addr = new (std::nothrow) ws_address_t ();
|
||||||
// - hostname starts with digit or letter, with embedded '-' or '.'
|
alloc_assert (paddr->resolved.ws_addr);
|
||||||
// - IPv6 address may contain hex chars and colons.
|
rc = paddr->resolved.ws_addr->resolve (address.c_str (), false,
|
||||||
// - IPv6 link local address may contain % followed by interface name / zone_id
|
options.ipv6);
|
||||||
// (Reference: https://tools.ietf.org/html/rfc4007)
|
if (rc != 0) {
|
||||||
// - 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;
|
|
||||||
LIBZMQ_DELETE (paddr);
|
LIBZMQ_DELETE (paddr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Defer resolution until a socket is opened
|
|
||||||
paddr->resolved.tcp_addr = NULL;
|
|
||||||
}
|
}
|
||||||
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS \
|
||||||
&& !defined ZMQ_HAVE_VXWORKS
|
&& !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 "ip.hpp"
|
||||||
#include "tcp.hpp"
|
#include "tcp.hpp"
|
||||||
#include "address.hpp"
|
#include "address.hpp"
|
||||||
#include "tcp_address.hpp"
|
#include "ws_address.hpp"
|
||||||
#include "session_base.hpp"
|
#include "session_base.hpp"
|
||||||
#include "ws_engine.hpp"
|
#include "ws_engine.hpp"
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ void zmq::ws_connecter_t::out_event ()
|
|||||||
return;
|
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_)
|
void zmq::ws_connecter_t::timer_event (int id_)
|
||||||
@ -167,63 +167,20 @@ int zmq::ws_connecter_t::open ()
|
|||||||
{
|
{
|
||||||
zmq_assert (_s == retired_fd);
|
zmq_assert (_s == retired_fd);
|
||||||
|
|
||||||
// Resolve the address
|
tcp_address_t tcp_addr;
|
||||||
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);
|
|
||||||
_s = tcp_open_socket (_addr->address.c_str (), options, false, true,
|
_s = tcp_open_socket (_addr->address.c_str (), options, false, true,
|
||||||
_addr->resolved.tcp_addr);
|
&tcp_addr);
|
||||||
if (_s == retired_fd) {
|
if (_s == retired_fd)
|
||||||
// TODO we should emit some event in this case!
|
|
||||||
|
|
||||||
LIBZMQ_DELETE (_addr->resolved.tcp_addr);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
zmq_assert (_addr->resolved.tcp_addr != NULL);
|
|
||||||
|
|
||||||
// Set the socket to non-blocking mode so that we get async connect().
|
// Set the socket to non-blocking mode so that we get async connect().
|
||||||
unblock_socket (_s);
|
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.
|
// Connect to the remote peer.
|
||||||
#if defined ZMQ_HAVE_VXWORKS
|
#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
|
#else
|
||||||
rc = ::connect (_s, tcp_addr->addr (), tcp_addr->addrlen ());
|
int rc = ::connect (_s, tcp_addr.addr (), tcp_addr.addrlen ());
|
||||||
#endif
|
#endif
|
||||||
// Connect was successful immediately.
|
// Connect was successful immediately.
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
@ -307,8 +264,8 @@ void zmq::ws_connecter_t::create_engine (fd_t fd,
|
|||||||
endpoint_type_connect);
|
endpoint_type_connect);
|
||||||
|
|
||||||
// Create the engine object for this connection.
|
// Create the engine object for this connection.
|
||||||
ws_engine_t *engine =
|
ws_engine_t *engine = new (std::nothrow)
|
||||||
new (std::nothrow) ws_engine_t (fd, options, endpoint_pair, true);
|
ws_engine_t (fd, options, endpoint_pair, *_addr->resolved.ws_addr, true);
|
||||||
alloc_assert (engine);
|
alloc_assert (engine);
|
||||||
|
|
||||||
// Attach the engine to the corresponding session object.
|
// 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_,
|
zmq::ws_engine_t::ws_engine_t (fd_t fd_,
|
||||||
const options_t &options_,
|
const options_t &options_,
|
||||||
const endpoint_uri_pair_t &endpoint_uri_pair_,
|
const endpoint_uri_pair_t &endpoint_uri_pair_,
|
||||||
|
ws_address_t &address_,
|
||||||
bool client_) :
|
bool client_) :
|
||||||
stream_engine_base_t (fd_, options_, endpoint_uri_pair_),
|
stream_engine_base_t (fd_, options_, endpoint_uri_pair_),
|
||||||
_client (client_),
|
_client (client_),
|
||||||
|
_address (address_),
|
||||||
_client_handshake_state (client_handshake_initial),
|
_client_handshake_state (client_handshake_initial),
|
||||||
_server_handshake_state (handshake_initial),
|
_server_handshake_state (handshake_initial),
|
||||||
_header_name_position (0),
|
_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);
|
encode_base64 (nonce, 16, _websocket_key, MAX_HEADER_VALUE_LENGTH);
|
||||||
assert (size > 0);
|
assert (size > 0);
|
||||||
|
|
||||||
size = snprintf (
|
size = snprintf ((char *) _write_buffer, WS_BUFFER_SIZE,
|
||||||
(char *) _write_buffer, WS_BUFFER_SIZE,
|
"GET %s HTTP/1.1\r\n"
|
||||||
"GET / HTTP/1.1\r\n"
|
"Host: %s\r\n"
|
||||||
"Host: server.example.com\r\n" // TODO: we need the address here
|
"Upgrade: websocket\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Connection: Upgrade\r\n"
|
||||||
"Connection: Upgrade\r\n"
|
"Sec-WebSocket-Key: %s\r\n"
|
||||||
"Sec-WebSocket-Key: %s\r\n"
|
"Sec-WebSocket-Protocol: ZWS2.0\r\n"
|
||||||
"Sec-WebSocket-Protocol: ZWS2.0\r\n"
|
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
_address.path (), _address.host (), _websocket_key);
|
||||||
_websocket_key);
|
|
||||||
assert (size > 0 && size < WS_BUFFER_SIZE);
|
assert (size > 0 && size < WS_BUFFER_SIZE);
|
||||||
_outpos = _write_buffer;
|
_outpos = _write_buffer;
|
||||||
_outsize = size;
|
_outsize = size;
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "address.hpp"
|
#include "address.hpp"
|
||||||
#include "msg.hpp"
|
#include "msg.hpp"
|
||||||
#include "stream_engine_base.hpp"
|
#include "stream_engine_base.hpp"
|
||||||
|
#include "ws_address.hpp"
|
||||||
|
|
||||||
|
|
||||||
#define WS_BUFFER_SIZE 8192
|
#define WS_BUFFER_SIZE 8192
|
||||||
@ -130,6 +131,7 @@ class ws_engine_t : public stream_engine_base_t
|
|||||||
ws_engine_t (fd_t fd_,
|
ws_engine_t (fd_t fd_,
|
||||||
const options_t &options_,
|
const options_t &options_,
|
||||||
const endpoint_uri_pair_t &endpoint_uri_pair_,
|
const endpoint_uri_pair_t &endpoint_uri_pair_,
|
||||||
|
ws_address_t &address_,
|
||||||
bool client_);
|
bool client_);
|
||||||
~ws_engine_t ();
|
~ws_engine_t ();
|
||||||
|
|
||||||
@ -145,6 +147,7 @@ class ws_engine_t : public stream_engine_base_t
|
|||||||
bool server_handshake ();
|
bool server_handshake ();
|
||||||
|
|
||||||
bool _client;
|
bool _client;
|
||||||
|
ws_address_t _address;
|
||||||
|
|
||||||
ws_client_handshake_state_t _client_handshake_state;
|
ws_client_handshake_state_t _client_handshake_state;
|
||||||
ws_server_handshake_state_t _server_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_)
|
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) {
|
if (_s == retired_fd) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -133,7 +134,7 @@ int zmq::ws_listener_t::create_socket (const char *addr_)
|
|||||||
#if defined ZMQ_HAVE_VXWORKS
|
#if defined ZMQ_HAVE_VXWORKS
|
||||||
rc = bind (_s, (sockaddr *) _address.addr (), _address.addrlen ());
|
rc = bind (_s, (sockaddr *) _address.addr (), _address.addrlen ());
|
||||||
#else
|
#else
|
||||||
rc = bind (_s, _address.addr (), _address.addrlen ());
|
rc = bind (_s, address.addr (), address.addrlen ());
|
||||||
#endif
|
#endif
|
||||||
#ifdef ZMQ_HAVE_WINDOWS
|
#ifdef ZMQ_HAVE_WINDOWS
|
||||||
if (rc == SOCKET_ERROR) {
|
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
|
// socket was already created by the application
|
||||||
_s = options.use_fd;
|
_s = options.use_fd;
|
||||||
} else {
|
} else {
|
||||||
|
int rc = _address.resolve (addr_, true, options.ipv6);
|
||||||
|
if (rc != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (create_socket (addr_) == -1)
|
if (create_socket (addr_) == -1)
|
||||||
return -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_local),
|
||||||
get_socket_name (fd, socket_end_remote), endpoint_type_bind);
|
get_socket_name (fd, socket_end_remote), endpoint_type_bind);
|
||||||
|
|
||||||
ws_engine_t *engine =
|
ws_engine_t *engine = new (std::nothrow)
|
||||||
new (std::nothrow) ws_engine_t (fd, options, endpoint_pair, false);
|
ws_engine_t (fd, options, endpoint_pair, _address, false);
|
||||||
alloc_assert (engine);
|
alloc_assert (engine);
|
||||||
|
|
||||||
// Choose I/O thread to run connecter in. Given that we are already
|
// Choose I/O thread to run connecter in. Given that we are already
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#define __ZMQ_WS_LISTENER_HPP_INCLUDED__
|
#define __ZMQ_WS_LISTENER_HPP_INCLUDED__
|
||||||
|
|
||||||
#include "fd.hpp"
|
#include "fd.hpp"
|
||||||
#include "tcp_address.hpp"
|
#include "ws_address.hpp"
|
||||||
#include "stream_listener_base.hpp"
|
#include "stream_listener_base.hpp"
|
||||||
|
|
||||||
namespace zmq
|
namespace zmq
|
||||||
@ -63,7 +63,7 @@ class ws_listener_t : public stream_listener_base_t
|
|||||||
int create_socket (const char *addr_);
|
int create_socket (const char *addr_);
|
||||||
|
|
||||||
// Address to listen on.
|
// Address to listen on.
|
||||||
tcp_address_t _address;
|
ws_address_t _address;
|
||||||
|
|
||||||
ws_listener_t (const ws_listener_t &);
|
ws_listener_t (const ws_listener_t &);
|
||||||
const ws_listener_t &operator= (const ws_listener_t &);
|
const ws_listener_t &operator= (const ws_listener_t &);
|
||||||
|
@ -35,10 +35,11 @@ SETUP_TEARDOWN_TESTCONTEXT
|
|||||||
void test_roundtrip ()
|
void test_roundtrip ()
|
||||||
{
|
{
|
||||||
void *sb = test_context_socket (ZMQ_REP);
|
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);
|
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);
|
bounce (sb, sc);
|
||||||
|
|
||||||
@ -49,10 +50,10 @@ void test_roundtrip ()
|
|||||||
void test_short_message ()
|
void test_short_message ()
|
||||||
{
|
{
|
||||||
void *sb = test_context_socket (ZMQ_REP);
|
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);
|
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;
|
zmq_msg_t msg;
|
||||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 255));
|
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 255));
|
||||||
@ -78,10 +79,10 @@ void test_short_message ()
|
|||||||
void test_large_message ()
|
void test_large_message ()
|
||||||
{
|
{
|
||||||
void *sb = test_context_socket (ZMQ_REP);
|
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);
|
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;
|
zmq_msg_t msg;
|
||||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 65536));
|
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 65536));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user