Socket.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************
  4. Warning/TODO/FIXME: Once every few months 'UpdateCertificates' should be called to update latest version of trusted certificates for SSL/TLS/HTTPS
  5. Last Updated: 1 Feb 2019
  6. /******************************************************************************/
  7. #define UPDATE_CERTIFICATES (DEBUG && 0)
  8. /******************************************************************************/
  9. #define FORCE_IPV6 1 // prefer IPv6 addresses to avoid unnecessary 'convert' calls
  10. #if !WINDOWS
  11. #define SOCKET UIntPtr
  12. #define SOCKET_ERROR -1
  13. #endif
  14. #if WINDOWS_OLD && SUPPORT_WINDOWS_XP
  15. static const Bool DualStackSocket=(OSVerNumber().x>5); // not supported on WinXP, on WinXP one Socket can't be used for IPv4 and IPv6 connections at the same time, "In order to support both IPv4 and IPv6 on Windows XP with Service Pack 1 (SP1) and on Windows Server 2003, an application has to create two sockets, one socket for use with IPv4 and one socket for use with IPv6. These two sockets must be handled separately by the application." - https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
  16. #else
  17. #define DualStackSocket true // other OS's should support it
  18. #endif
  19. #define IP4_ANY 0 // "0.0.0.0" any address will be selected
  20. #define IP4_LOCAL_HOST 16777343 // "127.0.0.1" localhost
  21. #ifndef INET6_ADDRSTRLEN
  22. #define INET6_ADDRSTRLEN 65 // maximum length of an IPv6 address in text format (this constant was obtained from "ws2ipdef.h") (45: IPv6 address including embedded IPv4 address, 11: Scope Id, 2: Brackets around IPv6 address when port is present, 6: Port (including colon), 1: Terminating null byte)
  23. #endif
  24. #define LOG_ERROR 0
  25. #if LOG_ERROR
  26. #pragma message("!! Warning: Use this only for debugging !!")
  27. #endif
  28. namespace EE{
  29. /******************************************************************************/
  30. #define IPV6_SIZE 16 // 16 bytes
  31. ASSERT(MEMBER_SIZE(sockaddr_in6, sin6_addr)==IPV6_SIZE);
  32. #define IPV6_UINTS (16/SIZE(UInt)) // number of UInt's in IPv6 address
  33. ASSERT(IPV6_SIZE%SIZE(UInt)==0);
  34. static INLINE Int CompareV6(C UInt *a, C UInt *b) // assumes that a!=null && b!=null
  35. {
  36. REP(IPV6_UINTS)if(Int c=Compare(*a++, *b++))return c;
  37. return 0;
  38. }
  39. #if WINDOWS_OLD && SUPPORT_WINDOWS_XP // Windows XP doesn't have 'inet_pton' and 'inet_ntop' and apps won't start, so the functions need to be written manually
  40. static Int inet_ptonXP(Int addr_family, CChar8 *src, Ptr addr)
  41. {
  42. Char8 src_copy[INET6_ADDRSTRLEN]; Set(src_copy, src); // need to make a copy because the 'WSAStringToAddressA' param is not const
  43. sockaddr_storage sock_addr; Zero(sock_addr);
  44. int size=SIZE(sock_addr);
  45. if(WSAStringToAddressA(src_copy, addr_family, null, (sockaddr*)&sock_addr, &size)==0)switch(addr_family)
  46. {
  47. case AF_INET : *( in_addr*)addr=((sockaddr_in &)sock_addr). sin_addr; return 1;
  48. case AF_INET6: *(in6_addr*)addr=((sockaddr_in6&)sock_addr).sin6_addr; return 1;
  49. }
  50. return 0;
  51. }
  52. static CChar8* inet_ntopXP(Int addr_family, CPtr addr, Char8 *dest, DWORD dest_length)
  53. {
  54. sockaddr_storage sock_addr; Zero(sock_addr);
  55. switch(sock_addr.ss_family=addr_family)
  56. {
  57. case AF_INET : ((sockaddr_in &)sock_addr). sin_addr=*( in_addr*)addr; break;
  58. case AF_INET6: ((sockaddr_in6&)sock_addr).sin6_addr=*(in6_addr*)addr; break;
  59. default : return null;
  60. }
  61. return (WSAAddressToStringA((sockaddr*)&sock_addr, SIZE(sock_addr), null, dest, &dest_length)==0) ? dest : null;
  62. }
  63. #define inet_pton inet_ptonXP
  64. #define inet_ntop inet_ntopXP
  65. #endif
  66. /******************************************************************************/
  67. static ULong Mac;
  68. static Str ComputerName;
  69. #if WINDOWS
  70. static WSADATA WsaData;
  71. #endif
  72. static CChar8 *GlobalIPSites[]=
  73. {
  74. "http://checkip.dyndns.org", // 0 - returns text "Current IP Address: X.X.X.X"
  75. "http://www.icanhazip.com/", // 1
  76. "http://ifconfig.me/ip" , // 2
  77. //"http://automation.whatismyip.com/n09230945.asp", noticed on Feb 2013 that it is now paid only
  78. //"http://www.whatismyip.org/", noticed on May 2012 that this no longer returns IP in text format (but in HTML+graphics image)
  79. }; static const Int GlobalIPSiteSkipText=0;
  80. /******************************************************************************/
  81. static Bool TextToIP4(CChar8 *text, UInt &ip)
  82. {
  83. VecB4 v;
  84. CalcValue c;
  85. FREPA(v.c)
  86. {
  87. text=TextValue(text, c, false); if(c.type!=CVAL_INT || c.i<0 || c.i>255)goto error;
  88. if((i<3) ? !text || *text++!='.' : Is(text))goto error;
  89. v.c[i]=c.i;
  90. }
  91. ip=v.u; return true;
  92. error:
  93. ip=0; return false;
  94. }
  95. static Bool EqualIgnorePort(C SockAddr &a, C SockAddr &b) // !! this ignores port and v6(v4-mapped) IP4_LOCAL_HOST and IP4_ANY !!
  96. {
  97. if(a.family()!=b.family()) // they can still be the same if it's a v4 and v6(v4-mapped)
  98. {
  99. C SockAddr *v4=null, *v6=null;
  100. switch(a.family())
  101. {
  102. case AF_INET : v4=&a; break;
  103. case AF_INET6: v6=&a; break;
  104. default : return false;
  105. }
  106. switch(b.family())
  107. {
  108. case AF_INET : v4=&b; break;
  109. case AF_INET6: v6=&b; break;
  110. default : return false;
  111. }
  112. return v4 && v6 && v6->v6Ip4()==v4->v4Ip4() && IN6_IS_ADDR_V4MAPPED(&v6->v6().sin6_addr); // check IP4's first because it's faster
  113. }
  114. switch(a.family()) // at this stage a.family==b.family
  115. {
  116. default : return true;
  117. case AF_INET : return a.v4Ip4()==b.v4Ip4();
  118. case AF_INET6: return IN6_ARE_ADDR_EQUAL(&a.v6().sin6_addr, &b.v6().sin6_addr)!=0;
  119. }
  120. }
  121. /******************************************************************************/
  122. struct GlobalIPChecker
  123. {
  124. Bool busy;
  125. SockAddr addr;
  126. Download d[Elms(GlobalIPSites)];
  127. SyncLock lock;
  128. GlobalIPChecker() {busy=false;}
  129. ~GlobalIPChecker() {del();}
  130. static void Update(GlobalIPChecker &gipc) {gipc.update(true);}
  131. Bool valid()C {return addr.family()!=0;}
  132. void start()
  133. {
  134. if(!busy)
  135. {
  136. SyncLocker locker(lock); if(!busy)
  137. {
  138. busy=true;
  139. REPAO(d).create(GlobalIPSites[i]);
  140. App._callbacks.add(Update, T);
  141. }
  142. }
  143. }
  144. void del()
  145. {
  146. if(busy)
  147. {
  148. SyncLocker locker(lock); if(busy)
  149. {
  150. REPAO(d).stop(); App._callbacks.exclude(Update, T);
  151. REPAO(d).del ();
  152. busy=false;
  153. }
  154. }
  155. }
  156. void update(Bool callback)
  157. {
  158. SyncLocker locker(lock);
  159. Bool waiting=false; // if any of the downloads are still active
  160. REPA(d)switch(d[i].state())
  161. {
  162. case DWNL_CONNECTING:
  163. case DWNL_AUTH :
  164. case DWNL_SENDING :
  165. case DWNL_DOWNLOAD : waiting=true; break;
  166. case DWNL_DONE:
  167. {
  168. FileText f; f.readMem(d[i].data(), d[i].done());
  169. Str8 t; f.getLine(t); CChar8 *text=t;
  170. if(i==GlobalIPSiteSkipText)
  171. {
  172. if(text=TextPos(text, ':'))text++;
  173. if(text && text[0]==' ' )text++;
  174. }
  175. if(addr.ipText(text))
  176. {
  177. del(); return;
  178. }
  179. d[i].del(); // don't process this download again
  180. }break;
  181. }
  182. if(!waiting)del();else if(callback)App._callbacks.add(Update, T);
  183. }
  184. void wait()
  185. {
  186. for(;;)
  187. {
  188. update(false);
  189. #if HAS_THREADS
  190. if(!busy)break;
  191. Time.wait(1);
  192. #else
  193. break; // when there are no threads, waiting can do nothing
  194. #endif
  195. }
  196. }
  197. };
  198. static GlobalIPChecker GIPC;
  199. /******************************************************************************/
  200. // SOCKET ADDRESS
  201. /******************************************************************************/
  202. Bool SockAddr::valid()C
  203. {
  204. switch(family())
  205. {
  206. case AF_INET :
  207. case AF_INET6: return true;
  208. }
  209. return false;
  210. }
  211. Bool SockAddr::thisDevice()C
  212. {
  213. switch(family())
  214. {
  215. default : return false;
  216. case AF_INET : if(v4Ip4()==IP4_LOCAL_HOST)return true; break;
  217. case AF_INET6: if(v6Ip4()==IP4_LOCAL_HOST && IN6_IS_ADDR_V4MAPPED(&v6().sin6_addr) // check IP4 first because it's faster
  218. || IN6_IS_ADDR_LOOPBACK(&v6().sin6_addr))return true; break;
  219. }
  220. Memt<SockAddr> addrs; GetLocalAddresses(addrs); REPA(addrs)if(EqualIgnorePort(T, addrs[i]))return true;
  221. return false;
  222. }
  223. Bool SockAddr::needsV6()C
  224. {
  225. return family()==AF_INET6
  226. && !IN6_IS_ADDR_V4MAPPED (&v6().sin6_addr)
  227. && !IN6_IS_ADDR_LOOPBACK (&v6().sin6_addr)
  228. && !IN6_IS_ADDR_UNSPECIFIED(&v6().sin6_addr);
  229. }
  230. /******************************************************************************
  231. Bool SockAddr::universal()C // if socket can be of any family
  232. {
  233. switch(family())
  234. {
  235. case AF_INET: return v4Ip4()==IP4_LOCAL_HOST
  236. || v4Ip4()==IP4_ANY;
  237. case AF_INET6:
  238. {
  239. if(IN6_IS_ADDR_LOOPBACK (&v6().sin6_addr)
  240. || IN6_IS_ADDR_UNSPECIFIED(&v6().sin6_addr))return true;
  241. if(IN6_IS_ADDR_V4MAPPED (&v6().sin6_addr))
  242. {
  243. return v6Ip4()==IP4_LOCAL_HOST
  244. || v6Ip4()==IP4_ANY;
  245. }
  246. }break;
  247. }
  248. return false;
  249. }
  250. /******************************************************************************/
  251. SockAddr& SockAddr::clear()
  252. {
  253. Zero(T); return T;
  254. }
  255. /******************************************************************************/
  256. Int SockAddr::port()C
  257. {
  258. return ntohs(portN());
  259. }
  260. SockAddr& SockAddr::port(Int port)
  261. {
  262. portN()=htons(port);
  263. return T;
  264. }
  265. /******************************************************************************/
  266. UInt SockAddr::ip4()C
  267. {
  268. switch(family())
  269. {
  270. case AF_INET : return v4Ip4();
  271. case AF_INET6:
  272. {
  273. if(IN6_IS_ADDR_V4MAPPED (&v6().sin6_addr))return v6Ip4();
  274. if(IN6_IS_ADDR_LOOPBACK (&v6().sin6_addr))return IP4_LOCAL_HOST;
  275. //if(IN6_IS_ADDR_UNSPECIFIED(&v6().sin6_addr))return IP4_ANY; IP4_ANY is 0 which is returned either way below
  276. }break;
  277. }
  278. return 0;
  279. }
  280. SockAddr& SockAddr::ip4(UInt ip4)
  281. {
  282. Int port_n=portN(); // we're doing a direct copy so 'ntohs' is not needed
  283. clear();
  284. portN()=port_n; // we're doing a direct copy so 'htons' is not needed
  285. #if FORCE_IPV6
  286. #if APPLE
  287. v6().sin6_len=SIZE(sockaddr_in6);
  288. #endif
  289. v6setAfterClearV4Mapped();
  290. v6Ip4 ()=ip4;
  291. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  292. #else
  293. #if APPLE
  294. v4().sin_len=SIZE(sockaddr_in);
  295. #endif
  296. v4Ip4 ()=ip4;
  297. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  298. #endif
  299. return T;
  300. }
  301. Bool SockAddr::ip4Text(C Str8 &ip4)
  302. {
  303. Int port_n=portN(); // we're doing a direct copy so 'ntohs' is not needed
  304. clear();
  305. portN()=port_n; // always keep port, we're doing a direct copy so 'htons' is not needed
  306. #if FORCE_IPV6
  307. if(TextToIP4(ip4, v6Ip4()))
  308. {
  309. #if APPLE
  310. v6().sin6_len=SIZE(sockaddr_in6);
  311. #endif
  312. v6setAfterClearV4Mapped();
  313. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  314. #else
  315. if(TextToIP4(ip4, v4Ip4()))
  316. {
  317. #if APPLE
  318. v4().sin_len=SIZE(sockaddr_in);
  319. #endif
  320. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  321. #endif
  322. return true;
  323. }
  324. return false;
  325. }
  326. Bool SockAddr::ip6Text(C Str8 &ip6)
  327. {
  328. Int port_n=portN(); // we're doing a direct copy so 'ntohs' is not needed
  329. clear();
  330. portN()=port_n; // always keep port, we're doing a direct copy so 'htons' is not needed
  331. #if WINDOWS_OLD && SUPPORT_WINDOWS_XP // instead of calling manually written 'inet_pton' because of Windows XP, just call 'WSAStringToAddressA' directly
  332. sockaddr_in6 temp;
  333. int size=SIZE(temp);
  334. if(WSAStringToAddressA(ConstCast(ip6()), AF_INET6, null, (sockaddr*)&temp, &size)==0) // Warning: this assumes that 'WSAStringToAddressA' will not modify the 'ip6'
  335. {
  336. v6().sin6_addr=temp.sin6_addr; // copy only 'addr', without the 'port' and 'scope' from 'temp' to match 'inet_pton'
  337. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  338. return true;
  339. }
  340. #else
  341. if(inet_pton(AF_INET6, ip6, &v6().sin6_addr)==1)
  342. {
  343. #if APPLE
  344. v6().sin6_len=SIZE(sockaddr_in6);
  345. #endif
  346. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  347. return true;
  348. }
  349. #endif
  350. return false;
  351. }
  352. Bool SockAddr::ipText(C Str8 &ip)
  353. {
  354. return ip4Text(ip) || ip6Text(ip);
  355. }
  356. Str8 SockAddr::ip4Text()C
  357. {
  358. switch(family())
  359. {
  360. case AF_INET:
  361. {
  362. VecB4 v; v.u=v4Ip4(); return v.asTextDots();
  363. }break;
  364. case AF_INET6:
  365. {
  366. VecB4 v;
  367. if(IN6_IS_ADDR_V4MAPPED (&v6().sin6_addr))v.u=v6Ip4() ;else
  368. if(IN6_IS_ADDR_LOOPBACK (&v6().sin6_addr))v.u=IP4_LOCAL_HOST;else
  369. if(IN6_IS_ADDR_UNSPECIFIED(&v6().sin6_addr))v.u=IP4_ANY ;else break;
  370. return v.asTextDots();
  371. }break;
  372. }
  373. return S;
  374. }
  375. Str8 SockAddr::ip6Text()C
  376. {
  377. switch(family())
  378. {
  379. case AF_INET:
  380. {
  381. VecB4 v; v.u=v4Ip4(); return S+"::ffff:"+v.asTextDots();
  382. }break;
  383. case AF_INET6:
  384. {
  385. Char8 text[INET6_ADDRSTRLEN];
  386. #if WINDOWS_OLD && SUPPORT_WINDOWS_XP // instead of calling manually written 'inet_ntop' because of Windows XP, just call 'WSAAddressToStringA' directly
  387. sockaddr_in6 temp; Zero(temp); // we need to set only 'family' and 'addr', because otherwise, 'scope' and 'port' can be included in the name
  388. temp.sin6_family=AF_INET6;
  389. temp.sin6_addr =v6().sin6_addr;
  390. DWORD length=Elms(text); return (WSAAddressToStringA((sockaddr*)&temp, SIZE(temp), null, text, &length)==0) ? text : null;
  391. #else
  392. return inet_ntop(AF_INET6, (Ptr)&v6().sin6_addr, text, Elms(text));
  393. #endif
  394. }break;
  395. }
  396. return S;
  397. }
  398. Str8 SockAddr::ipText()C
  399. {
  400. switch(family())
  401. {
  402. case AF_INET : ip4: return ip4Text();
  403. case AF_INET6: if(!needsV6())goto ip4; return ip6Text();
  404. }
  405. return S;
  406. }
  407. /******************************************************************************/
  408. Bool SockAddr::setFrom(C Socket &socket)
  409. {
  410. socklen_t size=SIZE(_data);
  411. return getsockname((SOCKET)socket._s, (sockaddr*)&_data, &size)!=SOCKET_ERROR;
  412. }
  413. SockAddr& SockAddr::setLocal(Int port)
  414. {
  415. #if 1 // prefer IPv4, this function is most often used for displaying address of the local device, so it can be used on other devices for connecting to it. Prefer IPv4 as they're shorter and easier to type. As it was tested on Jul 2015, using 3 laptops: Windows 7, Windows 8.1, Mac OS X 10.10. When using 'GetHostAddresses' for getting local addresses of other devices, all devices displayed IPv4, as for IPv6 only Win8 displayed address for Win7 laptop (it connected fine to that address). However when trying to connect via manually typed IPv6 addresses obtained from 'GetLocalAddresses': Win laptops connected through only half of the IPv6 addresses, and Mac failed to connect to all Win IPv6 with EHOSTUNREACH error.
  416. Memt<SockAddr> addrs; GetHostAddresses(addrs, ComputerName, port);
  417. FREPA(addrs)if(addrs[i].family()==AF_INET){Swap(T, addrs[i]); return T;} // look for IPv4 first
  418. if(addrs.elms())Swap(T, addrs.first());else clear(); // grab the first result as it is recommended to process results in order
  419. #else
  420. setHost(ComputerName, port);
  421. #endif
  422. return T;
  423. }
  424. Bool SockAddr::setHost(C Str &host, Int port)
  425. {
  426. Memt<SockAddr> addrs; GetHostAddresses(addrs, host, port);
  427. if(addrs.elms())
  428. {
  429. Swap(T, addrs.first()); // grab the first result as it is recommended to process results in order
  430. return true;
  431. }
  432. clear(); return false;
  433. }
  434. SockAddr& SockAddr::setServer(Int port)
  435. {
  436. clear();
  437. portN()=htons(port);
  438. #if 1 // prefer IPv6 to avoid calling 'convert'
  439. #if APPLE
  440. v6().sin6_len=SIZE(sockaddr_in6);
  441. #endif
  442. v6setAfterClearAny();
  443. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  444. #else
  445. #if APPLE
  446. v4().sin_len=SIZE(sockaddr_in);
  447. #endif
  448. v4Ip4 ()=IP4_ANY;
  449. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  450. #endif
  451. return T;
  452. }
  453. SockAddr& SockAddr::setLocalFast(Int port)
  454. {
  455. clear();
  456. portN()=htons(port);
  457. #if 1 // prefer IPv6 to avoid calling 'convert'
  458. #if APPLE
  459. v6().sin6_len=SIZE(sockaddr_in6);
  460. #endif
  461. v6setAfterClearLocalHost();
  462. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  463. #else
  464. #if APPLE
  465. v4().sin_len=SIZE(sockaddr_in);
  466. #endif
  467. v4Ip4 ()=IP4_LOCAL_HOST;
  468. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  469. #endif
  470. return T;
  471. }
  472. Bool SockAddr::setGlobal(Int port)
  473. {
  474. if(!GIPC.valid()){GIPC.start(); GIPC.wait();}
  475. if( GIPC.valid()){T=GIPC.addr; T.port(port); return true;}
  476. clear(); return false;
  477. }
  478. SockAddr& SockAddr::setIp4Port(UInt ip4, Int port)
  479. {
  480. clear();
  481. portN()=htons(port);
  482. #if FORCE_IPV6
  483. #if APPLE
  484. v6().sin6_len=SIZE(sockaddr_in6);
  485. #endif
  486. v6setAfterClearV4Mapped();
  487. v6Ip4 ()=ip4;
  488. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  489. #else
  490. #if APPLE
  491. v4().sin_len=SIZE(sockaddr_in);
  492. #endif
  493. v4Ip4 ()=ip4;
  494. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  495. #endif
  496. return T;
  497. }
  498. Bool SockAddr::setIp4Port(C Str8 &ip4, Int port)
  499. {
  500. clear();
  501. #if FORCE_IPV6
  502. if(TextToIP4(ip4, v6Ip4()))
  503. {
  504. #if APPLE
  505. v6().sin6_len=SIZE(sockaddr_in6);
  506. #endif
  507. v6setAfterClearV4Mapped();
  508. portN ()=htons(port);
  509. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  510. #else
  511. if(TextToIP4(ip4, v4Ip4()))
  512. {
  513. #if APPLE
  514. v4().sin_len=SIZE(sockaddr_in);
  515. #endif
  516. portN ()=htons(port);
  517. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  518. #endif
  519. return true;
  520. }
  521. return false;
  522. }
  523. Bool SockAddr::setIp6Port(C Str8 &ip6, Int port)
  524. {
  525. if(ip6Text(ip6))
  526. {
  527. portN()=htons(port);
  528. return true;
  529. }
  530. clear(); return false;
  531. }
  532. Bool SockAddr::setIpPort(C Str8 &ip, Int port)
  533. {
  534. if(ipText(ip))
  535. {
  536. portN()=htons(port);
  537. return true;
  538. }
  539. clear(); return false;
  540. }
  541. /******************************************************************************/
  542. Str SockAddr::asText()C
  543. {
  544. switch(family())
  545. {
  546. case AF_INET : ip4: return ip4Text()+ ':'+port();
  547. case AF_INET6: if(!needsV6())goto ip4; return S+'['+ip6Text()+"]:"+port();
  548. }
  549. return S;
  550. }
  551. Bool SockAddr::fromText(C Str8 &ip_port)
  552. {
  553. if(CChar8 *addr=_SkipStartPath(_SkipStartPath(ip_port, "http://"), "https://"))
  554. {
  555. if(*addr=='[') // try IPv6
  556. {
  557. Int pos =TextPosI(addr, ']');
  558. if( pos>=0 && addr[pos+1]==':')
  559. {
  560. Int port=TextInt(addr+pos+2); if(InRange(port, 0x10000))return setIp6Port(Str8(addr+1).clip(pos-1), port);
  561. }
  562. }else // try IPv4 + Name
  563. {
  564. Int pos =TextPosI(addr, ':');
  565. if( pos>=0)
  566. {
  567. Int port=TextInt(addr+pos+1); if(InRange(port, 0x10000))
  568. {
  569. Str8 a=addr; a.clip(pos);
  570. return setIp4Port(a, port) || setHost(a, port);
  571. }
  572. }
  573. }
  574. }
  575. clear(); return false;
  576. }
  577. /******************************************************************************/
  578. Bool SockAddr::convert(C SockAddr &src)
  579. {
  580. switch(src.family())
  581. {
  582. case AF_INET:
  583. {
  584. // copy first in case "&src==this"
  585. Int port_n=src.portN(); // we're doing a direct copy so 'ntohs' is not needed
  586. UInt ip4=src.v4Ip4();
  587. clear();
  588. #if APPLE
  589. v6().sin6_len=SIZE(sockaddr_in6);
  590. #endif
  591. switch(ip4)
  592. {
  593. case IP4_ANY : v6setAfterClearAny (); break; // handle special cases in case dual-stack isn't supported
  594. case IP4_LOCAL_HOST: v6setAfterClearLocalHost(); break; // handle special cases in case dual-stack isn't supported
  595. default : v6setAfterClearV4Mapped (); v6Ip4()=ip4; break; // set v4-mapped
  596. }
  597. portN ()=port_n; // we're doing a direct copy so 'htons' is not needed
  598. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  599. }return true;
  600. case AF_INET6:
  601. {
  602. // copy first in case "&src==this"
  603. Int port_n=src.portN(); // we're doing a direct copy so 'ntohs' is not needed
  604. UInt ip4;
  605. if(IN6_IS_ADDR_V4MAPPED (&src.v6().sin6_addr))ip4=src.v6Ip4() ;else
  606. if(IN6_IS_ADDR_LOOPBACK (&src.v6().sin6_addr))ip4=IP4_LOCAL_HOST;else
  607. if(IN6_IS_ADDR_UNSPECIFIED(&src.v6().sin6_addr))ip4=IP4_ANY ;else break;
  608. clear();
  609. #if APPLE
  610. v4().sin_len=SIZE(sockaddr_in);
  611. #endif
  612. v4Ip4 ()=ip4;
  613. portN ()=port_n; // we're doing a direct copy so 'htons' is not needed
  614. family()=AF_INET; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  615. }return true;
  616. }
  617. return false;
  618. }
  619. /******************************************************************************/
  620. Int Compare(C SockAddr &a, C SockAddr &b)
  621. {
  622. if(Int c=Compare(a.family(), b.family()))return c;
  623. switch(a.family())
  624. {
  625. case AF_INET : if(Int c=Compare(a.v4Ip4(), b.v4Ip4()))return c; break;
  626. case AF_INET6: if(Int c=CompareV6((UInt*)&a.v6().sin6_addr, (UInt*)&b.v6().sin6_addr))return c; break;
  627. }
  628. return Compare(a.port(), b.port());
  629. }
  630. /******************************************************************************/
  631. Bool SockAddr::save(File &f)C
  632. {
  633. switch(family()) // we can use 'putByte' because we know that these versions will fit in one byte
  634. {
  635. default : f.putByte ( 0); break;
  636. case AF_INET : f.putMulti(Byte(1), UInt(v4Ip4()), U16(port())); break;
  637. case AF_INET6: if(!needsV6())f.putMulti(Byte(1), UInt( ip4()), U16(port()));
  638. else f.putMulti(Byte(2), U16(port()))<<v6().sin6_addr; break;
  639. }
  640. return f.ok();
  641. }
  642. Bool SockAddr::load(File &f)
  643. {
  644. switch(f.decUIntV())
  645. {
  646. case 0: clear(); return f.ok();
  647. case 1:
  648. {
  649. UInt ip; U16 port; f.getMulti(ip, port);
  650. if(f.ok()){setIp4Port(ip, port); return true;}
  651. }break;
  652. case 2:
  653. {
  654. clear();
  655. port(f.getUShort());
  656. #if APPLE
  657. v6().sin6_len=SIZE(sockaddr_in6);
  658. #endif
  659. f>>v6().sin6_addr;
  660. family()=AF_INET6; // !! set family as last for thread-safety, because some methods (including 'GIPC') detect if address is valid based on family !!
  661. if(f.ok())return true;
  662. }break;
  663. }
  664. clear(); return false;
  665. }
  666. /******************************************************************************/
  667. // SOCKET
  668. /******************************************************************************/
  669. void Socket::init(Bool ipv6)
  670. {
  671. #if APPLE
  672. int val=1; setsockopt((SOCKET)_s, SOL_SOCKET, SO_NOSIGPIPE, &val, SIZE(val)); // disable SIGPIPE process signal on Unix machines (it is received when writing to closed socket, and it causes process termination)
  673. #endif
  674. if(ipv6 && DualStackSocket) // don't bother if it's not supported
  675. {
  676. int val=0; setsockopt((SOCKET)_s, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&val, SIZE(val)); // this allows binding to IPv4-mapped IPv6
  677. }
  678. }
  679. void Socket::del()
  680. {
  681. if(is())
  682. {
  683. #if WINDOWS
  684. closesocket((SOCKET)_s);
  685. #else
  686. close((SOCKET)_s);
  687. #endif
  688. _s=NULL_SOCKET;
  689. }
  690. }
  691. Bool Socket::createTcp(Bool ipv6) {del(); _s=(CPtr)socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if(is()){init(ipv6); return true;} return false;}
  692. Bool Socket::createUdp(Bool ipv6) {del(); _s=(CPtr)socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM , IPPROTO_UDP); if(is()){init(ipv6); return true;} return false;}
  693. // if we support 'DualStackSocket' then always create IPv6, because IPv6 with 'DualStackSocket' can support both modes
  694. // otherwise the address can be v4 only - use IPv4, v6 only - use IPv6, or universal (LOCAL_HOST / ANY) - use IPv4
  695. // this was tested: ConnectionServer was created with IPv6, Connection was created with IPv4 and tried to connect to a IPv4 address of the server, that failed. Result: Server needs to have IPv4 when 'DualStackSocket' is not supported.
  696. Bool Socket::createTcp(C SockAddr &addr) {return createTcp(DualStackSocket || addr.needsV6());}
  697. Bool Socket::createUdp(C SockAddr &addr) {return createUdp(DualStackSocket || addr.needsV6());}
  698. /******************************************************************************/
  699. Int Socket::port()C {SockAddr addr; addr.setFrom(T); return addr.port();}
  700. UInt Socket::ip4 ()C {SockAddr addr; addr.setFrom(T); return addr.ip4 ();}
  701. SockAddr Socket::addr()C {SockAddr addr; addr.setFrom(T); return addr ;}
  702. /******************************************************************************/
  703. Bool Socket::block(Bool on)
  704. {
  705. if(is())
  706. {
  707. #if WEB
  708. return !on; // web sockets are always non-blocking, this can't be changed, so return success only if non-blocking mode was requested
  709. #elif WINDOWS
  710. DWORD non_block=(on ? false : true); return ioctlsocket((SOCKET)_s, FIONBIO, &non_block)!=SOCKET_ERROR;
  711. #else
  712. UInt non_block=(on ? false : true); return ioctl ((SOCKET)_s, FIONBIO, &non_block)!=SOCKET_ERROR; // works better than : int flags=fcntl((SOCKET)_s, F_GETFL, 0); FlagSet(flags, O_NONBLOCK, !on); return fcntl((SOCKET)_s, F_SETFL, flags)!=SOCKET_ERROR;
  713. #endif
  714. }
  715. return false;
  716. }
  717. Bool Socket::tcpNoDelay(Bool on)
  718. {
  719. if(is())
  720. {
  721. int flag=on;
  722. return !setsockopt((SOCKET)_s, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, SIZE(flag));
  723. }
  724. return false;
  725. }
  726. /******************************************************************************/
  727. Socket::RESULT Socket::connect(C SockAddr &addr, Int timeout) // !! warning: this sets non-blocking mode when timeout is specified, but does not restore the blocking mode after !!
  728. {
  729. if(timeout>=0)block(false);
  730. #if !WINDOWS
  731. again:
  732. #endif
  733. if(::connect((SOCKET)_s, (C sockaddr*)&addr._data, addr.size())!=SOCKET_ERROR)return CONNECTED;
  734. switch(PLATFORM(WSAGetLastError(), errno)) // don't use 'Socket::WouldBlock' here because it's not meant for 'connect'
  735. {
  736. case PLATFORM(WSAEWOULDBLOCK, EINPROGRESS): // according to docs only these enums can occur for IN_PROGRESS, Win - https://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx Mac - http://www.manpages.info/macosx/connect.2.html Linux - http://man7.org/linux/man-pages/man2/connect.2.html
  737. {
  738. in_progress:
  739. if(any(timeout) )return CONNECTED;
  740. if(!connectFailed())return IN_PROGRESS;
  741. }break;
  742. /*#if WINDOWS
  743. case WSAECONNREFUSED: return REFUSED;
  744. #endif*/
  745. #if !WINDOWS
  746. case EINTR: goto again; // call was interrupted by a signal
  747. #endif
  748. case PLATFORM(WSAEAFNOSUPPORT, EAFNOSUPPORT):
  749. #if !WINDOWS
  750. case EINVAL: // this error can happen on Android (Lollipop 5.0) and Linux (Ubuntu 14.10)
  751. case EPERM : // this error can happen on iOS 9
  752. #endif
  753. {
  754. SockAddr temp; if(temp.convert(addr))
  755. {
  756. #if !WINDOWS
  757. again_2:
  758. #endif
  759. if(::connect((SOCKET)_s, (C sockaddr*)&temp._data, temp.size())!=SOCKET_ERROR)return CONNECTED;
  760. switch(PLATFORM(WSAGetLastError(), errno)) // don't use 'Socket::WouldBlock' here because it's not meant for 'connect'
  761. {
  762. case PLATFORM(WSAEWOULDBLOCK, EINPROGRESS): goto in_progress;
  763. #if !WINDOWS
  764. case EINTR: goto again_2; // call was interrupted by a signal
  765. #endif
  766. }
  767. }
  768. }break;
  769. #if LOG_ERROR
  770. default: LogN(S+"Socket.connect failed:"+PLATFORM(WSAGetLastError(), errno)); break;
  771. #endif
  772. }
  773. return FAILED;
  774. }
  775. Bool Socket::connectFailed()
  776. {
  777. #if !WEB
  778. if(is())
  779. {
  780. Int error=0; socklen_t size=SIZE(error);
  781. if(getsockopt((SOCKET)_s, SOL_SOCKET, SO_ERROR, (char*)&error, &size)!=SOCKET_ERROR)return error!=0;
  782. }
  783. #endif
  784. return false;
  785. }
  786. Bool Socket::bind(C SockAddr &addr)
  787. {
  788. if(::bind((SOCKET)_s, (C sockaddr*)&addr._data, addr.size())!=SOCKET_ERROR)return true;
  789. switch(PLATFORM(WSAGetLastError(), errno))
  790. {
  791. #if !WINDOWS // leave these extra checks just in case
  792. case EINVAL: // this error can happen on Android (Lollipop 5.0) and Linux (Ubuntu 14.10)
  793. case EPERM : // this error can happen on iOS 9
  794. #endif
  795. case PLATFORM(WSAEAFNOSUPPORT, EAFNOSUPPORT):
  796. {
  797. SockAddr temp; if(temp.convert(addr))return ::bind((SOCKET)_s, (C sockaddr*)&temp._data, temp.size())!=SOCKET_ERROR;
  798. }break;
  799. #if LOG_ERROR
  800. default: LogN(S+"Socket.bind:"+PLATFORM(WSAGetLastError(), errno)); break;
  801. #endif
  802. }
  803. return false;
  804. }
  805. Bool Socket::listen( ) {return ::listen((SOCKET)_s, SOMAXCONN)!=SOCKET_ERROR;}
  806. Bool Socket::accept(Socket &connection, SockAddr &addr)
  807. {
  808. connection.del(); addr.clear();
  809. if(is())
  810. {
  811. socklen_t size=SIZE(addr._data); connection._s=(CPtr)::accept((SOCKET)_s, (sockaddr*)&addr._data, &size);
  812. if(connection.is())
  813. {
  814. connection.init(false); // don't adjust IPV6_V6ONLY because the socket is already connected to an address and can't be adjusted afterwards, doing that would fail and cause an error
  815. return true;
  816. }
  817. }
  818. return false;
  819. }
  820. /******************************************************************************/
  821. #if !WINDOWS && !APPLE
  822. #define SEND_FLAGS MSG_NOSIGNAL // use MSG_NOSIGNAL to disable SIGPIPE process signal when writing to closed socket
  823. #else
  824. #define SEND_FLAGS 0
  825. #endif
  826. Int Socket::send ( CPtr data, Int size) { return ::send ((SOCKET)_s, (Char8*)data, size, SEND_FLAGS);}
  827. Int Socket::receive( Ptr data, Int size) { return ::recv ((SOCKET)_s, (Char8*)data, size, 0);}
  828. Int Socket::receive( SockAddr &addr, Ptr data, Int size) {socklen_t addr_size=SIZE(addr._data); return ::recvfrom((SOCKET)_s, (Char8*)data, size, 0, (sockaddr*)&addr._data, &addr_size);}
  829. Int Socket::send (C SockAddr &addr, CPtr data, Int size)
  830. {
  831. Int sent=::sendto((SOCKET)_s, (Char8*)data, size, SEND_FLAGS, (C sockaddr*)&addr._data, addr.size());
  832. if( sent<0)switch(PLATFORM(WSAGetLastError(), errno))
  833. {
  834. #if !WINDOWS // leave these extra checks just in case
  835. case EINVAL: // this error can happen on Android (Lollipop 5.0) and Linux (Ubuntu 14.10)
  836. case EPERM : // this error can happen on iOS 9
  837. #endif
  838. case PLATFORM(WSAEAFNOSUPPORT, EAFNOSUPPORT):
  839. {
  840. SockAddr temp; if(temp.convert(addr))sent=::sendto((SOCKET)_s, (Char8*)data, size, SEND_FLAGS, (C sockaddr*)&temp._data, temp.size());
  841. }break;
  842. #if LOG_ERROR
  843. default: LogN(S+"Socket.send failed:"+PLATFORM(WSAGetLastError(), errno)); break;
  844. #endif
  845. }
  846. return sent;
  847. }
  848. Bool Socket::WouldBlock()
  849. {
  850. switch(PLATFORM(WSAGetLastError(), errno))
  851. {
  852. case PLATFORM(WSAEWOULDBLOCK, EWOULDBLOCK):
  853. #if !WINDOWS && EAGAIN!=EWOULDBLOCK
  854. case EAGAIN:
  855. #endif
  856. #if !WINDOWS
  857. case EINTR: // call was interrupted by a signal
  858. #endif
  859. return true;
  860. #if LOG_ERROR
  861. default: LogN(S+"Socket failed:"+PLATFORM(WSAGetLastError(), errno)); break;
  862. #endif
  863. }
  864. return false;
  865. }
  866. /******************************************************************************/
  867. Bool Socket::select(Bool read, Bool write, Int time)
  868. {
  869. if(is())
  870. {
  871. fd_set fd;
  872. #if WINDOWS
  873. fd.fd_count=1; fd.fd_array[0]=SOCKET(_s);
  874. #else
  875. FD_ZERO(&fd); FD_SET(SOCKET(_s), &fd);
  876. #endif
  877. timeval tv; if(time>0){tv.tv_sec=time/1000; tv.tv_usec=(time%1000)*1000;}else tv.tv_sec=tv.tv_usec=0;
  878. return ::select(SOCKET(_s)+1, read ? &fd : null, write ? &fd : null, null, &tv)>0;
  879. }
  880. return false;
  881. }
  882. Bool Socket::wait (Int time) {return select( true, false, time);}
  883. Bool Socket::flush(Int time) {return select(false, true, time);}
  884. Bool Socket::any (Int time) {return select( true, true, time);}
  885. Int Socket::available()C
  886. {
  887. if(is())
  888. {
  889. #if WINDOWS
  890. DWORD size; if(ioctlsocket((SOCKET)_s, FIONREAD, &size)!=SOCKET_ERROR)return size;
  891. #else
  892. UInt size; if(ioctl ((SOCKET)_s, FIONREAD, &size)!=SOCKET_ERROR)return size;
  893. #endif
  894. }
  895. return -1;
  896. }
  897. /******************************************************************************/
  898. // MAIN
  899. /******************************************************************************/
  900. static Bool ConnectSMTPIPv6Failed;
  901. static Bool ConnectSMTP(Socket &socket)
  902. {
  903. SockAddr addr; addr.setLocalFast(25); // 25 is the default port for SMTP servers
  904. if(DualStackSocket && !ConnectSMTPIPv6Failed) // try IPv6 first if dual stack sockets are supported, and only if it didn't fail before (IPv6 can fail with WSAECONNREFUSED for some reason on Windows Server 2012, while IPv4 succeeded. However WSAECONNREFUSED is returned as well for Windows 10 which has no SMTP at all)
  905. {
  906. if(socket.createTcp(true))switch(socket.connect(addr))
  907. {
  908. case Socket::CONNECTED: return true;
  909. default : ConnectSMTPIPv6Failed=true; break;
  910. }
  911. }
  912. return socket.createTcp(false) && socket.connect(addr)==Socket::CONNECTED; // try IPv4 later
  913. }
  914. Bool SendMailSupported()
  915. {
  916. Socket sock; return ConnectSMTP(sock);
  917. }
  918. Bool SendMail(C Str &from_name, C Str &from_email, C Str &to_name, C Str &to_email, C Str &subject, C Str &body)
  919. {
  920. Socket sock; if(ConnectSMTP(sock))
  921. {
  922. Byte buf[64*1024];
  923. Str8 m;
  924. const Bool log=false;
  925. if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf);
  926. m= "HELO SendMail\r\n" ; sock.send(m(), m.length()); if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf);
  927. m=S+"MAIL FROM:"+from_email+"\r\n"; sock.send(m(), m.length()); if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf);
  928. m=S+"RCPT TO:" + to_email+"\r\n"; sock.send(m(), m.length()); if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf);
  929. m= "DATA\r\n" ; sock.send(m(), m.length()); if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf);
  930. m=(from_name.is() ? S+ "FROM:"+from_name+" <"+from_email+">\r\n" : S)
  931. +( to_name.is() ? S+ "TO:"+ to_name+" <"+ to_email+">\r\n" : S)
  932. +"SUBJECT:"+ subject+"\r\n"
  933. + body +"\r\n"
  934. + ".\r\n"; sock.send(m(), m.length()); if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf); Bool ok=(buf[0]=='2');
  935. m="QUIT\r\n" ; sock.send(m(), m.length()); if(log)Zero(buf); sock.receive(buf, SIZE(buf)); if(log)LogN(S+(char*)buf);
  936. return ok;
  937. }
  938. return false;
  939. }
  940. /******************************************************************************/
  941. Bool GetDualStackSocket() {return DualStackSocket;}
  942. ULong GetMac () {return Mac;}
  943. C Str& GetComputerName () {return ComputerName;}
  944. /******************************************************************************/
  945. void GetLocalAddresses(MemPtr<SockAddr> addresses, Int port) {return GetHostAddresses(addresses, ComputerName, port);}
  946. void GetHostAddresses (MemPtr<SockAddr> addresses, C Str &host, Int port)
  947. {
  948. addresses.clear();
  949. const Bool allow_local_host=true; // allow local host as it's actually needed if for example we want to use 'Download' (which uses this function) to connect to "localhost"
  950. #if WINDOWS
  951. // 'GetAddrInfoW' requires at least Windows XP with SP2
  952. ADDRINFOW hints; Zero(hints);
  953. hints.ai_family =AF_UNSPEC;
  954. hints.ai_socktype=SOCK_STREAM;
  955. hints.ai_protocol=IPPROTO_TCP;
  956. ADDRINFOW *result=null; if(!GetAddrInfoW(host, null, &hints, &result))
  957. {
  958. for(ADDRINFOW *r=result; r; r=r->ai_next)switch(r->ai_family)
  959. {
  960. case AF_INET: if(r->ai_addr && r->ai_addrlen<=MEMBER_SIZE(SockAddr, _data))
  961. {
  962. C sockaddr_in &addr=*(sockaddr_in*)r->ai_addr;
  963. if(allow_local_host || addr.sin_addr.s_addr!=IP4_LOCAL_HOST){SockAddr &sa=addresses.New(); sa.v4()=addr; sa.port(port);}
  964. }break;
  965. case AF_INET6: if(r->ai_addr && r->ai_addrlen<=MEMBER_SIZE(SockAddr, _data))
  966. {
  967. C sockaddr_in6 &addr=*(sockaddr_in6*)r->ai_addr;
  968. if(allow_local_host || !IN6_IS_ADDR_LOOPBACK(&addr.sin6_addr)){SockAddr &sa=addresses.New(); sa.v6()=addr; sa.port(port);}
  969. }break;
  970. }
  971. FreeAddrInfoW(result);
  972. }
  973. #else
  974. if(Equal(host, ComputerName, true)) // try using dedicated methods for local host for more precision
  975. {
  976. #if LINUX
  977. ifaddrs *interfaces=null; if(!getifaddrs(&interfaces))
  978. {
  979. for(ifaddrs *r=interfaces; r; r=r->ifa_next)if(r->ifa_addr)switch(r->ifa_addr->sa_family)
  980. {
  981. case AF_INET:
  982. {
  983. C sockaddr_in &addr=*(sockaddr_in*)r->ifa_addr;
  984. if(allow_local_host || addr.sin_addr.s_addr!=IP4_LOCAL_HOST){SockAddr &sa=addresses.New(); sa.v4()=addr; sa.port(port);}
  985. }break;
  986. case AF_INET6:
  987. {
  988. C sockaddr_in6 &addr=*(sockaddr_in6*)r->ifa_addr;
  989. if(allow_local_host || !IN6_IS_ADDR_LOOPBACK(&addr.sin6_addr)){SockAddr &sa=addresses.New(); sa.v6()=addr; sa.port(port);}
  990. }break;
  991. }
  992. freeifaddrs(interfaces);
  993. }
  994. #elif APPLE
  995. #if 0 // don't use as 'NSHost' is private API on the iOS?
  996. if(NSHost *host=[NSHost currentHost])
  997. {
  998. //if(NSString *addr=[host address]) // this may be IP6, [addr release]; don't release as it causes crashes
  999. if(NSArray *addrs=[host addresses])
  1000. {
  1001. REP([addrs count])
  1002. {
  1003. Str addr=[addrs objectAtIndex:i];
  1004. if( addr.length()<=4*3 + 3) // 4*"255" + 3*'.'
  1005. {
  1006. Int dots=0; REPA(addr)if(addr[i]=='.')dots++;
  1007. if( dots==3 && (allow_local_host || addr!="127.0.0.1"))addresses.New().setIP(addr, port);
  1008. }
  1009. }
  1010. //[addrs release]; don't release as it causes crashes
  1011. }
  1012. //[host release]; don't release as it causes crashes
  1013. }
  1014. #else
  1015. ifaddrs *interfaces=null; if(!getifaddrs(&interfaces))
  1016. {
  1017. for(ifaddrs *r=interfaces; r; r=r->ifa_next)if(r->ifa_addr)switch(r->ifa_addr->sa_family)
  1018. {
  1019. case AF_INET:
  1020. {
  1021. C sockaddr_in &addr=*(sockaddr_in*)r->ifa_addr;
  1022. if(allow_local_host || addr.sin_addr.s_addr!=IP4_LOCAL_HOST){SockAddr &sa=addresses.New(); sa.v4()=addr; sa.port(port);}
  1023. }break;
  1024. case AF_INET6:
  1025. {
  1026. C sockaddr_in6 &addr=*(sockaddr_in6*)r->ifa_addr;
  1027. if(allow_local_host || !IN6_IS_ADDR_LOOPBACK(&addr.sin6_addr)){SockAddr &sa=addresses.New(); sa.v6()=addr; sa.port(port);}
  1028. }break;
  1029. }
  1030. freeifaddrs(interfaces);
  1031. }
  1032. #endif
  1033. #elif ANDROID
  1034. #if 0
  1035. Java
  1036. WifiManager wifiManager = (WifiManager)getSystemService(WIFI_SERVICE);
  1037. WifiInfo wifiInfo = wifiManager.getConnectionInfo();
  1038. int ipAddress = wifiInfo.getIpAddress();
  1039. #else
  1040. Socket sock; if(sock.createUdp(true)) // prefer IPv6 because it's better
  1041. {
  1042. ifreq buffer[32];
  1043. ifconf ifc;
  1044. ifc.ifc_len=SIZE(buffer);
  1045. ifc.ifc_req=buffer;
  1046. if(ioctl((SOCKET)sock._s, SIOCGIFCONF, &ifc)!=SOCKET_ERROR)
  1047. {
  1048. FREP(ifc.ifc_len/SIZE(ifreq))
  1049. {
  1050. ifreq &ifr=buffer[i];
  1051. switch(ifr.ifr_addr.sa_family)
  1052. {
  1053. case AF_INET:
  1054. {
  1055. C sockaddr_in &addr=(sockaddr_in&)ifr.ifr_addr;
  1056. if(allow_local_host || addr.sin_addr.s_addr!=IP4_LOCAL_HOST){SockAddr &sa=addresses.New(); sa.v4()=addr; sa.port(port);}
  1057. }break;
  1058. case AF_INET6:
  1059. {
  1060. C sockaddr_in6 &addr=(sockaddr_in6&)ifr.ifr_addr;
  1061. if(allow_local_host || !IN6_IS_ADDR_LOOPBACK(&addr.sin6_addr)){SockAddr &sa=addresses.New(); sa.v6()=addr; sa.port(port);}
  1062. }break;
  1063. }
  1064. }
  1065. }
  1066. }
  1067. #endif
  1068. #endif
  1069. }
  1070. if(!addresses.elms())
  1071. {
  1072. addrinfo hints; Zero(hints);
  1073. hints.ai_family =AF_UNSPEC;
  1074. hints.ai_socktype=SOCK_STREAM;
  1075. hints.ai_protocol=IPPROTO_TCP;
  1076. addrinfo *result=null; if(!getaddrinfo(Str8(host), null, &hints, &result))
  1077. {
  1078. for(addrinfo *r=result; r; r=r->ai_next)switch(r->ai_family)
  1079. {
  1080. case AF_INET: if(r->ai_addr && r->ai_addrlen<=MEMBER_SIZE(SockAddr, _data))
  1081. {
  1082. C sockaddr_in &addr=*(sockaddr_in*)r->ai_addr;
  1083. if(allow_local_host || addr.sin_addr.s_addr!=IP4_LOCAL_HOST){SockAddr &sa=addresses.New(); sa.v4()=addr; sa.port(port);}
  1084. }break;
  1085. case AF_INET6: if(r->ai_addr && r->ai_addrlen<=MEMBER_SIZE(SockAddr, _data))
  1086. {
  1087. C sockaddr_in6 &addr=*(sockaddr_in6*)r->ai_addr;
  1088. if(allow_local_host || !IN6_IS_ADDR_LOOPBACK(&addr.sin6_addr)){SockAddr &sa=addresses.New(); sa.v6()=addr; sa.port(port);}
  1089. }break;
  1090. }
  1091. freeaddrinfo(result);
  1092. }
  1093. }
  1094. #endif
  1095. if(!addresses.elms() && Equal(host, ComputerName, true))addresses.New().setLocalFast(port);
  1096. }
  1097. /******************************************************************************/
  1098. void GetGlobalIP(Bool refresh) {if(!GIPC.valid() || refresh)GIPC.start();}
  1099. Bool HasGlobalIP( ) {return GIPC.valid();}
  1100. Bool ObtainingGlobalIP( ) {return GIPC.busy ;}
  1101. /******************************************************************************/
  1102. static Bool InitSocketEx()
  1103. {
  1104. if(LogInit)LogN("InitSocket");
  1105. #if WINDOWS
  1106. if(WSAStartup(MAKEWORD(2, 2), &WsaData)==NO_ERROR) // init WinSock
  1107. {
  1108. // get mac address
  1109. {
  1110. #if WINDOWS_OLD
  1111. Memt<Byte> addresses; ULONG size=0;
  1112. if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_UNICAST|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER, null, (IP_ADAPTER_ADDRESSES*)addresses.data(), &size)==ERROR_BUFFER_OVERFLOW)
  1113. {
  1114. addresses.setNum(size);
  1115. if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_UNICAST|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER, null, (IP_ADAPTER_ADDRESSES*)addresses.data(), &size)==ERROR_SUCCESS)
  1116. for(IP_ADAPTER_ADDRESSES *adapter=(IP_ADAPTER_ADDRESSES*)addresses.data(); adapter; adapter=adapter->Next)
  1117. {
  1118. /*
  1119. On a Windows Laptop there were following adapters found:
  1120. 1. MIB_IF_TYPE_ETHERNET "Qualcomm Atheros AR8151 PCI-E Gigabit Ethernet Controller (NDIS 6.30)"
  1121. 2. IF_TYPE_IEEE80211 "Microsoft Wi-Fi Direct Virtual Adapter"
  1122. 3. IF_TYPE_IEEE80211 "Intel(R) Centrino(R) Advanced-N 6235"
  1123. */
  1124. if(adapter->IfType==IF_TYPE_IEEE80211
  1125. || adapter->IfType==MIB_IF_TYPE_ETHERNET)
  1126. CopyFast(&Mac, adapter->PhysicalAddress, Min(SIZEU(Mac), (UInt)adapter->PhysicalAddressLength));
  1127. }
  1128. }
  1129. #else
  1130. // TODO: WINDOWS_NEW get MAC address, it should support 'GetAdaptersAddresses', however there are compilation errors as of right now, so try #include <IPHlpApi.h> in the future again
  1131. #endif
  1132. }
  1133. // get host name
  1134. {
  1135. #if 1 // better
  1136. wchar_t host[MAX_COMPUTERNAME_LENGTH+1]; DWORD size=Elms(host);
  1137. if(GetComputerNameW(host, &size))ComputerName=host;
  1138. #else // doesn't work if "hosts" file is modified
  1139. sockaddr_in addr; Zero(addr); // this also clears 'port'
  1140. addr.sin_family =AF_INET;
  1141. addr.sin_addr.s_addr=IP4_LOCAL_HOST;
  1142. //addr.sin_port =htons(port); use zero port, we don't need to set this since 'Zero' is called above
  1143. // 'GetNameInfoW' requires at least Windows XP with SP2
  1144. wchar_t host[NI_MAXHOST], service[NI_MAXSERV]; if(!GetNameInfoW((sockaddr*)&addr, SIZE(addr), host, Elms(host), service, Elms(service), NI_NUMERICSERV))
  1145. { // ok
  1146. ComputerName=host;
  1147. }
  1148. #endif
  1149. }
  1150. return true;
  1151. }
  1152. return false;
  1153. #else
  1154. signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE signal
  1155. Char8 host[NI_MAXHOST]; if(!gethostname(host, Elms(host)))ComputerName=host;
  1156. #if MAC // Mac can append a suffix ".lan"
  1157. if(Ends(ComputerName, ".lan"))ComputerName.removeLast(4);
  1158. #endif
  1159. if(!ComputerName.is())ComputerName="localhost";
  1160. #if LINUX
  1161. Socket sock; if(sock.createUdp(true)) // we need this only for Mac Address, prefer IPv6 because it's better
  1162. {
  1163. ifreq ifr;
  1164. // try ethernet first
  1165. Set(ifr.ifr_name, "eth0"); if(ioctl((SOCKET)sock._s, SIOCGIFHWADDR, &ifr)!=SOCKET_ERROR)CopyFast(&Mac, ifr.ifr_hwaddr.sa_data, Min(SIZEU(Mac), 6));
  1166. if(!Mac) // try wireless lan next
  1167. {
  1168. Set(ifr.ifr_name, "wlan0"); if(ioctl((SOCKET)sock._s, SIOCGIFHWADDR, &ifr)!=SOCKET_ERROR)CopyFast(&Mac, ifr.ifr_hwaddr.sa_data, Min(SIZEU(Mac), 6));
  1169. if(!Mac) // if failed then try all available interfaces
  1170. {
  1171. ifreq buffer[32];
  1172. ifconf ifc;
  1173. ifc.ifc_len=SIZE(buffer);
  1174. ifc.ifc_req=buffer;
  1175. if(ioctl((SOCKET)sock._s, SIOCGIFCONF, &ifc)!=SOCKET_ERROR)
  1176. FREP(ifc.ifc_len/SIZE(ifreq))
  1177. {
  1178. ifreq &ifr=buffer[i];
  1179. if(ioctl((SOCKET)sock._s, SIOCGIFFLAGS, &ifr)!=SOCKET_ERROR)
  1180. if(!(ifr.ifr_flags&IFF_LOOPBACK)) // ignore loopback
  1181. if(ioctl((SOCKET)sock._s, SIOCGIFHWADDR, &ifr)!=SOCKET_ERROR)
  1182. {
  1183. CopyFast(&Mac, ifr.ifr_hwaddr.sa_data, Min(SIZEU(Mac), 6));
  1184. break; // stop on first found
  1185. }
  1186. }
  1187. }
  1188. }
  1189. }
  1190. #elif MAC
  1191. ifaddrs *interfaces=null;
  1192. if(!getifaddrs(&interfaces))
  1193. {
  1194. for(ifaddrs *r=interfaces; r; r=r->ifa_next)
  1195. if(r->ifa_addr)switch(r->ifa_addr->sa_family)
  1196. {
  1197. case AF_LINK:
  1198. {
  1199. sockaddr_dl &addr=*(sockaddr_dl*)r->ifa_addr;
  1200. if(addr.sdl_type==IFT_ETHER)
  1201. {
  1202. CopyFast(&Mac, addr.sdl_data+addr.sdl_nlen, Min(SIZEU(Mac), addr.sdl_alen));
  1203. goto found; // stop on first found
  1204. }
  1205. }break;
  1206. }
  1207. found:
  1208. freeifaddrs(interfaces);
  1209. }
  1210. #elif IOS // since iOS 7 this will always return "02:00:00:00:00:00"
  1211. Socket sock; if(sock.createUdp(true)) // we need this only for Mac Address, prefer IPv6 because it's better
  1212. {
  1213. ifreq buffer[32];
  1214. ifconf ifc;
  1215. ifc.ifc_len=SIZE(buffer);
  1216. ifc.ifc_req=buffer;
  1217. if(ioctl((SOCKET)sock._s, SIOCGIFCONF, &ifc)!=SOCKET_ERROR)
  1218. FREP(ifc.ifc_len/SIZE(ifreq))
  1219. {
  1220. ifreq &ifr=buffer[i];
  1221. switch(ifr.ifr_addr.sa_family)
  1222. {
  1223. case AF_LINK:
  1224. {
  1225. sockaddr_dl &addr=(sockaddr_dl&)ifr.ifr_addr;
  1226. if(addr.sdl_type==IFT_ETHER)
  1227. {
  1228. CopyFast(&Mac, addr.sdl_data+addr.sdl_nlen, Min(SIZEU(Mac), addr.sdl_alen));
  1229. goto found; // stop on first found
  1230. }
  1231. }break;
  1232. }
  1233. }
  1234. found:;
  1235. }
  1236. #elif ANDROID
  1237. if(!Mac)
  1238. if(Jni && ActivityClass)
  1239. if(JClass ContextClass="android/content/Context")
  1240. if(JFieldID WIFI_SERVICEField=Jni->GetStaticFieldID(ContextClass, "WIFI_SERVICE", "Ljava/lang/String;"))
  1241. if(JObject WIFI_SERVICE=Jni->GetStaticObjectField(ContextClass, WIFI_SERVICEField))
  1242. if(JClass WifiManagerClass="android/net/wifi/WifiManager")
  1243. if(JMethodID getSystemService=Jni->GetMethodID(ActivityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"))
  1244. {
  1245. JObject WifiManager=Jni->CallObjectMethod(Activity, getSystemService, WIFI_SERVICE());
  1246. if(Jni->ExceptionCheck())
  1247. {
  1248. #if DEBUG
  1249. Jni->ExceptionDescribe();
  1250. #endif
  1251. WifiManager.clear(); WifiManagerClass.clear(); Jni->ExceptionClear();
  1252. }
  1253. if(WifiManager)
  1254. if(JClass WifiInfoClass="android/net/wifi/WifiInfo")
  1255. if(JMethodID getConnectionInfo=Jni->GetMethodID(WifiManagerClass, "getConnectionInfo", "()Landroid/net/wifi/WifiInfo;"))
  1256. if(JObject WifiInfo=Jni->CallObjectMethod(WifiManager, getConnectionInfo))
  1257. if(JMethodID getMacAddress=Jni->GetMethodID(WifiInfoClass, "getMacAddress", "()Ljava/lang/String;"))
  1258. if(JString MacAddress=Jni->CallObjectMethod(WifiInfo , getMacAddress))
  1259. {
  1260. Memt<Str> mac; Split(mac, MacAddress.str(), ':');
  1261. REP(Min(SIZE(Mac), Elms(mac)))((Byte*)&Mac)[i]=TextInt(S+"0x"+mac[i]);
  1262. }
  1263. }
  1264. #endif
  1265. return true;
  1266. #endif
  1267. }
  1268. /******************************************************************************/
  1269. // SECURE
  1270. /******************************************************************************/
  1271. #if SUPPORT_MBED_TLS
  1272. #include "_/Certificates.h"
  1273. static mbedtls_x509_crt Certificates;
  1274. static mbedtls_entropy_context entropy;
  1275. static mbedtls_ctr_drbg_context ctr_drbg;
  1276. static mbedtls_ssl_config SecureConfig;
  1277. static SyncLock SecureSyncLock;
  1278. #if WINDOWS
  1279. extern "C" int mbedtls_platform_entropy_poll(Ptr data, Byte *output, size_t len, size_t *olen) // manually define this function so we can specify different bodies depending on WINDOWS_OLD/WINDOWS_NEW, without having to create separate libs for mbedTLS library
  1280. {
  1281. *olen=0; Int r=MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
  1282. #if WINDOWS_OLD
  1283. HCRYPTPROV provider; if(CryptAcquireContext(&provider, null, null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  1284. {
  1285. if(CryptGenRandom(provider, (DWORD)len, output)){*olen=len; r=0;}
  1286. CryptReleaseContext(provider, 0);
  1287. }
  1288. #else
  1289. if(OK(BCryptGenRandom(null, output, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG))){*olen=len; r=0;}
  1290. #endif
  1291. return r;
  1292. }
  1293. #endif
  1294. static int EntropyFunc(Ptr ctx, Byte *output, size_t len) {SyncLocker sl(SecureSyncLock); return mbedtls_entropy_func (ctx, output, len);}
  1295. static int RandomFunc(Ptr ctx, Byte *output, size_t len) {SyncLocker sl(SecureSyncLock); return mbedtls_ctr_drbg_random(ctx, output, len);}
  1296. #endif
  1297. /******************************************************************************/
  1298. static void DebugCallback(Ptr ctx, int level, CChar8 *file, int line, CChar8 *str)
  1299. {
  1300. Log(str);
  1301. }
  1302. static void ShutSecure()
  1303. {
  1304. #if SUPPORT_MBED_TLS
  1305. SyncLocker sl(SecureSyncLock);
  1306. mbedtls_ssl_config_free(&SecureConfig);
  1307. mbedtls_ctr_drbg_free (&ctr_drbg);
  1308. mbedtls_entropy_free (&entropy);
  1309. mbedtls_x509_crt_free (&Certificates);
  1310. #endif
  1311. }
  1312. static void InitSecure()
  1313. {
  1314. #if SUPPORT_MBED_TLS
  1315. #define TEST_LOAD_SPEED (DEBUG && 0)
  1316. #if TEST_LOAD_SPEED
  1317. Dbl t=Time.curTime();
  1318. #endif
  1319. if(!SecureConfig.f_dbg)
  1320. {
  1321. SyncLocker sl(SecureSyncLock); if(!SecureConfig.f_dbg)
  1322. {
  1323. {
  1324. File cmpr, src; cmpr.readMem(CertificatesData, SIZE(CertificatesData));
  1325. DYNAMIC_ASSERT(DecompressRaw(cmpr, src, COMPRESS_LZ4, cmpr.size(), CertificatesSize, true), "Can't decompress Certificates");
  1326. DYNAMIC_ASSERT(src._type==FILE_MEM, "Src should be FILE_MEM");
  1327. mbedtls_x509_crt *cert=&Certificates;
  1328. mbedtls_x509_crt_init(cert);
  1329. for(src.pos(0); !src.end(); )
  1330. {
  1331. Int size=src.getUShort(); DYNAMIC_ASSERT(size>0 && size<=src.left(), "Invalid Certificate size");
  1332. DYNAMIC_ASSERT(mbedtls_x509_crt_parse_der(cert, (Byte*)src.memFast(), size)==0, "Can't load Certificate");
  1333. if(cert->next)cert=cert->next; // advance to the last available to avoid iteration inside 'mbedtls_x509_crt_parse_der'
  1334. src.skip(size);
  1335. }
  1336. //Int n=0; for(mbedtls_x509_crt *cert=&Certificates; cert; cert=cert->next)n++; Exit(n); display how many certificates were loaded
  1337. }
  1338. #if DEBUG && defined MBEDTLS_DEBUG_C
  1339. mbedtls_debug_set_threshold(4); // enable reporting all messages, use 1 for errors only
  1340. #endif
  1341. mbedtls_ssl_config_init(&SecureConfig);
  1342. mbedtls_ctr_drbg_init(&ctr_drbg);
  1343. mbedtls_entropy_init(&entropy);
  1344. UID custom; custom.randomize(); // using random values improves entropy
  1345. DYNAMIC_ASSERT(!mbedtls_ctr_drbg_seed(&ctr_drbg, EntropyFunc, &entropy, custom.b, SIZE(custom)), "mbedtls_ctr_drbg_seed");
  1346. DYNAMIC_ASSERT(!mbedtls_ssl_config_defaults(&SecureConfig, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT), "mbedtls_ssl_config_defaults");
  1347. mbedtls_ssl_conf_read_timeout(&SecureConfig, DOWNLOAD_WAIT_TIME); ASSERT(DOWNLOAD_WAIT_TIME!=0); // for 'mbedtls_ssl_conf_read_timeout' 0 is actually unlimited and not instant
  1348. mbedtls_ssl_conf_authmode(&SecureConfig, MBEDTLS_SSL_VERIFY_OPTIONAL); // make optional here and just check 'mbedtls_ssl_get_verify_result' manually so we can decide what to do later
  1349. mbedtls_ssl_conf_ca_chain(&SecureConfig, &Certificates, null);
  1350. mbedtls_ssl_conf_rng(&SecureConfig, RandomFunc, &ctr_drbg);
  1351. // !! always set this and as the last thing, because this is used for checking if lib was initialized !!
  1352. mbedtls_ssl_conf_dbg(&SecureConfig, DebugCallback, null);
  1353. DEBUG_ASSERT(SecureConfig.f_dbg, "SecureConfig.f_dbg==null"); // make sure that 'SecureConfig.f_dbg' was set which is used for detecting if lib was initialized
  1354. }
  1355. }
  1356. #if TEST_LOAD_SPEED
  1357. Exit(Flt(Time.curTime()-t)); // loads very fast, in 0.001s
  1358. #endif
  1359. #endif
  1360. }
  1361. #if UPDATE_CERTIFICATES
  1362. static void UpdateCertificates()
  1363. {
  1364. #if SUPPORT_MBED_TLS
  1365. Mems<Byte> data;
  1366. {
  1367. #if 0 // from file
  1368. File f; f.read(SystemPath(SP_DESKTOP).tailSlash(true)+"cacert.pem"); f.copyToAndDiscard(data); f.del();
  1369. #else // from internet
  1370. Download down; down.create("https://curl.haxx.se/ca/cacert.pem"); down.wait(); // this is from CURL based on Mozilla, some alternative resources:
  1371. // https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt
  1372. // https://chromium.googlesource.com/external/github.com/dart-lang/root_certificates/+/master
  1373. // https://chromium.googlesource.com/external/github.com/dart-lang/root_certificates/+/master/certdata.pem
  1374. DYNAMIC_ASSERT(down.state()==DWNL_DONE && down.done()>0, "Can't download certificates");
  1375. data.setNum(down.size()).copyFrom((Byte*)down.data());
  1376. #endif
  1377. }
  1378. mbedtls_x509_crt certs; mbedtls_x509_crt_init(&certs);
  1379. data.add(0); // add null character which is required by 'mbedtls_x509_crt_parse'
  1380. Int error=mbedtls_x509_crt_parse(&certs, data.data(), data.elms());
  1381. DYNAMIC_ASSERT(error==0, S+"Cert failed to load:"+error);
  1382. Memc<Memc<Byte>> cert_data;
  1383. for(mbedtls_x509_crt *cert=&certs; cert; cert=cert->next)
  1384. {
  1385. Int size=Int(cert->raw.len); DYNAMIC_ASSERT(size>0 && size<=USHORT_MAX, S+"Invalid CERT size:"+size);
  1386. cert_data.New().setNum(size).copyFrom(cert->raw.p);
  1387. }
  1388. File f; f.writeMem();
  1389. FREPA(cert_data)
  1390. {
  1391. f.putUShort(cert_data[i].elms());
  1392. f.put (cert_data[i].data(), cert_data[i].elms());
  1393. }
  1394. f.pos(0);
  1395. File cmpr; DYNAMIC_ASSERT(CompressRaw(f, cmpr.writeMem(), COMPRESS_LZ4, 9), "failed to compress");
  1396. {
  1397. Str dest=GetPath(__FILE__).tailSlash(true)+"_/Certificates.h";
  1398. FileText ft;
  1399. ft.write(dest);
  1400. ft.putLine(S+"static const Int CertificatesSize="+f.size()+';');
  1401. ft.putLine( "static const Byte CertificatesData[]=");
  1402. ft.putLine("{");
  1403. for(cmpr.pos(0); !cmpr.end(); ){if(cmpr.pos()!=0){ft.putText(","); if(!(cmpr.pos()%64))ft.endLine();} ft.putText(cmpr.getByte());}
  1404. ft.endLine();
  1405. ft.putLine("};");
  1406. Exit(S+"Certificates updated OK: "+ft.flushOK()+"\nCompressed Size: "+TextInt(cmpr.size(), -1, 3));
  1407. }
  1408. #endif
  1409. }
  1410. #endif
  1411. /******************************************************************************/
  1412. void SecureSocket::del()
  1413. {
  1414. unsecure(); // 'unsecure' first so connection can be notified of closing
  1415. super::del();
  1416. }
  1417. void SecureSocket::unsecure()
  1418. {
  1419. #if SUPPORT_MBED_TLS
  1420. if(_secure)
  1421. {
  1422. mbedtls_ssl_close_notify(_secure);
  1423. mbedtls_ssl_free(_secure);
  1424. Free(_secure);
  1425. }
  1426. #endif
  1427. }
  1428. Bool SecureSocket::secure(CChar8 *host)
  1429. {
  1430. unsecure();
  1431. InitSecure(); // first make sure that lib was initialized
  1432. #if SUPPORT_MBED_TLS
  1433. Alloc(_secure);
  1434. mbedtls_ssl_init (_secure);
  1435. return !mbedtls_ssl_setup (_secure, &SecureConfig)
  1436. && !mbedtls_ssl_set_hostname(_secure, _GetStart(host));
  1437. #endif
  1438. return false;
  1439. }
  1440. #if SUPPORT_MBED_TLS
  1441. static int SendFunc(Ptr ctx, C Byte *buf, size_t len)
  1442. {
  1443. SecureSocket &s=*(SecureSocket*)ctx; Int r=s.Socket::send(buf, (Int)len); if(r<0)return Socket::WouldBlock() ? MBEDTLS_ERR_SSL_WANT_WRITE : MBEDTLS_ERR_NET_SEND_FAILED;
  1444. return r;
  1445. }
  1446. static int ReceiveFunc(Ptr ctx, Byte *buf, size_t len)
  1447. {
  1448. SecureSocket &s=*(SecureSocket*)ctx; Int r=s.Socket::receive(buf, (Int)len); if(r<0)return Socket::WouldBlock() ? MBEDTLS_ERR_SSL_WANT_READ : MBEDTLS_ERR_NET_RECV_FAILED;
  1449. return r;
  1450. }
  1451. static int ReceiveFuncTimeout(Ptr ctx, Byte *buf, size_t len, uint32_t timeout)
  1452. {
  1453. SecureSocket &s=*(SecureSocket*)ctx; if(!s.wait(timeout ? Min(timeout, INT_MAX) : INT_MAX))return MBEDTLS_ERR_SSL_TIMEOUT; // Min to INT_MAX because 'wait' expected Int, if 'timeout' is zero, then use INT_MAX because MBED TLS treats this as unlimited time
  1454. return ReceiveFunc(ctx, buf, len);
  1455. }
  1456. static inline Int MbedTlsToResult(Int r)
  1457. {
  1458. switch(r)
  1459. {
  1460. case MBEDTLS_ERR_SSL_WANT_READ :
  1461. case MBEDTLS_ERR_SSL_TIMEOUT : return SecureSocket::NEED_WAIT;
  1462. case MBEDTLS_ERR_SSL_WANT_WRITE: return SecureSocket::NEED_FLUSH;
  1463. default: return (r>=-1) ? r : SecureSocket::ERROR;
  1464. }
  1465. }
  1466. #endif
  1467. void SecureSocket::setDefaultFunc()
  1468. {
  1469. #if SUPPORT_MBED_TLS
  1470. mbedtls_ssl_set_bio(_secure, this, SendFunc, ReceiveFunc, ReceiveFuncTimeout);
  1471. #endif
  1472. }
  1473. Int SecureSocket::send(CPtr data, Int size)
  1474. {
  1475. #if SUPPORT_MBED_TLS
  1476. if(_secure)return MbedTlsToResult(mbedtls_ssl_write(_secure, (Byte*)data, size));
  1477. #endif
  1478. return super::send(data, size);
  1479. }
  1480. Int SecureSocket::receive(Ptr data, Int size)
  1481. {
  1482. #if SUPPORT_MBED_TLS
  1483. if(_secure)return MbedTlsToResult(mbedtls_ssl_read(_secure, (Byte*)data, size));
  1484. #endif
  1485. return super::receive(data, size);
  1486. }
  1487. SecureSocket::RESULT SecureSocket::handshake()
  1488. {
  1489. if(!_secure)return OK;
  1490. #if SUPPORT_MBED_TLS
  1491. switch(mbedtls_ssl_handshake(_secure))
  1492. {
  1493. case 0: return mbedtls_ssl_get_verify_result(_secure) ? BAD_CERT : OK;
  1494. case MBEDTLS_ERR_SSL_WANT_READ :
  1495. case MBEDTLS_ERR_SSL_TIMEOUT : return NEED_WAIT;
  1496. case MBEDTLS_ERR_SSL_WANT_WRITE: return NEED_FLUSH;
  1497. }
  1498. #endif
  1499. return ERROR;
  1500. }
  1501. /******************************************************************************/
  1502. Bool InitSocket()
  1503. {
  1504. if(InitSocketEx())
  1505. {
  1506. #if UPDATE_CERTIFICATES
  1507. #pragma message("!! Warning: Use this only once in many days !!")
  1508. UpdateCertificates();
  1509. #endif
  1510. return true;
  1511. }
  1512. return false;
  1513. }
  1514. void ShutSocket()
  1515. {
  1516. GIPC.del();
  1517. #if WINDOWS
  1518. WSACleanup();
  1519. #endif
  1520. ShutSecure();
  1521. }
  1522. /******************************************************************************/
  1523. }
  1524. /******************************************************************************/