//+------------------------------------------------------------------+ //| Socket.mqh | //| Copyright 2016, Li Ding | //| dingmaotu@hotmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2016, Li Ding" #property link "dingmaotu@hotmail.com" #property strict #include "Common.mqh" #import "libzmq.dll" // We can overload the same function for different data types // as in the C level the optval paramter is just a pointer #define SOCKOPT_OVERLOAD_ARRAY(TYPE) \ int zmq_setsockopt(intptr_t s,int option,const TYPE &optval[],\ size_t optvallen);\ int zmq_getsockopt(intptr_t s,int option,TYPE &optval[],\ size_t &optvallen);\ #define SOCKOPT_OVERLOAD(TYPE) \ int zmq_setsockopt(intptr_t s,int option,const TYPE &optval,\ size_t optvallen);\ int zmq_getsockopt(intptr_t s,int option,TYPE &optval,\ size_t &optvallen);\ SOCKOPT_OVERLOAD_ARRAY(uchar) SOCKOPT_OVERLOAD(long) SOCKOPT_OVERLOAD(ulong) SOCKOPT_OVERLOAD(int) SOCKOPT_OVERLOAD(uint) #import // Socket options #define ZMQ_AFFINITY 4 #define ZMQ_IDENTITY 5 #define ZMQ_SUBSCRIBE 6 #define ZMQ_UNSUBSCRIBE 7 #define ZMQ_RATE 8 #define ZMQ_RECOVERY_IVL 9 #define ZMQ_SNDBUF 11 #define ZMQ_RCVBUF 12 #define ZMQ_RCVMORE 13 #define ZMQ_FD 14 #define ZMQ_EVENTS 15 #define ZMQ_TYPE 16 #define ZMQ_LINGER 17 #define ZMQ_RECONNECT_IVL 18 #define ZMQ_BACKLOG 19 #define ZMQ_RECONNECT_IVL_MAX 21 #define ZMQ_MAXMSGSIZE 22 #define ZMQ_SNDHWM 23 #define ZMQ_RCVHWM 24 #define ZMQ_MULTICAST_HOPS 25 #define ZMQ_RCVTIMEO 27 #define ZMQ_SNDTIMEO 28 #define ZMQ_LAST_ENDPOINT 32 #define ZMQ_ROUTER_MANDATORY 33 #define ZMQ_TCP_KEEPALIVE 34 #define ZMQ_TCP_KEEPALIVE_CNT 35 #define ZMQ_TCP_KEEPALIVE_IDLE 36 #define ZMQ_TCP_KEEPALIVE_INTVL 37 #define ZMQ_IMMEDIATE 39 #define ZMQ_XPUB_VERBOSE 40 #define ZMQ_ROUTER_RAW 41 #define ZMQ_IPV6 42 #define ZMQ_MECHANISM 43 #define ZMQ_PLAIN_SERVER 44 #define ZMQ_PLAIN_USERNAME 45 #define ZMQ_PLAIN_PASSWORD 46 #define ZMQ_CURVE_SERVER 47 #define ZMQ_CURVE_PUBLICKEY 48 #define ZMQ_CURVE_SECRETKEY 49 #define ZMQ_CURVE_SERVERKEY 50 #define ZMQ_PROBE_ROUTER 51 #define ZMQ_REQ_CORRELATE 52 #define ZMQ_REQ_RELAXED 53 #define ZMQ_CONFLATE 54 #define ZMQ_ZAP_DOMAIN 55 #define ZMQ_ROUTER_HANDOVER 56 #define ZMQ_TOS 57 #define ZMQ_CONNECT_RID 61 #define ZMQ_GSSAPI_SERVER 62 #define ZMQ_GSSAPI_PRINCIPAL 63 #define ZMQ_GSSAPI_SERVICE_PRINCIPAL 64 #define ZMQ_GSSAPI_PLAINTEXT 65 #define ZMQ_HANDSHAKE_IVL 66 #define ZMQ_SOCKS_PROXY 68 #define ZMQ_XPUB_NODROP 69 #define ZMQ_BLOCKY 70 #define ZMQ_XPUB_MANUAL 71 #define ZMQ_XPUB_WELCOME_MSG 72 #define ZMQ_STREAM_NOTIFY 73 #define ZMQ_INVERT_MATCHING 74 #define ZMQ_HEARTBEAT_IVL 75 #define ZMQ_HEARTBEAT_TTL 76 #define ZMQ_HEARTBEAT_TIMEOUT 77 #define ZMQ_XPUB_VERBOSER 78 #define ZMQ_CONNECT_TIMEOUT 79 #define ZMQ_TCP_MAXRT 80 #define ZMQ_THREAD_SAFE 81 #define ZMQ_MULTICAST_MAXTPDU 84 #define ZMQ_VMCI_BUFFER_SIZE 85 #define ZMQ_VMCI_BUFFER_MIN_SIZE 86 #define ZMQ_VMCI_BUFFER_MAX_SIZE 87 #define ZMQ_VMCI_CONNECT_TIMEOUT 88 #define ZMQ_USE_FD 89 //+------------------------------------------------------------------+ //| A dedicated class to get/set socket options | //+------------------------------------------------------------------+ class SocketOptions { protected: intptr_t m_ref; #define SOCKOPT_WRAP_ARRAY(TYPE) \ bool setOption(int option,const TYPE &value[],size_t len) {return 0==zmq_setsockopt(m_ref,option,value,len);}\ bool getOption(int option,TYPE &value[],size_t &len) {return 0==zmq_getsockopt(m_ref,option,value,len);} #define SOCKOPT_WRAP(TYPE) \ bool setOption(int option,TYPE value) {return 0==zmq_setsockopt(m_ref,option,value,sizeof(TYPE));}\ bool getOption(int option,TYPE &value) {size_t s=sizeof(TYPE); return 0==zmq_getsockopt(m_ref,option,value,s);} SOCKOPT_WRAP_ARRAY(uchar) SOCKOPT_WRAP(int) SOCKOPT_WRAP(uint) SOCKOPT_WRAP(long) SOCKOPT_WRAP(ulong) bool setStringOption(int option,string value,bool ending=true); bool getStringOption(int option,string &value,size_t length=1024); SocketOptions(intptr_t ref):m_ref(ref){} public: //--- option templates //--- various integer options #define SOCKOPT_GET(TYPE, NAME, MACRO) \ bool get##NAME(TYPE &value) {return getOption(MACRO,value);} #define SOCKOPT_SET(TYPE, NAME, MACRO) \ bool set##NAME(TYPE value) {return setOption(MACRO,value);} #define SOCKOPT(TYPE,NAME,MACRO) \ SOCKOPT_GET(TYPE,NAME,MACRO) \ SOCKOPT_SET(TYPE,NAME,MACRO) //--- boolean options #define SOCKOPT_GET_BOOL(NAME, MACRO) \ bool is##NAME(bool &value) {int v; bool res=getOption(MACRO,v); value=(v==1);return res;} #define SOCKOPT_SET_BOOL(NAME, MACRO) \ bool set##NAME(bool value) {return setOption(MACRO,value?1:0);} #define SOCKOPT_BOOL(NAME,MACRO) \ SOCKOPT_GET_BOOL(NAME,MACRO) \ SOCKOPT_SET_BOOL(NAME,MACRO) //--- null-terminated string options #define SOCKOPT_GET_NTSTR(NAME,MACRO) \ bool get##NAME(string &value) {return getStringOption(MACRO,value);} #define SOCKOPT_SET_NTSTR(NAME,MACRO) \ bool set##NAME(string value) {return setStringOption(MACRO,value);} #define SOCKOPT_NTSTR(NAME,MACRO) \ SOCKOPT_GET_NTSTR(NAME,MACRO) \ SOCKOPT_SET_NTSTR(NAME,MACRO) //--- bytes array or string converted options #define SOCKOPT_SET_BYTES(OptionName,Macro) \ bool set##OptionName(const uchar &value[]) {return setOption(Macro,value,(size_t)ArraySize(value));} \ bool set##OptionName(string value) {return setStringOption(Macro,value,false);} #define SOCKOPT_GET_BYTES(OptionName,Macro,InitSize) \ bool get##OptionName(uchar &value[]) {size_t len=(size_t)InitSize; ArrayResize(value,(int)len); bool res=getOption(Macro,value,len); if(res){ArrayResize(value,(int)len);}return res;} \ bool get##OptionName(string &value) {return getStringOption(Macro,value,InitSize);} #define SOCKOPT_BYTES(OptionName,Macro,InitSize) \ SOCKOPT_SET_BYTES(OptionName,Macro) \ SOCKOPT_GET_BYTES(OptionName,Macro,InitSize) //--- for curve key #define SOCKOPT_CURVE_KEY(KeyType,Macro) \ bool getCurve##KeyType##Key(uchar &key[32]) {size_t len=32; return getOption(Macro,key,len);} \ bool getCurve##KeyType##Key(string &key) {return getStringOption(Macro,key,41);} \ bool setCurve##KeyType##Key(const uchar &key[32]) {return setOption(Macro,key,32);} \ bool setCurve##KeyType##Key(string key) {return setStringOption(Macro,key);} SOCKOPT_GET(int,Type,ZMQ_TYPE) SOCKOPT(ulong,Affinity,ZMQ_AFFINITY) //64bit bitmask SOCKOPT(int,BackLog,ZMQ_BACKLOG) // number of connections SOCKOPT(int,Timeout,ZMQ_CONNECT_TIMEOUT) // milliseconds SOCKOPT_GET_BOOL(ThreadSafe,ZMQ_THREAD_SAFE) SOCKOPT_SET_BOOL(Conflate,ZMQ_CONFLATE) // only for ZMQ_PULL, ZMQ_PUSH, ZMQ_SUB, ZMQ_PUB, ZMQ_DEALER types SOCKOPT_GET(int,Events,ZMQ_EVENTS); // bitmask of ZMQ_POLLIN, ZMQ_POLLOUT SOCKOPT_GET(uintptr_t,FileDescriptor,ZMQ_FD) SOCKOPT_GET(int,Mechanism,ZMQ_MECHANISM) // current security mechanism //--- plain SOCKOPT_NTSTR(PlainUsername,ZMQ_PLAIN_USERNAME) SOCKOPT_NTSTR(PlainPassword,ZMQ_PLAIN_PASSWORD) SOCKOPT_BOOL(PlainServer,ZMQ_PLAIN_SERVER) //--- gssapi: this is not supported in this binding. Following methods will FAIL if you invoke them SOCKOPT_BOOL(GssApiPlainText,ZMQ_GSSAPI_PLAINTEXT) SOCKOPT_BOOL(GssApiServer,ZMQ_GSSAPI_SERVER) SOCKOPT_NTSTR(GssApiPrincipal,ZMQ_GSSAPI_PRINCIPAL) SOCKOPT_NTSTR(GssApiServicePrincipal,ZMQ_GSSAPI_SERVICE_PRINCIPAL) //--- curve SOCKOPT_CURVE_KEY(Public,ZMQ_CURVE_PUBLICKEY) SOCKOPT_CURVE_KEY(Secret,ZMQ_CURVE_SECRETKEY) SOCKOPT_CURVE_KEY(Server,ZMQ_CURVE_SERVERKEY) SOCKOPT_SET_BOOL(CurveServer,ZMQ_CURVE_SERVER) SOCKOPT_GET_NTSTR(LastEndpoint,ZMQ_LAST_ENDPOINT) SOCKOPT(int,HandshakeInterval,ZMQ_HANDSHAKE_IVL) // milliseconds SOCKOPT_SET(int,HeartbeatInterval,ZMQ_HEARTBEAT_IVL) // milliseconds SOCKOPT_SET(int,HeartbeatTimeout,ZMQ_HEARTBEAT_TIMEOUT) // milliseconds SOCKOPT_SET(int,HeartbeatTTL,ZMQ_HEARTBEAT_TTL) // milliseconds SOCKOPT_BOOL(Immediate,ZMQ_IMMEDIATE) SOCKOPT_BOOL(Ipv6,ZMQ_IPV6) //--- ZMQ_IPV4ONLY is deprecated, use this instead SOCKOPT(int,Linger,ZMQ_LINGER) // milliseconds SOCKOPT(long,MaxMessageSize,ZMQ_MAXMSGSIZE) //--- multicast SOCKOPT(int,MulticastHops,ZMQ_MULTICAST_HOPS) // hops SOCKOPT(int,MulticastMaxTPDU,ZMQ_MULTICAST_MAXTPDU) // bytes SOCKOPT(int,MulticastRate,ZMQ_RATE) // kilobits per second SOCKOPT(int,RecoveryInterval,ZMQ_RECOVERY_IVL) // multicast recovery interval //--- there is a problem here: FileDescriptor should be SOCKET type on Windows, //--- while in the zmq doc it is a int. Possible error in the doc SOCKOPT(uintptr_t,UseFileDescriptor,ZMQ_USE_FD) SOCKOPT_SET_BOOL(ProbeRouter,ZMQ_PROBE_ROUTER) // only for ZMQ_ROUTER, ZMQ_DEALER, ZMQ_REQ SOCKOPT(int,ReceiveBuffer,ZMQ_RCVBUF) // bytes SOCKOPT(int,ReceiveHighWaterMark,ZMQ_RCVHWM) // messages SOCKOPT(int,ReceiveTimeout,ZMQ_RCVTIMEO) // milliseconds SOCKOPT(int,SendBuffer,ZMQ_SNDBUF) // bytes SOCKOPT(int,SendHighWaterMark,ZMQ_SNDHWM) // messages SOCKOPT(int,SendTimout,ZMQ_SNDTIMEO) SOCKOPT_GET_BOOL(ReceiveMore,ZMQ_RCVMORE) SOCKOPT(int,ReconnectInterval,ZMQ_RECONNECT_IVL) // milliseconds SOCKOPT(int,ReconnectIntervalMax,ZMQ_RECONNECT_IVL_MAX) // milliseconds //--- only for ZMQ_REQ SOCKOPT_SET_BOOL(RequestCorrelated,ZMQ_REQ_CORRELATE) SOCKOPT_SET_BOOL(RequestRelaxed,ZMQ_REQ_RELAXED) //--- only for ZMQ_SUB SOCKOPT_SET_BYTES(Subscribe,ZMQ_SUBSCRIBE) SOCKOPT_SET_BYTES(Unsubscribe,ZMQ_UNSUBSCRIBE) //--- convenience methods bool subscribe(string channel) {return setSubscribe(channel);} bool unsubscribe(string channel) {return setUnsubscribe(channel);} //--- only for ZMQ_XSUB SOCKOPT_BOOL(XpubVerbose,ZMQ_XPUB_VERBOSE) SOCKOPT_BOOL(XpubVerboser,ZMQ_XPUB_VERBOSER) SOCKOPT_BOOL(XpubManual,ZMQ_XPUB_MANUAL) SOCKOPT_BOOL(XpubNoDrop,ZMQ_XPUB_NODROP) // also for ZMQ_PUB SOCKOPT_SET_BYTES(XpubWelcomeMessage,ZMQ_XPUB_WELCOME_MSG) SOCKOPT_BOOL(InvertMatching,ZMQ_INVERT_MATCHING) //--- only for ZMQ_PUB, ZMQ_XPUB, ZMQ_SUB //--- only for ZMQ_ROUTER SOCKOPT_SET_BOOL(RouterHandover,ZMQ_ROUTER_HANDOVER) SOCKOPT_SET_BOOL(RouterMandatory,ZMQ_ROUTER_MANDATORY) SOCKOPT_SET_BOOL(RouterRaw,ZMQ_ROUTER_RAW) //--- only for ZMQ_STREAM SOCKOPT_SET_BOOL(StreamNotify,ZMQ_STREAM_NOTIFY) //--- only for ZMQ_ROUTER, ZMQ_STREAM SOCKOPT_SET_BYTES(ConnectRid,ZMQ_CONNECT_RID) //--- only for ZMQ_REP, ZMQ_REQ, ZMQ_ROUTER, ZMQ_DEALER SOCKOPT_BYTES(Identity,ZMQ_IDENTITY,255) //--- tcp SOCKOPT(int,TcpKeepAlive,ZMQ_TCP_KEEPALIVE) SOCKOPT(int,TcpKeepAliveCount,ZMQ_TCP_KEEPALIVE_CNT) SOCKOPT(int,TcpKeepAliveIdle,ZMQ_TCP_KEEPALIVE_IDLE) SOCKOPT(int,TcpKeepAliveInterval,ZMQ_TCP_KEEPALIVE_INTVL) SOCKOPT(int,TcpMaxRetransmitTimeout,ZMQ_TCP_MAXRT) SOCKOPT(int,TypeOfService,ZMQ_TOS) // IP_TOS //--- ZMQ_TCP_ACCEPT_FILTER //--- ZMQ_IPC_FILTER_GID //--- ZMQ_IPC_FILTER_PID //--- ZMQ_IPC_FILTER_UID //--- are deprecated in favor of ZAP API and ip address whitelisting/blacklisting SOCKOPT_NTSTR(ZapDomain,ZMQ_ZAP_DOMAIN) //--- only for vmci transport SOCKOPT(ulong,VmciBufferSize,ZMQ_VMCI_BUFFER_SIZE) // bytes SOCKOPT(ulong,VmciBufferMinSize,ZMQ_VMCI_BUFFER_MIN_SIZE) // bytes SOCKOPT(ulong,VmciBufferMaxSize,ZMQ_VMCI_BUFFER_MAX_SIZE) // bytes SOCKOPT(int,VmciConnectTimeout,ZMQ_VMCI_CONNECT_TIMEOUT) // milliseconds }; //+------------------------------------------------------------------+ //| The option value is a string with predefined byte length | //| | //| If it is a NULL-terminated string without predefined length, | //| The situation is tricky: we do not know the length of the option | //| value beforehand, but the function does not return the correct | //| one, either. So the only option is to guess. | //| | //| Here we adopt the solution of the Java binding. We just guess | //| that the length of a NULL-terminated string option is less than | //| 1024. So hopefully, it is the case. | //+------------------------------------------------------------------+ bool SocketOptions::getStringOption(int option,string &value,size_t length) { char buf[]; ArrayResize(buf,(int)length); bool res=getOption(option,buf,length); if(res) { value=StringFromUtf8(buf); } ArrayFree(buf); return res; } //+------------------------------------------------------------------+ //| The ending means that the converted buffer contains the ending | //| null. | //+------------------------------------------------------------------+ bool SocketOptions::setStringOption(int option,const string value,bool ending) { char buf[]; StringToUtf8(value,buf,ending); int len = ArraySize(buf); bool res=setOption(option,buf,len); ArrayFree(buf); return res; } //+------------------------------------------------------------------+