Socket.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /******************************************************************************
  2. Use 'Socket' to communicate with external devices through the internet.
  3. /******************************************************************************/
  4. #define NULL_SOCKET Ptr(~0)
  5. /******************************************************************************/
  6. struct SockAddr // Socket Address
  7. {
  8. // get/set single value
  9. Bool valid ()C; // if address is valid
  10. Bool thisDevice()C; // if address points to this device using a local address (but not global)
  11. Int port ()C; SockAddr& port (Int port); // get/set port
  12. UInt ip4 ()C; SockAddr& ip4 (UInt ip4 ); // get/set IPv4
  13. Str8 ip4Text()C; Bool ip4Text(C Str8 &ip4 ); // get/set IPv4 in text format
  14. Str8 ip6Text()C; Bool ip6Text(C Str8 &ip6 ); // get/set IPv6 in text format
  15. Str8 ipText ()C; Bool ipText (C Str8 &ip ); // get/set IP in text format
  16. // set
  17. SockAddr& clear ( ); // clear address to zero
  18. Bool setFrom (C Socket &socket ); // set address from socket
  19. SockAddr& setServer ( Int port); // set address to be used for creating a server
  20. SockAddr& setLocalFast( Int port); // set address to local host ( fast ip will be used "127.0.0.1"), this allows connections only within the same device
  21. SockAddr& setLocal ( Int port); // set address to local host ( local ip will be used ), this allows connections only within the same device and local network (connecting beyond local network depends if the local host is behind a router)
  22. Bool setGlobal ( Int port); // set address to local host (global/public/external ip will be used ), this allows connections within the same device, local network and beyond (resolving global ip address requires connecting to external websites !!)
  23. Bool setHost (C Str &host, Int port); // set address to host from its name, false on fail
  24. SockAddr& setIp4Port ( UInt ip4 , Int port); // set address to direct IPv4 address with specified port
  25. Bool setIp4Port (C Str8 &ip4 , Int port); // set address to direct IPv4 address in text format with specified port, false on fail
  26. Bool setIp6Port (C Str8 &ip6 , Int port); // set address to direct IPv6 address in text format with specified port, false on fail
  27. Bool setIpPort (C Str8 &ip , Int port); // set address to direct IP address in text format with specified port, false on fail
  28. Bool setFtp (C Str &host) {return setHost(host, 21);}
  29. Bool setHttp(C Str &host) {return setHost(host, 80);}
  30. // conversions
  31. Str asText( )C; // get address as text
  32. Bool fromText(C Str8 &ip_port) ; // set address from text, false on fail
  33. // io
  34. Bool save(File &f)C; // save address to file, false on fail
  35. Bool load(File &f) ; // load address from file, false on fail
  36. SockAddr() {clear();}
  37. #if !EE_PRIVATE
  38. private:
  39. #endif
  40. UInt _data[7];
  41. #if EE_PRIVATE
  42. // don't use unions in EE_PRIVATE because of potential alignment issue "struct A {Bool b; SockAddr sa;}" would have different alignments when sockaddr_in is used and when it's not, use UInt to force alignment in case some platforms don't support unaligned reads
  43. ASSERT(SIZE(UInt)*7>=SIZE(sockaddr_in) && SIZE(UInt)*7>=SIZE(sockaddr_in6));
  44. sockaddr & sa() {return *(sockaddr *)_data;}
  45. C sockaddr & sa()C {return *(sockaddr *)_data;}
  46. sockaddr_in & v4() {return *(sockaddr_in *)_data;}
  47. C sockaddr_in & v4()C {return *(sockaddr_in *)_data;}
  48. sockaddr_in6& v6() {return *(sockaddr_in6*)_data;}
  49. C sockaddr_in6& v6()C {return *(sockaddr_in6*)_data;}
  50. #if APPLE
  51. INLINE U8& family() {return (U8&)v4().sin_family;}
  52. INLINE U8 family()C {return (U8&)v4().sin_family;}
  53. ASSERT(MEMBER_SIZE(sockaddr_in, sin_family)==SIZE(U8) && MEMBER_SIZE(sockaddr_in6, sin6_family)==SIZE(U8) && OFFSET(sockaddr_in, sin_family)==OFFSET(sockaddr_in6, sin6_family));
  54. #else
  55. INLINE U16& family() {return (U16&)v4().sin_family;}
  56. INLINE U16 family()C {return (U16&)v4().sin_family;}
  57. ASSERT(MEMBER_SIZE(sockaddr_in, sin_family)==SIZE(U16) && MEMBER_SIZE(sockaddr_in6, sin6_family)==SIZE(U16) && OFFSET(sockaddr_in, sin_family)==OFFSET(sockaddr_in6, sin6_family));
  58. #endif
  59. #if WINDOWS
  60. INLINE Int size()C {return SIZE(_data);}
  61. #else // must be precise on other platforms
  62. INLINE Int size()C {return (family()==AF_INET6) ? SIZE(sockaddr_in6) : SIZE(sockaddr_in);}
  63. #endif
  64. INLINE U16& portN() {return (U16&)v4().sin_port;} // port in Network Byte Order
  65. INLINE U16 portN()C {return (U16&)v4().sin_port;} // port in Network Byte Order
  66. ASSERT(MEMBER_SIZE(sockaddr_in, sin_port)==SIZE(U16) && MEMBER_SIZE(sockaddr_in6, sin6_port)==SIZE(U16) && OFFSET(sockaddr_in, sin_port)==OFFSET(sockaddr_in6, sin6_port));
  67. INLINE UInt& v4Ip4() {return (UInt&)v4().sin_addr;}
  68. INLINE UInt v4Ip4()C {return (UInt&)v4().sin_addr;}
  69. ASSERT(MEMBER_SIZE(sockaddr_in, sin_addr)==SIZE(UInt));
  70. INLINE Byte& v6B(Int i) {return ((Byte*)&v6().sin6_addr)[i];}
  71. INLINE Byte v6B(Int i)C {return ((Byte*)&v6().sin6_addr)[i];}
  72. INLINE UShort& v6S(Int i) {return ((UShort*)&v6().sin6_addr)[i];}
  73. INLINE UShort v6S(Int i)C {return ((UShort*)&v6().sin6_addr)[i];}
  74. INLINE UInt& v6I(Int i) {return ((UInt*)&v6().sin6_addr)[i];}
  75. INLINE UInt v6I(Int i)C {return ((UInt*)&v6().sin6_addr)[i];}
  76. INLINE UInt& v6Ip4() {return v6I(3);}
  77. INLINE UInt v6Ip4()C {return v6I(3);}
  78. INLINE void v6setAfterClearAny () {}
  79. INLINE void v6setAfterClearLocalHost() {v6B(15)=1;}
  80. INLINE void v6setAfterClearV4Mapped () {v6S( 5)=0xFFFF;}
  81. Bool needsV6()C; // if this requires an IPv6 socket
  82. Bool convert(C SockAddr &src); // this converts between IPv4<->IPv6, false on fail
  83. #endif
  84. };
  85. // compare
  86. Int Compare (C SockAddr &a, C SockAddr &b); // compare
  87. inline Bool operator==(C SockAddr &a, C SockAddr &b) {return Compare(a, b)==0;} // if equal
  88. inline Bool operator!=(C SockAddr &a, C SockAddr &b) {return Compare(a, b)!=0;} // if not equal
  89. /******************************************************************************/
  90. struct Socket
  91. {
  92. enum RESULT
  93. {
  94. FAILED , // couldn't connect
  95. CONNECTED , // connected successfully
  96. IN_PROGRESS, // still connecting, you can verify the connection state at a later time using 'connectFailed' method
  97. };
  98. // manage
  99. void del (); // delete
  100. Bool createTcp(Bool ipv6); // create Tcp socket, 'ipv6'=if create in IPv6 mode (IPv4 otherwise), false on fail, TCP protocol description: data is guaranteed to reach the target, data is always received in the same order as it was sent, sending multiple small packets may result in groupping them together and sending as one big packet
  101. Bool createUdp(Bool ipv6); // create Udp socket, 'ipv6'=if create in IPv6 mode (IPv4 otherwise), false on fail, UDP protocol description: data is not guaranteed to reach the target, data is not always received in the same order as it was sent, sending multiple small packets never results in groupping them together and sending as one big packet
  102. Bool createTcp(C SockAddr &addr); // this method will call 'createTcp(Bool ipv6)' with 'ipv6' parameter set based on specified 'addr' address and Dual-Stack Socket availability in the Operating System
  103. Bool createUdp(C SockAddr &addr); // this method will call 'createUdp(Bool ipv6)' with 'ipv6' parameter set based on specified 'addr' address and Dual-Stack Socket availability in the Operating System
  104. // get
  105. Bool is ()C {return _s!=NULL_SOCKET;} // if socket is valid
  106. Int port()C; // get socket port
  107. UInt ip4 ()C; // get socket IPV4 address
  108. SockAddr addr()C; // get socket address
  109. // set
  110. Bool block (Bool on); // set blocking mode , false on fail
  111. Bool tcpNoDelay(Bool on); // set TCP_NODELAY option, false on fail
  112. // operations
  113. Bool bind (C SockAddr &addr ); // bind socket to specific address, false on fail
  114. RESULT connect(C SockAddr &addr, Int timeout=-1); // connect socket to specific address, 'timeout'=how long (in milliseconds) to wait for a connection (<0 use default value specified by the OS, for >=0 values the socket will automatically be converted into non-blocking mode)
  115. Bool connectFailed( ); // you can use this method after getting IN_PROGRESS result from 'connect' method to test if the connection attempt has failed
  116. Bool listen( ); // start listening for incoming connections , false on fail
  117. Bool accept(Socket &connection, SockAddr &addr); // accept incomming connection and its address, false on fail, upon success 'connection' and 'addr' will be set according to the incomming connection properties
  118. // io
  119. Int send ( CPtr data, Int size); // send 'data' , returns the size of sent data ( -1 on fail )
  120. Int receive( Ptr data, Int size); // receive 'data' , returns the size of received data (0 on disconnection, -1 if no data awaiting)
  121. Int send (C SockAddr &addr, CPtr data, Int size); // send 'data' to 'addr' socket address, returns the size of sent data ( -1 on fail ), this method is available only for UDP sockets
  122. Int receive( SockAddr &addr, Ptr data, Int size); // receive 'data' from 'addr' socket address, returns the size of received data (0 on disconnection, -1 if no data awaiting), this method is available only for UDP sockets, if any data was received then 'addr' will be set to the address of the sender
  123. Bool wait (Int time); // wait 'time' milliseconds for data arrival , false on timeout
  124. Bool flush(Int time); // wait 'time' milliseconds until the data has been sent fully, false on timeout
  125. Bool any (Int time); // wait 'time' milliseconds for any 'wait' or 'flush' event , false on timeout
  126. Int available()C; // get number of bytes available for reading, -1 on fail
  127. #if EE_PRIVATE
  128. Bool select(Bool read, Bool write, Int time);
  129. void init (Bool ipv6);
  130. static Bool WouldBlock();
  131. #endif
  132. ~Socket() {del();}
  133. Socket() {_s=NULL_SOCKET;}
  134. #if !EE_PRIVATE
  135. private:
  136. #endif
  137. CPtr _s;
  138. NO_COPY_CONSTRUCTOR(Socket);
  139. };
  140. /******************************************************************************/
  141. STRUCT(SecureSocket , Socket)
  142. //{
  143. enum RESULT
  144. {
  145. OK = 0, // handshake succeeded (returned only for 'handshake')
  146. ERROR =-1, // !! -1 is reserved due to system Socket.send/receive error and can't be changed !!
  147. NEED_WAIT =-2,
  148. NEED_FLUSH=-3,
  149. BAD_CERT =-4, // bad certificate (returned only for 'handshake')
  150. };
  151. void del();
  152. void unsecure();
  153. Bool secure(CChar8 *host);
  154. void setDefaultFunc();
  155. RESULT handshake();
  156. Int send (CPtr data, Int size); // can return RESULT (ERROR as in 'Socket', and NEED_WAIT, NEED_FLUSH)
  157. Int receive( Ptr data, Int size); // can return RESULT (ERROR as in 'Socket', and NEED_WAIT, NEED_FLUSH)
  158. SecureSocket() { _secure=null;}
  159. ~SecureSocket() {unsecure();}
  160. #if !EE_PRIVATE
  161. private:
  162. #endif
  163. #if EE_PRIVATE && SUPPORT_MBED_TLS
  164. mbedtls_ssl_context *_secure;
  165. #else
  166. Ptr _secure;
  167. #endif
  168. NO_COPY_CONSTRUCTOR(SecureSocket);
  169. };
  170. /******************************************************************************/
  171. ULong GetMac(); // get MAC address of current device
  172. C Str& GetComputerName(); // get name of this computer which can be used in 'GetHostAddresses' function
  173. void GetLocalAddresses(MemPtr<SockAddr> addresses, Int port=0); // get a list of all known addresses for local host
  174. void GetHostAddresses (MemPtr<SockAddr> addresses, C Str &host, Int port=0); // get a list of all known addresses for specified host
  175. void GetGlobalIP(Bool refresh=false); // initiate obtaining global ip address in the background, 'refresh'=if ignore previously obtained ip address and try getting a new one in case it was changed
  176. Bool HasGlobalIP( ); // if successfully obtained global ip address
  177. Bool ObtainingGlobalIP( ); // if currently obtaining global ip address
  178. Bool SendMailSupported(); // check if 'SendMail' function is supported on this machine, this function should not be called before 'InitPre'
  179. Bool SendMail(C Str &from_name, C Str &from_email, C Str &to_name, C Str &to_email, C Str &subject, C Str &message); // send e-mail using local host as SMTP server, 'from_name'=name of the sender (example "John Smith"), 'from_email'=sender e-mail address (example "[email protected]"), 'to_name'=name of the recipent (example "Jane Smith"), 'to'=recipent e-mail address (example "[email protected]"), 'subject'=subject, 'message'=e-mail message
  180. #if EE_PRIVATE
  181. Bool GetDualStackSocket();
  182. Bool InitSocket();
  183. void ShutSocket();
  184. #endif
  185. /******************************************************************************/