291 lines
12 KiB
Plaintext
291 lines
12 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| Socket.mqh |
|
|
//| Copyright 2016, Li Ding |
|
|
//| dingmaotu@hotmail.com |
|
|
//+------------------------------------------------------------------+
|
|
#property strict
|
|
|
|
#include "Common.mqh"
|
|
#include "Context.mqh"
|
|
#include "SocketOptions.mqh"
|
|
#include "ZmqMsg.mqh"
|
|
//--- fd is SOCKET on Win32, which is defined as UINT_PTR
|
|
struct zmq_pollitem_t
|
|
{
|
|
intptr_t socket;
|
|
uintptr_t fd;
|
|
short events;
|
|
short revents;
|
|
};
|
|
|
|
//--- Socket types
|
|
#define ZMQ_PAIR 0
|
|
#define ZMQ_PUB 1
|
|
#define ZMQ_SUB 2
|
|
#define ZMQ_REQ 3
|
|
#define ZMQ_REP 4
|
|
#define ZMQ_DEALER 5
|
|
#define ZMQ_ROUTER 6
|
|
#define ZMQ_PULL 7
|
|
#define ZMQ_PUSH 8
|
|
#define ZMQ_XPUB 9
|
|
#define ZMQ_XSUB 10
|
|
#define ZMQ_STREAM 11
|
|
|
|
//--- Message options
|
|
#define ZMQ_MORE 1
|
|
#define ZMQ_SRCFD 2 // Deprecated
|
|
#define ZMQ_SHARED 3
|
|
|
|
//--- Send/recv options
|
|
#define ZMQ_DONTWAIT 1
|
|
#define ZMQ_SNDMORE 2
|
|
|
|
//--- Socket transport events (TCP, IPC and TIPC only)
|
|
#define ZMQ_EVENT_CONNECTED 0x0001
|
|
#define ZMQ_EVENT_CONNECT_DELAYED 0x0002
|
|
#define ZMQ_EVENT_CONNECT_RETRIED 0x0004
|
|
#define ZMQ_EVENT_LISTENING 0x0008
|
|
#define ZMQ_EVENT_BIND_FAILED 0x0010
|
|
#define ZMQ_EVENT_ACCEPTED 0x0020
|
|
#define ZMQ_EVENT_ACCEPT_FAILED 0x0040
|
|
#define ZMQ_EVENT_CLOSED 0x0080
|
|
#define ZMQ_EVENT_CLOSE_FAILED 0x0100
|
|
#define ZMQ_EVENT_DISCONNECTED 0x0200
|
|
#define ZMQ_EVENT_MONITOR_STOPPED 0x0400
|
|
#define ZMQ_EVENT_ALL 0xFFFF
|
|
|
|
//--- I/O multiplexing
|
|
#define ZMQ_POLLIN 1
|
|
#define ZMQ_POLLOUT 2
|
|
// We only use 0MQ sockets on Windows
|
|
// So POLLERR and POLLPRI is of no use
|
|
#define ZMQ_POLLERR 4
|
|
#define ZMQ_POLLPRI 8
|
|
|
|
#define ZMQ_POLLITEMS_DFLT 16
|
|
|
|
#import "libzmq.dll"
|
|
//+------------------------------------------------------------------+
|
|
//| Sockets |
|
|
//+------------------------------------------------------------------+
|
|
intptr_t zmq_socket(intptr_t context,int type);
|
|
int zmq_close(intptr_t s);
|
|
int zmq_bind(intptr_t s,const char &addr[]);
|
|
int zmq_connect(intptr_t s,const char &addr[]);
|
|
int zmq_unbind(intptr_t s,const char &addr[]);
|
|
int zmq_disconnect(intptr_t s,const char &addr[]);
|
|
int zmq_send(intptr_t s,const uchar &buf[],size_t len,int flags);
|
|
int zmq_send_const(intptr_t s,const uchar &buf[],size_t len,int flags);
|
|
int zmq_recv(intptr_t s,uchar &buf[],size_t len,int flags);
|
|
int zmq_socket_monitor(intptr_t s,const char &addr[],int events);
|
|
//+------------------------------------------------------------------+
|
|
//| Message |
|
|
//+------------------------------------------------------------------+
|
|
int zmq_msg_send(zmq_msg_t &msg,intptr_t s,int flags);
|
|
int zmq_msg_recv(zmq_msg_t &msg,intptr_t s,int flags);
|
|
//+------------------------------------------------------------------+
|
|
//| I/O multiplexing |
|
|
//+------------------------------------------------------------------+
|
|
int zmq_poll(zmq_pollitem_t &items[],int nitems,long timeout);
|
|
//+------------------------------------------------------------------+
|
|
//| Message proxying |
|
|
//+------------------------------------------------------------------+
|
|
int zmq_proxy(intptr_t frontend_ref,intptr_t backend_ref,intptr_t capture_ref);
|
|
int zmq_proxy_steerable(intptr_t frontend_ref,intptr_t backend_ref,intptr_t capture_ref,intptr_t control_ref);
|
|
#import
|
|
//+------------------------------------------------------------------+
|
|
//| Wraps a 0MQ socket |
|
|
//+------------------------------------------------------------------+
|
|
class Socket: public SocketOptions
|
|
{
|
|
public:
|
|
Socket(const Context &ctx,int type):SocketOptions(zmq_socket(ctx.ref(),type)){}
|
|
virtual ~Socket() {if(0!=zmq_close(m_ref)){Debug(StringFormat("Failed to close socket 0x%0X",m_ref));}}
|
|
|
|
// for better cooperation between objects
|
|
intptr_t ref() const {return m_ref;}
|
|
|
|
bool valid() const {return m_ref!=0;}
|
|
|
|
//--- see Zmq::error() if any of the following command failed
|
|
//--- connection management
|
|
bool bind(string addr);
|
|
bool unbind(string addr);
|
|
bool connect(string addr);
|
|
bool disconnect(string addr);
|
|
|
|
//--- send and receive packets
|
|
bool recv(uchar &buf[],bool nowait=false);
|
|
bool send(const uchar &buf[],bool nowait=false,bool more=false);
|
|
bool sendConst(const uchar &buf[],bool nowait=false,bool more=false);
|
|
|
|
bool send(ZmqMsg &msg,bool nowait=false,bool more=false);
|
|
bool recv(ZmqMsg &msg,bool nowait=false);
|
|
|
|
void register(zmq_pollitem_t &pollitem,bool read=false,bool write=false);
|
|
void register(zmq_pollitem_t &pollitems[],int index,bool read=false,bool write=false);
|
|
|
|
//--- monitor socket events
|
|
bool monitor(string addr,int events);
|
|
|
|
//--- proxy
|
|
static bool proxy(Socket *frontend,Socket *backend,Socket *capture);
|
|
static bool proxySteerable(Socket *frontend,Socket *backend,Socket *capture,Socket *control);
|
|
|
|
//--- poll
|
|
static int poll(zmq_pollitem_t &arr[],long timeout);
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::bind(string addr)
|
|
{
|
|
char arr[];
|
|
StringToUtf8(addr,arr);
|
|
bool res=(0==zmq_bind(m_ref,arr));
|
|
ArrayFree(arr);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::unbind(string addr)
|
|
{
|
|
char arr[];
|
|
StringToUtf8(addr,arr);
|
|
bool res=(0==zmq_unbind(m_ref,arr));
|
|
ArrayFree(arr);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::connect(string addr)
|
|
{
|
|
char arr[];
|
|
StringToUtf8(addr,arr);
|
|
bool res=(0==zmq_connect(m_ref,arr));
|
|
ArrayFree(arr);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::disconnect(string addr)
|
|
{
|
|
char arr[];
|
|
StringToUtf8(addr,arr);
|
|
bool res=(0==zmq_disconnect(m_ref,arr));
|
|
ArrayFree(arr);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::recv(uchar &buf[],bool nowait=false)
|
|
{
|
|
int options=0;
|
|
if(nowait) options|=ZMQ_DONTWAIT;
|
|
return 0==zmq_recv(m_ref,buf,ArraySize(buf),options);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::send(const uchar &buf[],bool nowait=false,bool more=false)
|
|
{
|
|
int options=0;
|
|
if(nowait) options|=ZMQ_DONTWAIT;
|
|
if(more) options|=ZMQ_SNDMORE;
|
|
return 0==zmq_send(m_ref,buf,ArraySize(buf),options);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::sendConst(const uchar &buf[],bool nowait=false,bool more=false)
|
|
{
|
|
int options=0;
|
|
if(nowait) options|=ZMQ_DONTWAIT;
|
|
if(more) options|=ZMQ_SNDMORE;
|
|
return 0==zmq_send_const(m_ref,buf,ArraySize(buf),options);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Send a zmq_msg_t through a socket |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::send(ZmqMsg &msg,bool nowait=false,bool more=false)
|
|
{
|
|
int flags=0;
|
|
if(nowait) flags|=ZMQ_DONTWAIT;
|
|
if(more) flags|=ZMQ_SNDMORE;
|
|
return -1!=zmq_msg_send(msg,m_ref,flags);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Receive a zmq_msg_t from a socket |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::recv(ZmqMsg &msg,bool nowait=false)
|
|
{
|
|
int flags=0;
|
|
if(nowait) flags|=ZMQ_DONTWAIT;
|
|
return -1!=zmq_msg_recv(msg,m_ref,flags);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::monitor(string addr,int events)
|
|
{
|
|
uchar str[];
|
|
StringToUtf8(addr,str);
|
|
bool res=(0==zmq_socket_monitor(m_ref,str,events));
|
|
ArrayFree(str);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void Socket::register(zmq_pollitem_t &pollitem,bool read=false,bool write=false)
|
|
{
|
|
ZeroMemory(pollitem);
|
|
pollitem.socket=m_ref;
|
|
if(read) pollitem.events|=ZMQ_POLLIN;
|
|
if(write) pollitem.events|=ZMQ_POLLOUT;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void Socket::register(zmq_pollitem_t &pollitems[],int index,bool read=false,bool write=false)
|
|
{
|
|
ZeroMemory(pollitems[index]);
|
|
pollitems[index].socket=m_ref;
|
|
if(read) pollitems[index].events|=ZMQ_POLLIN;
|
|
if(write) pollitems[index].events|=ZMQ_POLLOUT;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::proxy(Socket *frontend,Socket *backend,Socket *capture)
|
|
{
|
|
intptr_t frontend_ref= CheckPointer(frontend)==POINTER_DYNAMIC?frontend.ref():0;
|
|
intptr_t backend_ref = CheckPointer(backend)==POINTER_DYNAMIC?backend.ref():0;
|
|
intptr_t capture_ref=CheckPointer(capture)==POINTER_DYNAMIC?capture.ref():0;
|
|
return 0==zmq_proxy(frontend_ref, backend_ref, capture_ref);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Socket::proxySteerable(Socket *frontend,Socket *backend,Socket *capture,Socket *control)
|
|
{
|
|
intptr_t frontend_ref= CheckPointer(frontend)==POINTER_DYNAMIC?frontend.ref():0;
|
|
intptr_t backend_ref = CheckPointer(backend)==POINTER_DYNAMIC?backend.ref():0;
|
|
intptr_t capture_ref=CheckPointer(capture)==POINTER_DYNAMIC?capture.ref():0;
|
|
intptr_t control_ref=CheckPointer(control)==POINTER_DYNAMIC?control.ref():0;
|
|
return 0==zmq_proxy_steerable(frontend_ref, backend_ref, capture_ref, control_ref);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int Socket::poll(zmq_pollitem_t &arr[],long timeout)
|
|
{
|
|
return zmq_poll(arr,ArraySize(arr),timeout);
|
|
}
|
|
//+------------------------------------------------------------------+
|