udp_socket.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include "stdafx.h"
  2. #include "udp_socket.h"
  3. #include "block_chain.h"
  4. #include "udp_address.h"
  5. #include <util/datetime/cputimer.h>
  6. #include <util/system/spinlock.h>
  7. #include <util/random/random.h>
  8. #include <library/cpp/netliba/socket/socket.h>
  9. #include <errno.h>
  10. //#define SIMULATE_NETWORK_FAILURES
  11. // there is no explicit bit in the packet header for last packet of transfer
  12. // last packet is just smaller then maximum size
  13. namespace NNetliba {
  14. static bool LocalHostFound;
  15. enum {
  16. IPv4 = 0,
  17. IPv6 = 1
  18. };
  19. struct TIPv6Addr {
  20. ui64 Network, Interface;
  21. TIPv6Addr() {
  22. Zero(*this);
  23. }
  24. TIPv6Addr(ui64 n, ui64 i)
  25. : Network(n)
  26. , Interface(i)
  27. {
  28. }
  29. };
  30. inline bool operator==(const TIPv6Addr& a, const TIPv6Addr& b) {
  31. return a.Interface == b.Interface && a.Network == b.Network;
  32. }
  33. static ui32 LocalHostIP[2];
  34. static TVector<ui32> LocalHostIPList[2];
  35. static TVector<TIPv6Addr> LocalHostIPv6List;
  36. // Struct sockaddr_in6 does not have ui64-array representation
  37. // so we add it here. This avoids "strict aliasing" warnings
  38. typedef union {
  39. in6_addr Addr;
  40. ui64 Addr64[2];
  41. } TIPv6AddrUnion;
  42. static ui32 GetIPv6SuffixCrc(const sockaddr_in6& addr) {
  43. TIPv6AddrUnion a;
  44. a.Addr = addr.sin6_addr;
  45. ui64 suffix = a.Addr64[1];
  46. return (suffix & 0xffffffffll) + (suffix >> 32);
  47. }
  48. bool InitLocalIPList() {
  49. // Do not use TMutex here: it has a non-trivial destructor which will be called before
  50. // destruction of current thread, if its TThread declared as global/static variable.
  51. static TAdaptiveLock cs;
  52. TGuard lock(cs);
  53. if (LocalHostFound)
  54. return true;
  55. TVector<TUdpAddress> addrs;
  56. if (!GetLocalAddresses(&addrs))
  57. return false;
  58. for (int i = 0; i < addrs.ysize(); ++i) {
  59. const TUdpAddress& addr = addrs[i];
  60. if (addr.IsIPv4()) {
  61. LocalHostIPList[IPv4].push_back(addr.GetIPv4());
  62. LocalHostIP[IPv4] = addr.GetIPv4();
  63. } else {
  64. sockaddr_in6 addr6;
  65. GetWinsockAddr(&addr6, addr);
  66. LocalHostIPList[IPv6].push_back(GetIPv6SuffixCrc(addr6));
  67. LocalHostIP[IPv6] = GetIPv6SuffixCrc(addr6);
  68. LocalHostIPv6List.push_back(TIPv6Addr(addr.Network, addr.Interface));
  69. }
  70. }
  71. LocalHostFound = true;
  72. return true;
  73. }
  74. template <class T, class TElem>
  75. inline bool IsInSet(const T& c, const TElem& e) {
  76. return Find(c.begin(), c.end(), e) != c.end();
  77. }
  78. bool IsLocalIPv4(ui32 ip) {
  79. return IsInSet(LocalHostIPList[IPv4], ip);
  80. }
  81. bool IsLocalIPv6(ui64 network, ui64 iface) {
  82. return IsInSet(LocalHostIPv6List, TIPv6Addr(network, iface));
  83. }
  84. //////////////////////////////////////////////////////////////////////////
  85. void TNetSocket::Open(int port) {
  86. TIntrusivePtr<NNetlibaSocket::ISocket> theSocket = NNetlibaSocket::CreateSocket();
  87. theSocket->Open(port);
  88. Open(theSocket);
  89. }
  90. void TNetSocket::Open(const TIntrusivePtr<NNetlibaSocket::ISocket>& socket) {
  91. s = socket;
  92. if (IsValid()) {
  93. PortCrc = s->GetSelfAddress().sin6_port;
  94. }
  95. }
  96. void TNetSocket::Close() {
  97. if (IsValid()) {
  98. s->Close();
  99. }
  100. }
  101. void TNetSocket::SendSelfFakePacket() const {
  102. s->CancelWait();
  103. }
  104. inline ui32 CalcAddressCrc(const sockaddr_in6& addr) {
  105. Y_ASSERT(addr.sin6_family == AF_INET6);
  106. const ui64* addr64 = (const ui64*)addr.sin6_addr.s6_addr;
  107. const ui32* addr32 = (const ui32*)addr.sin6_addr.s6_addr;
  108. if (addr64[0] == 0 && addr32[2] == 0xffff0000ll) {
  109. // ipv4
  110. return addr32[3];
  111. } else {
  112. // ipv6
  113. return GetIPv6SuffixCrc(addr);
  114. }
  115. }
  116. TNetSocket::ESendError TNetSocket::SendTo(const char* buf, int size, const sockaddr_in6& toAddress, const EFragFlag frag) const {
  117. Y_ASSERT(size >= UDP_LOW_LEVEL_HEADER_SIZE);
  118. ui32 crc = CalcChecksum(buf + UDP_LOW_LEVEL_HEADER_SIZE, size - UDP_LOW_LEVEL_HEADER_SIZE);
  119. ui32 ipCrc = CalcAddressCrc(toAddress);
  120. ui32 portCrc = toAddress.sin6_port;
  121. *(ui32*)buf = crc + ipCrc + portCrc;
  122. #ifdef SIMULATE_NETWORK_FAILURES
  123. if ((RandomNumber<size_t>() % 3) == 0)
  124. return true; // packet lost
  125. if ((RandomNumber<size_t>() % 3) == 0)
  126. (char&)(buf[RandomNumber<size_t>() % size]) += RandomNumber<size_t>(); // packet broken
  127. #endif
  128. char tosBuffer[NNetlibaSocket::TOS_BUFFER_SIZE];
  129. void* t = NNetlibaSocket::CreateTos(Tos, tosBuffer);
  130. const NNetlibaSocket::TIoVec iov = NNetlibaSocket::CreateIoVec((char*)buf, size);
  131. NNetlibaSocket::TMsgHdr hdr = NNetlibaSocket::CreateSendMsgHdr(toAddress, iov, t);
  132. const int rv = s->SendMsg(&hdr, 0, frag);
  133. if (rv < 0) {
  134. if (errno == EHOSTUNREACH || errno == ENETUNREACH) {
  135. return SEND_NO_ROUTE_TO_HOST;
  136. } else {
  137. return SEND_BUFFER_OVERFLOW;
  138. }
  139. }
  140. Y_ASSERT(rv == size);
  141. return SEND_OK;
  142. }
  143. inline bool CrcMatches(ui32 pktCrc, ui32 crc, const sockaddr_in6& addr) {
  144. Y_ASSERT(LocalHostFound);
  145. Y_ASSERT(addr.sin6_family == AF_INET6);
  146. // determine our ip address family based on the sender address
  147. // address family can not change in network, so sender address type determines type of our address used
  148. const ui64* addr64 = (const ui64*)addr.sin6_addr.s6_addr;
  149. const ui32* addr32 = (const ui32*)addr.sin6_addr.s6_addr;
  150. yint ipType;
  151. if (addr64[0] == 0 && addr32[2] == 0xffff0000ll) {
  152. // ipv4
  153. ipType = IPv4;
  154. } else {
  155. // ipv6
  156. ipType = IPv6;
  157. }
  158. if (crc + LocalHostIP[ipType] == pktCrc) {
  159. return true;
  160. }
  161. // crc failed
  162. // check if packet was sent to different IP address
  163. for (int idx = 0; idx < LocalHostIPList[ipType].ysize(); ++idx) {
  164. ui32 otherIP = LocalHostIPList[ipType][idx];
  165. if (crc + otherIP == pktCrc) {
  166. LocalHostIP[ipType] = otherIP;
  167. return true;
  168. }
  169. }
  170. // crc is really failed, discard packet
  171. return false;
  172. }
  173. bool TNetSocket::RecvFrom(char* buf, int* size, sockaddr_in6* fromAddress) const {
  174. for (;;) {
  175. int rv;
  176. if (s->IsRecvMsgSupported()) {
  177. const NNetlibaSocket::TIoVec v = NNetlibaSocket::CreateIoVec(buf, *size);
  178. NNetlibaSocket::TMsgHdr hdr = NNetlibaSocket::CreateRecvMsgHdr(fromAddress, v);
  179. rv = s->RecvMsg(&hdr, 0);
  180. } else {
  181. sockaddr_in6 dummy;
  182. TAutoPtr<NNetlibaSocket::TUdpRecvPacket> pkt = s->Recv(fromAddress, &dummy, -1);
  183. rv = !!pkt ? pkt->DataSize - pkt->DataStart : -1;
  184. if (rv > 0) {
  185. memcpy(buf, pkt->Data.get() + pkt->DataStart, rv);
  186. }
  187. }
  188. if (rv < 0)
  189. return false;
  190. // ignore empty packets
  191. if (rv == 0)
  192. continue;
  193. // skip small packets
  194. if (rv < UDP_LOW_LEVEL_HEADER_SIZE)
  195. continue;
  196. *size = rv;
  197. ui32 pktCrc = *(ui32*)buf;
  198. ui32 crc = CalcChecksum(buf + UDP_LOW_LEVEL_HEADER_SIZE, rv - UDP_LOW_LEVEL_HEADER_SIZE);
  199. if (!CrcMatches(pktCrc, crc + PortCrc, *fromAddress)) {
  200. // crc is really failed, discard packet
  201. continue;
  202. }
  203. return true;
  204. }
  205. }
  206. void TNetSocket::Wait(float timeoutSec) const {
  207. s->Wait(timeoutSec);
  208. }
  209. void TNetSocket::SetTOS(int n) const {
  210. Tos = n;
  211. }
  212. bool TNetSocket::Connect(const sockaddr_in6& addr) {
  213. // "connect" - meaningless operation
  214. // needed since port unreachable is routed only to "connected" udp sockets in ingenious FreeBSD
  215. if (s->Connect((sockaddr*)&addr, sizeof(addr)) < 0) {
  216. if (errno == EHOSTUNREACH || errno == ENETUNREACH) {
  217. return false;
  218. } else {
  219. Y_ASSERT(0);
  220. }
  221. }
  222. return true;
  223. }
  224. void TNetSocket::SendEmptyPacket() {
  225. NNetlibaSocket::TIoVec v;
  226. Zero(v);
  227. // darwin ignores packets with msg_iovlen == 0, also windows implementation uses sendto of first iovec.
  228. NNetlibaSocket::TMsgHdr hdr;
  229. Zero(hdr);
  230. hdr.msg_iov = &v;
  231. hdr.msg_iovlen = 1;
  232. s->SendMsg(&hdr, 0, FF_ALLOW_FRAG); // sends empty packet to connected address
  233. }
  234. bool TNetSocket::IsHostUnreachable() {
  235. #ifdef _win_
  236. char buf[10000];
  237. sockaddr_in6 fromAddress;
  238. const NNetlibaSocket::TIoVec v = NNetlibaSocket::CreateIoVec(buf, Y_ARRAY_SIZE(buf));
  239. NNetlibaSocket::TMsgHdr hdr = NNetlibaSocket::CreateRecvMsgHdr(&fromAddress, v);
  240. const ssize_t rv = s->RecvMsg(&hdr, 0);
  241. if (rv < 0) {
  242. int err = WSAGetLastError();
  243. if (err == WSAECONNRESET)
  244. return true;
  245. }
  246. #else
  247. int err = 0;
  248. socklen_t bufSize = sizeof(err);
  249. s->GetSockOpt(SOL_SOCKET, SO_ERROR, (char*)&err, &bufSize);
  250. if (err == ECONNREFUSED)
  251. return true;
  252. #endif
  253. return false;
  254. }
  255. }