socket.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. /*
  2. socket.c -- Sockets layer
  3. Copyright (c) All Rights Reserved. See details at the end of the file.
  4. */
  5. /********************************** Includes **********************************/
  6. #include "goahead.h"
  7. /************************************ Locals **********************************/
  8. PUBLIC WebsSocket **socketList; /* List of open sockets */
  9. PUBLIC int socketMax; /* Maximum size of socket */
  10. PUBLIC Socket socketHighestFd = -1; /* Highest socket fd opened */
  11. PUBLIC int socketOpenCount = 0; /* Number of task using sockets */
  12. static int hasIPv6; /* System supports IPv6 */
  13. /***************************** Forward Declarations ***************************/
  14. static int ipv6(cchar *ip);
  15. static void socketAccept(WebsSocket *sp);
  16. static void socketDoEvent(WebsSocket *sp);
  17. /*********************************** Code *************************************/
  18. PUBLIC int socketOpen(void)
  19. {
  20. Socket fd;
  21. if (++socketOpenCount > 1) {
  22. return 0;
  23. }
  24. //#if ME_WIN_LIKE
  25. //{
  26. // WSADATA wsaData;
  27. // if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
  28. // return -1;
  29. // }
  30. // if (wsaData.wVersion != MAKEWORD(1,1)) {
  31. // WSACleanup();
  32. // return -1;
  33. // }
  34. //}
  35. //#endif
  36. socketList = NULL;
  37. socketMax = 0;
  38. socketHighestFd = -1;
  39. error("---> socketOpen\n");
  40. if ((fd = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
  41. closesocket(fd);
  42. } else {
  43. trace(1, "This system does not have IPv6 support");
  44. }
  45. hasIPv6 = 0;
  46. return 0;
  47. }
  48. PUBLIC void socketClose(void)
  49. {
  50. int i;
  51. if (--socketOpenCount <= 0) {
  52. for (i = socketMax; i >= 0; i--) {
  53. if (socketList && socketList[i]) {
  54. socketCloseConnection(i);
  55. }
  56. }
  57. socketOpenCount = 0;
  58. }
  59. }
  60. PUBLIC bool socketHasDualNetworkStack(void)
  61. {
  62. bool dual;
  63. #if defined(ME_COMPILER_HAS_SINGLE_STACK) || VXWORKS
  64. error("---> ME_COMPILER_HAS_SINGLE_STACK\n");
  65. dual = 0;
  66. #else
  67. error("---> ndef SINGLE_STACK\n");
  68. dual = hasIPv6;
  69. #endif
  70. return dual;
  71. }
  72. PUBLIC bool socketHasIPv6(void)
  73. {
  74. return hasIPv6;
  75. }
  76. PUBLIC int socketListen(cchar *ip, int port, SocketAccept accept, int flags)
  77. {
  78. WebsSocket *sp;
  79. struct sockaddr_storage addr;
  80. Socklen addrlen;
  81. cchar *sip;
  82. int family, protocol, sid, enable;
  83. if (port > SOCKET_PORT_MAX) {
  84. return -1;
  85. }
  86. if ((sid = socketAlloc(ip, port, accept, flags)) < 0) {
  87. return -1;
  88. }
  89. sp = socketList[sid];
  90. assert(sp);
  91. /*
  92. Change null IP address to be an IPv6 endpoint if the system is dual-stack. That way we can listen on
  93. both IPv4 and IPv6
  94. */
  95. sip = ((ip == 0 || *ip == '\0') && socketHasDualNetworkStack()) ? "::" : ip;
  96. /*
  97. Bind to the socket endpoint and the call listen() to start listening
  98. */
  99. if (socketInfo(sip, port, &family, &protocol, &addr, &addrlen) < 0) {
  100. return -1;
  101. }
  102. if ((sp->sock = socket(family, SOCK_STREAM, protocol)) == SOCKET_ERROR) {
  103. socketFree(sid);
  104. return -1;
  105. }
  106. socketHighestFd = max(socketHighestFd, sp->sock);
  107. #if ME_COMPILER_HAS_FCNTL
  108. fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
  109. #endif
  110. enable = 1;
  111. #if ME_UNIX_LIKE || VXWORKS
  112. if (setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char*) &enable, sizeof(enable)) != 0) {
  113. error("Cannot set reuseaddr, errno %d", errno);
  114. }
  115. #if defined(SO_REUSEPORT) && KEEP
  116. /*
  117. This permits multiple servers listening on the same endpoint
  118. */
  119. if (setsockopt(sp->sock, SOL_SOCKET, SO_REUSEPORT, (char*) &enable, sizeof(enable)) != 0) {
  120. error("Cannot set reuseport, errno %d", errno);
  121. }
  122. #endif
  123. #elif ME_WIN_LIKE && defined(SO_EXCLUSIVEADDRUSE)
  124. if (setsockopt(sp->sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*) &enable, sizeof(enable)) != 0) {
  125. error("Cannot set exclusiveaddruse, errno %d", WSAGetLastError());
  126. }
  127. #endif
  128. #if defined(IPV6_V6ONLY)
  129. error("---> IPV6_V6ONLY\n");
  130. /*
  131. By default, most stacks listen on both IPv6 and IPv4 if ip == 0, except windows which inverts this.
  132. So we explicitly control.
  133. */
  134. if (hasIPv6) {
  135. if (ip == 0) {
  136. enable = 0;
  137. setsockopt(sp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &enable, sizeof(enable));
  138. } else if (ipv6(ip)) {
  139. enable = 1;
  140. setsockopt(sp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &enable, sizeof(enable));
  141. }
  142. }
  143. #endif
  144. if (bind(sp->sock, (struct sockaddr*) &addr, addrlen) == SOCKET_ERROR) {
  145. error("Cannot bind to address %s:%d, errno %d", ip ? ip : "*", port, errno);
  146. socketFree(sid);
  147. return -1;
  148. }
  149. if (listen(sp->sock, SOMAXCONN) < 0) {
  150. socketFree(sid);
  151. return -1;
  152. }
  153. sp->flags |= SOCKET_LISTENING | SOCKET_NODELAY;
  154. sp->handlerMask |= SOCKET_READABLE;
  155. socketSetBlock(sid, (flags & SOCKET_BLOCK));
  156. if (sp->flags & SOCKET_NODELAY) {
  157. socketSetNoDelay(sid, 1);
  158. }
  159. return sid;
  160. }
  161. #if KEEP
  162. PUBLIC int socketConnect(char *ip, int port, int flags)
  163. {
  164. WebsSocket *sp;
  165. struct sockaddr_storage addr;
  166. socklen_t addrlen;
  167. int family, protocol, sid, rc;
  168. if (port > SOCKET_PORT_MAX) {
  169. return -1;
  170. }
  171. if ((sid = socketAlloc(ip, port, NULL, flags)) < 0) {
  172. return -1;
  173. }
  174. sp = socketList[sid];
  175. assert(sp);
  176. if (socketInfo(ip, port, &family, &protocol, &addr, &addrlen) < 0) {
  177. return -1;
  178. }
  179. if ((sp->sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
  180. socketFree(sid);
  181. return -1;
  182. }
  183. socketHighestFd = max(socketHighestFd, sp->sock);
  184. #if ME_COMPILER_HAS_FCNTL
  185. fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
  186. #endif
  187. /*
  188. Connect to the remote server in blocking mode, then go into non-blocking mode if desired.
  189. */
  190. if (!(sp->flags & SOCKET_BLOCK)) {
  191. #if ME_WIN_LIKE
  192. /*
  193. Set to non-blocking for an async connect
  194. */
  195. int flag = 1;
  196. if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) {
  197. socketFree(sid);
  198. return -1;
  199. }
  200. sp->flags |= SOCKET_ASYNC;
  201. #else
  202. socketSetBlock(sid, 1);
  203. #endif
  204. }
  205. if ((rc = connect(sp->sock, (struct sockaddr*) &addr, sizeof(addr))) < 0 &&
  206. (rc = tryAlternateConnect(sp->sock, (struct sockaddr*) &addr)) < 0) {
  207. #if ME_WIN_LIKE
  208. if (socketGetError(sid) != EWOULDBLOCK) {
  209. socketFree(sid);
  210. return -1;
  211. }
  212. #else
  213. socketFree(sid);
  214. return -1;
  215. #endif
  216. }
  217. socketSetBlock(sid, (flags & SOCKET_BLOCK));
  218. return sid;
  219. }
  220. /*
  221. If the connection failed, swap the first two bytes in the sockaddr structure. This is a kludge due to a change in
  222. VxWorks between versions 5.3 and 5.4, but we want the product to run on either.
  223. */
  224. static int tryAlternateConnect(int sock, struct sockaddr *sockaddr)
  225. {
  226. #if VXWORKS || TIDSP
  227. char *ptr;
  228. ptr = (char*) sockaddr;
  229. *ptr = *(ptr+1);
  230. *(ptr+1) = 0;
  231. return connect(sock, sockaddr, sizeof(struct sockaddr));
  232. #else
  233. return -1;
  234. #endif
  235. }
  236. #endif
  237. PUBLIC void socketCloseConnection(int sid)
  238. {
  239. WebsSocket *sp;
  240. if ((sp = socketPtr(sid)) == NULL) {
  241. return;
  242. }
  243. socketFree(sid);
  244. }
  245. /*
  246. Accept a connection. Called as a callback on incoming connection.
  247. */
  248. static void socketAccept(WebsSocket *sp)
  249. {
  250. struct sockaddr_storage addrStorage;
  251. struct sockaddr *addr;
  252. WebsSocket *nsp;
  253. Socket newSock;
  254. size_t len;
  255. char ipbuf[1024];
  256. int port, nid;
  257. assert(sp);
  258. /*
  259. Accept the connection and prevent inheriting by children (F_SETFD)
  260. */
  261. len = sizeof(addrStorage);
  262. addr = (struct sockaddr*) &addrStorage;
  263. if ((newSock = accept(sp->sock, addr, (Socklen*) &len)) == SOCKET_ERROR) {
  264. return;
  265. }
  266. #if ME_COMPILER_HAS_FCNTL
  267. fcntl(newSock, F_SETFD, FD_CLOEXEC);
  268. #endif
  269. socketHighestFd = max(socketHighestFd, newSock);
  270. /*
  271. Create a socket structure and insert into the socket list
  272. */
  273. if ((nid = socketAlloc(sp->ip, sp->port, sp->accept, sp->flags)) < 0) {
  274. return;
  275. }
  276. if ((nsp = socketList[nid]) == 0) {
  277. return;
  278. }
  279. assert(nsp);
  280. nsp->sock = newSock;
  281. nsp->flags &= ~SOCKET_LISTENING;
  282. socketSetBlock(nid, (nsp->flags & SOCKET_BLOCK));
  283. if (nsp->flags & SOCKET_NODELAY) {
  284. socketSetNoDelay(nid, 1);
  285. }
  286. /*
  287. Call the user accept callback. The user must call socketCreateHandler to register for further events of interest.
  288. */
  289. if (sp->accept != NULL) {
  290. /* Get the remote client address */
  291. socketAddress(addr, (int) len, ipbuf, sizeof(ipbuf), &port);
  292. if ((sp->accept)(nid, ipbuf, port, sp->sid) < 0) {
  293. socketFree(nid);
  294. }
  295. }
  296. }
  297. PUBLIC void socketRegisterInterest(int sid, int handlerMask)
  298. {
  299. WebsSocket *sp;
  300. assert(socketPtr(sid));
  301. sp = socketPtr(sid);
  302. sp->handlerMask = handlerMask;
  303. if (sp->flags & SOCKET_BUFFERED_READ) {
  304. sp->handlerMask |= SOCKET_READABLE;
  305. }
  306. if (sp->flags & SOCKET_BUFFERED_WRITE) {
  307. sp->handlerMask |= SOCKET_WRITABLE;
  308. }
  309. }
  310. /*
  311. Wait until an event occurs on a socket. Return zero on success, -1 on failure.
  312. */
  313. PUBLIC int socketWaitForEvent(WebsSocket *sp, int handlerMask)
  314. {
  315. int mask;
  316. assert(sp);
  317. mask = sp->handlerMask;
  318. sp->handlerMask |= handlerMask;
  319. while (socketSelect(sp->sid, 1000)) {
  320. if (sp->currentEvents & (handlerMask | SOCKET_EXCEPTION)) {
  321. break;
  322. }
  323. }
  324. sp->handlerMask = mask;
  325. if (sp->currentEvents & SOCKET_EXCEPTION) {
  326. return -1;
  327. } else if (sp->currentEvents & handlerMask) {
  328. return 0;
  329. }
  330. return 0;
  331. }
  332. PUBLIC void socketHiddenData(WebsSocket *sp, ssize len, int dir)
  333. {
  334. if (len > 0) {
  335. sp->flags |= (dir == SOCKET_READABLE) ? SOCKET_BUFFERED_READ : SOCKET_BUFFERED_WRITE;
  336. if (sp->handler) {
  337. socketReservice(sp->sid);
  338. }
  339. } else {
  340. sp->flags &= ~((dir == SOCKET_READABLE) ? SOCKET_BUFFERED_READ : SOCKET_BUFFERED_WRITE);
  341. }
  342. }
  343. /*
  344. Wait for a handle to become readable or writable and return a number of noticed events. Timeout is in milliseconds.
  345. */
  346. #if ME_WIN_LIKE
  347. PUBLIC int socketSelect(int sid, int timeout)
  348. {
  349. struct timeval tv;
  350. WebsSocket *sp;
  351. fd_set readFds, writeFds, exceptFds;
  352. int nEvents;
  353. int all, socketHighestFd; /* Highest socket fd opened */
  354. FD_ZERO(&readFds);
  355. FD_ZERO(&writeFds);
  356. FD_ZERO(&exceptFds);
  357. socketHighestFd = -1;
  358. tv.tv_sec = (long) (timeout / 1000);
  359. tv.tv_usec = (DWORD) (timeout % 1000) * 1000;
  360. /*
  361. Set the select event masks for events to watch
  362. */
  363. all = nEvents = 0;
  364. if (sid < 0) {
  365. all++;
  366. sid = 0;
  367. }
  368. for (; sid < socketMax; sid++) {
  369. if ((sp = socketList[sid]) == NULL) {
  370. continue;
  371. }
  372. assert(sp);
  373. /*
  374. Set the appropriate bit in the ready masks for the sp->sock.
  375. */
  376. if (sp->handlerMask & SOCKET_READABLE) {
  377. FD_SET(sp->sock, &readFds);
  378. nEvents++;
  379. }
  380. if (sp->handlerMask & SOCKET_WRITABLE) {
  381. FD_SET(sp->sock, &writeFds);
  382. nEvents++;
  383. }
  384. if (sp->handlerMask & SOCKET_EXCEPTION) {
  385. FD_SET(sp->sock, &exceptFds);
  386. nEvents++;
  387. }
  388. if (sp->flags & SOCKET_RESERVICE) {
  389. tv.tv_sec = 0;
  390. tv.tv_usec = 0;
  391. }
  392. if (! all) {
  393. break;
  394. }
  395. }
  396. /*
  397. Windows select() fails if no descriptors are set, instead of just sleeping like other, nice select() calls.
  398. So, if WINDOWS, sleep.
  399. */
  400. if (nEvents == 0) {
  401. Sleep((DWORD) timeout);
  402. return 0;
  403. }
  404. /*
  405. Wait for the event or a timeout
  406. */
  407. nEvents = select(socketHighestFd + 1, &readFds, &writeFds, &exceptFds, &tv);
  408. if (all) {
  409. sid = 0;
  410. }
  411. for (; sid < socketMax; sid++) {
  412. if ((sp = socketList[sid]) == NULL) {
  413. continue;
  414. }
  415. if (sp->flags & SOCKET_RESERVICE) {
  416. if (sp->handlerMask & SOCKET_READABLE) {
  417. sp->currentEvents |= SOCKET_READABLE;
  418. }
  419. if (sp->handlerMask & SOCKET_WRITABLE) {
  420. sp->currentEvents |= SOCKET_WRITABLE;
  421. }
  422. sp->flags &= ~SOCKET_RESERVICE;
  423. nEvents++;
  424. }
  425. if (FD_ISSET(sp->sock, &readFds)) {
  426. sp->currentEvents |= SOCKET_READABLE;
  427. }
  428. if (FD_ISSET(sp->sock, &writeFds)) {
  429. sp->currentEvents |= SOCKET_WRITABLE;
  430. }
  431. if (FD_ISSET(sp->sock, &exceptFds)) {
  432. sp->currentEvents |= SOCKET_EXCEPTION;
  433. }
  434. if (! all) {
  435. break;
  436. }
  437. }
  438. return nEvents;
  439. }
  440. #else /* !ME_WIN_LIKE */
  441. PUBLIC int socketSelect(int sid, int timeout)
  442. {
  443. WebsSocket *sp;
  444. struct timeval tv;
  445. fd_mask *readFds, *writeFds, *exceptFds;
  446. int all, len, nwords, index, bit, nEvents;
  447. /*
  448. Allocate and zero the select masks
  449. */
  450. nwords = (socketHighestFd + NFDBITS) / NFDBITS;
  451. len = nwords * sizeof(fd_mask);
  452. readFds = walloc(len);
  453. memset(readFds, 0, len);
  454. writeFds = walloc(len);
  455. memset(writeFds, 0, len);
  456. exceptFds = walloc(len);
  457. memset(exceptFds, 0, len);
  458. tv.tv_sec = timeout / 1000;
  459. tv.tv_usec = (timeout % 1000) * 1000;
  460. /*
  461. Set the select event masks for events to watch
  462. */
  463. all = nEvents = 0;
  464. if (sid < 0) {
  465. all++;
  466. sid = 0;
  467. }
  468. for (; sid < socketMax; sid++) {
  469. if ((sp = socketList[sid]) == NULL) {
  470. if (all == 0) {
  471. break;
  472. } else {
  473. continue;
  474. }
  475. }
  476. assert(sp);
  477. /*
  478. Initialize the ready masks and compute the mask offsets.
  479. */
  480. index = sp->sock / (NBBY * sizeof(fd_mask));
  481. bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
  482. /*
  483. Set the appropriate bit in the ready masks for the sp->sock.
  484. */
  485. if (sp->handlerMask & SOCKET_READABLE) {
  486. readFds[index] |= bit;
  487. }
  488. if (sp->handlerMask & SOCKET_WRITABLE) {
  489. writeFds[index] |= bit;
  490. }
  491. if (sp->handlerMask & SOCKET_EXCEPTION) {
  492. exceptFds[index] |= bit;
  493. }
  494. if (sp->flags & SOCKET_RESERVICE) {
  495. tv.tv_sec = 0;
  496. tv.tv_usec = 0;
  497. }
  498. if (! all) {
  499. break;
  500. }
  501. }
  502. /*
  503. Wait for the event or a timeout
  504. */
  505. nEvents = select(socketHighestFd + 1, (fd_set *) readFds, (fd_set *) writeFds, (fd_set *) exceptFds, &tv);
  506. if (all) {
  507. sid = 0;
  508. }
  509. for (; sid < socketMax; sid++) {
  510. if ((sp = socketList[sid]) == NULL) {
  511. if (all == 0) {
  512. break;
  513. } else {
  514. continue;
  515. }
  516. }
  517. index = sp->sock / (NBBY * sizeof(fd_mask));
  518. bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
  519. if (sp->flags & SOCKET_RESERVICE) {
  520. if (sp->handlerMask & SOCKET_READABLE) {
  521. sp->currentEvents |= SOCKET_READABLE;
  522. }
  523. if (sp->handlerMask & SOCKET_WRITABLE) {
  524. sp->currentEvents |= SOCKET_WRITABLE;
  525. }
  526. sp->flags &= ~SOCKET_RESERVICE;
  527. nEvents++;
  528. }
  529. if (readFds[index] & bit) {
  530. sp->currentEvents |= SOCKET_READABLE;
  531. }
  532. if (writeFds[index] & bit) {
  533. sp->currentEvents |= SOCKET_WRITABLE;
  534. }
  535. if (exceptFds[index] & bit) {
  536. sp->currentEvents |= SOCKET_EXCEPTION;
  537. }
  538. if (! all) {
  539. break;
  540. }
  541. }
  542. wfree(readFds);
  543. wfree(writeFds);
  544. wfree(exceptFds);
  545. return nEvents;
  546. }
  547. #endif /* WINDOWS || CE */
  548. PUBLIC void socketProcess(void)
  549. {
  550. WebsSocket *sp;
  551. int sid;
  552. for (sid = 0; sid < socketMax; sid++) {
  553. if ((sp = socketList[sid]) != NULL) {
  554. if (sp->currentEvents & sp->handlerMask) {
  555. socketDoEvent(sp);
  556. }
  557. }
  558. }
  559. }
  560. static void socketDoEvent(WebsSocket *sp)
  561. {
  562. int sid;
  563. assert(sp);
  564. sid = sp->sid;
  565. if (sp->currentEvents & SOCKET_READABLE) {
  566. if (sp->flags & SOCKET_LISTENING) {
  567. socketAccept(sp);
  568. sp->currentEvents = 0;
  569. return;
  570. }
  571. }
  572. /*
  573. Now invoke the users socket handler. NOTE: the handler may delete the
  574. socket, so we must be very careful after calling the handler.
  575. */
  576. if (sp->handler && (sp->handlerMask & sp->currentEvents)) {
  577. (sp->handler)(sid, sp->handlerMask & sp->currentEvents, sp->handler_data);
  578. /*
  579. Make sure socket pointer is still valid, then reset the currentEvents.
  580. */
  581. if (socketList && sid < socketMax && socketList[sid] == sp) {
  582. sp->currentEvents = 0;
  583. }
  584. }
  585. }
  586. /*
  587. Set the socket blocking mode. Return the previous mode.
  588. */
  589. PUBLIC int socketSetBlock(int sid, int on)
  590. {
  591. WebsSocket *sp;
  592. int oldBlock;
  593. if ((sp = socketPtr(sid)) == NULL) {
  594. assert(0);
  595. return 0;
  596. }
  597. oldBlock = (sp->flags & SOCKET_BLOCK);
  598. sp->flags &= ~(SOCKET_BLOCK);
  599. if (on) {
  600. sp->flags |= SOCKET_BLOCK;
  601. }
  602. /*
  603. Put the socket into block / non-blocking mode
  604. */
  605. if (sp->flags & SOCKET_BLOCK) {
  606. #if ME_WIN_LIKE
  607. ulong flag = !on;
  608. ioctlsocket(sp->sock, FIONBIO, &flag);
  609. #elif ECOS
  610. int off;
  611. off = 0;
  612. ioctl(sp->sock, FIONBIO, &off);
  613. #elif VXWORKS
  614. int iflag = !on;
  615. ioctl(sp->sock, FIONBIO, (int) &iflag);
  616. #elif TIDSP
  617. setsockopt((SOCKET)sp->sock, SOL_SOCKET, SO_BLOCKING, &on, sizeof(on));
  618. #else
  619. fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) & ~O_NONBLOCK);
  620. #endif
  621. } else {
  622. #if ME_WIN_LIKE
  623. ulong flag = !on;
  624. int rc = ioctlsocket(sp->sock, FIONBIO, &flag);
  625. rc = rc;
  626. #elif ECOS
  627. int on = 1;
  628. ioctl(sp->sock, FIONBIO, &on);
  629. #elif VXWORKS
  630. int iflag = !on;
  631. ioctl(sp->sock, FIONBIO, (int) &iflag);
  632. #elif TIDSP
  633. setsockopt((SOCKET)sp->sock, SOL_SOCKET, SO_BLOCKING, &on, sizeof(on));
  634. #else
  635. fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) | O_NONBLOCK);
  636. #endif
  637. }
  638. #if MACOSX
  639. /* Prevent SIGPIPE when writing to closed socket on OS X */
  640. int iflag = 1;
  641. setsockopt(sp->sock, SOL_SOCKET, SO_NOSIGPIPE, (void*) &iflag, sizeof(iflag));
  642. #endif
  643. return oldBlock;
  644. }
  645. /*
  646. Set the TCP delay behavior (nagle algorithm)
  647. */
  648. PUBLIC int socketSetNoDelay(int sid, bool on)
  649. {
  650. WebsSocket *sp;
  651. int oldDelay;
  652. if ((sp = socketPtr(sid)) == NULL) {
  653. assert(0);
  654. return 0;
  655. }
  656. oldDelay = sp->flags & SOCKET_NODELAY;
  657. if (on) {
  658. sp->flags |= SOCKET_NODELAY;
  659. } else {
  660. sp->flags &= ~(SOCKET_NODELAY);
  661. }
  662. #if ME_WIN_LIKE
  663. {
  664. BOOL noDelay;
  665. noDelay = on ? 1 : 0;
  666. setsockopt(sp->sock, IPPROTO_TCP, TCP_NODELAY, (FAR char*) &noDelay, sizeof(BOOL));
  667. }
  668. #else
  669. {
  670. int noDelay;
  671. noDelay = on ? 1 : 0;
  672. setsockopt(sp->sock, IPPROTO_TCP, TCP_NODELAY, (char*) &noDelay, sizeof(int));
  673. }
  674. #endif /* ME_WIN_LIKE */
  675. return oldDelay;
  676. }
  677. /*
  678. Write to a socket. Absorb as much data as the socket can buffer. Block if the socket is in blocking mode. Returns -1
  679. on error, otherwise the number of bytes written.
  680. */
  681. PUBLIC ssize socketWrite(int sid, void *buf, ssize bufsize)
  682. {
  683. WebsSocket *sp;
  684. ssize len, written, sofar;
  685. int errCode;
  686. if (buf == 0 || (sp = socketPtr(sid)) == NULL) {
  687. return -1;
  688. }
  689. if (sp->flags & SOCKET_EOF) {
  690. return -1;
  691. }
  692. len = bufsize;
  693. sofar = 0;
  694. while (len > 0) {
  695. if ((written = send(sp->sock, (char*) buf + sofar, (int) len, 0)) < 0) {
  696. errCode = socketGetError(sid);
  697. if (errCode == EINTR) {
  698. continue;
  699. } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
  700. if (sofar) {
  701. /*
  702. If some data was written, we mask the EAGAIN for this time. Caller should recall and then
  703. will get a negative return code with EAGAIN.
  704. */
  705. return sofar;
  706. }
  707. }
  708. return -errCode;
  709. }
  710. len -= written;
  711. sofar += written;
  712. }
  713. return sofar;
  714. }
  715. /*
  716. Read from a socket. Return the number of bytes read if successful. This may be less than the requested "bufsize" and
  717. may be zero. This routine may block if the socket is in blocking mode.
  718. Return -1 for errors or EOF. Distinguish between error and EOF via socketEof().
  719. */
  720. PUBLIC ssize socketRead(int sid, void *buf, ssize bufsize)
  721. {
  722. WebsSocket *sp;
  723. ssize bytes;
  724. int errCode;
  725. assert(buf);
  726. assert(bufsize > 0);
  727. if ((sp = socketPtr(sid)) == NULL) {
  728. return -1;
  729. }
  730. if (sp->flags & SOCKET_EOF) {
  731. return -1;
  732. }
  733. if ((bytes = recv(sp->sock, buf, (int) bufsize, 0)) < 0) {
  734. errCode = socketGetError(sid);
  735. if (errCode == EAGAIN || errCode == EWOULDBLOCK) {
  736. bytes = 0;
  737. } else {
  738. /* Conn reset or Some other error */
  739. sp->flags |= SOCKET_EOF;
  740. bytes = -errCode;
  741. }
  742. } else if (bytes == 0) {
  743. sp->flags |= SOCKET_EOF;
  744. bytes = -1;
  745. }
  746. return bytes;
  747. }
  748. /*
  749. Return true if EOF
  750. */
  751. PUBLIC bool socketEof(int sid)
  752. {
  753. WebsSocket *sp;
  754. if ((sp = socketPtr(sid)) == NULL) {
  755. error("---> socketEof return 1\n");
  756. return 1;
  757. }
  758. error("---> socketEof return %#x\n", sp->flags&SOCKET_EOF);
  759. return sp->flags & SOCKET_EOF;
  760. }
  761. PUBLIC void socketReservice(int sid)
  762. {
  763. WebsSocket *sp;
  764. if ((sp = socketPtr(sid)) == NULL) {
  765. return;
  766. }
  767. sp->flags |= SOCKET_RESERVICE;
  768. }
  769. /*
  770. Create a user handler for this socket. The handler called whenever there
  771. is an event of interest as defined by handlerMask (SOCKET_READABLE, ...)
  772. */
  773. PUBLIC void socketCreateHandler(int sid, int handlerMask, SocketHandler handler, void *data)
  774. {
  775. WebsSocket *sp;
  776. if ((sp = socketPtr(sid)) == NULL) {
  777. return;
  778. }
  779. sp->handler = handler;
  780. sp->handler_data = data;
  781. socketRegisterInterest(sid, handlerMask);
  782. }
  783. PUBLIC void socketDeleteHandler(int sid)
  784. {
  785. WebsSocket *sp;
  786. if ((sp = socketPtr(sid)) == NULL) {
  787. return;
  788. }
  789. sp->handler = NULL;
  790. socketRegisterInterest(sid, 0);
  791. }
  792. /*
  793. Allocate a new socket structure
  794. */
  795. PUBLIC int socketAlloc(cchar *ip, int port, SocketAccept accept, int flags)
  796. {
  797. WebsSocket *sp;
  798. int sid;
  799. if (socketMax >= FD_SETSIZE) {
  800. return -1;
  801. }
  802. if ((sid = wallocObject(&socketList, &socketMax, sizeof(WebsSocket))) < 0) {
  803. return -1;
  804. }
  805. sp = socketList[sid];
  806. sp->sid = sid;
  807. sp->accept = accept;
  808. sp->port = port;
  809. sp->fileHandle = -1;
  810. sp->saveMask = -1;
  811. if (ip) {
  812. sp->ip = sclone(ip);
  813. }
  814. sp->flags = flags & (SOCKET_BLOCK | SOCKET_LISTENING | SOCKET_NODELAY);
  815. return sid;
  816. }
  817. /*
  818. Free a socket structure
  819. */
  820. PUBLIC void socketFree(int sid)
  821. {
  822. WebsSocket *sp;
  823. char buf[256];
  824. int i;
  825. if ((sp = socketPtr(sid)) == NULL) {
  826. return;
  827. }
  828. /*
  829. To close a socket, remove any registered interests, set it to non-blocking so that the recv which follows won't
  830. block, do a shutdown on it so peers on the other end will receive a FIN, then read any data not yet retrieved
  831. from the receive buffer, and finally close it. If these steps are not all performed RESETs may be sent to the
  832. other end causing problems.
  833. */
  834. socketRegisterInterest(sid, 0);
  835. if (sp->sock >= 0) {
  836. socketSetBlock(sid, 0);
  837. while (recv(sp->sock, buf, sizeof(buf), 0) > 0) {}
  838. if (shutdown(sp->sock, SHUT_RDWR) >= 0) {
  839. while (recv(sp->sock, buf, sizeof(buf), 0) > 0) {}
  840. }
  841. closesocket(sp->sock);
  842. }
  843. wfree(sp->ip);
  844. wfree(sp);
  845. socketMax = wfreeHandle(&socketList, sid);
  846. /*
  847. Calculate the new highest socket number
  848. */
  849. socketHighestFd = -1;
  850. for (i = 0; i < socketMax; i++) {
  851. if ((sp = socketList[i]) == NULL) {
  852. continue;
  853. }
  854. socketHighestFd = max(socketHighestFd, sp->sock);
  855. }
  856. }
  857. /*
  858. Return the socket object reference
  859. */
  860. WebsSocket *socketPtr(int sid)
  861. {
  862. if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
  863. assert(NULL);
  864. errno = EBADF;
  865. return NULL;
  866. }
  867. assert(socketList[sid]);
  868. return socketList[sid];
  869. }
  870. /*
  871. Get the operating system error code
  872. */
  873. PUBLIC int socketGetError(int sid)
  874. {
  875. #if ME_WIN_LIKE
  876. switch (WSAGetLastError()) {
  877. case WSAEWOULDBLOCK:
  878. return EWOULDBLOCK;
  879. case WSAECONNRESET:
  880. return ECONNRESET;
  881. case WSAENETDOWN:
  882. return ENETDOWN;
  883. case WSAEPROCLIM:
  884. return EAGAIN;
  885. case WSAEINTR:
  886. return EINTR;
  887. default:
  888. return EINVAL;
  889. }
  890. #else
  891. return errno;
  892. #endif
  893. }
  894. PUBLIC void socketSetError(int error)
  895. {
  896. #if ME_WIN_LIKE
  897. SetLastError(error);
  898. #elif ME_UNIX_LIKE || VXWORKS
  899. errno = error;
  900. #endif
  901. }
  902. /*
  903. Return the underlying socket handle
  904. */
  905. PUBLIC Socket socketGetHandle(int sid)
  906. {
  907. WebsSocket *sp;
  908. if ((sp = socketPtr(sid)) == NULL) {
  909. return -1;
  910. }
  911. return sp->sock;
  912. }
  913. /*
  914. Get blocking mode
  915. */
  916. PUBLIC int socketGetBlock(int sid)
  917. {
  918. WebsSocket *sp;
  919. if ((sp = socketPtr(sid)) == NULL) {
  920. assert(0);
  921. return 0;
  922. }
  923. return (sp->flags & SOCKET_BLOCK);
  924. }
  925. PUBLIC int socketGetMode(int sid)
  926. {
  927. WebsSocket *sp;
  928. if ((sp = socketPtr(sid)) == NULL) {
  929. assert(0);
  930. return 0;
  931. }
  932. return sp->flags;
  933. }
  934. PUBLIC void socketSetMode(int sid, int mode)
  935. {
  936. WebsSocket *sp;
  937. if ((sp = socketPtr(sid)) == NULL) {
  938. assert(0);
  939. return;
  940. }
  941. sp->flags = mode;
  942. }
  943. PUBLIC int socketGetPort(int sid)
  944. {
  945. WebsSocket *sp;
  946. if ((sp = socketPtr(sid)) == NULL) {
  947. return -1;
  948. }
  949. return sp->port;
  950. }
  951. #if ME_UNIX_LIKE || WINDOWS
  952. /*
  953. Get a socket address from a host/port combination. If a host provides both IPv4 and IPv6 addresses,
  954. prefer the IPv4 address. This routine uses getaddrinfo.
  955. Caller must free addr.
  956. */
  957. PUBLIC int socketInfo(cchar *ip, int port, int *family, int *protocol, struct sockaddr_storage *addr, Socklen *addrlen)
  958. {
  959. struct addrinfo hints, *res, *r;
  960. char portBuf[16];
  961. int v6;
  962. assert(addr);
  963. memset((char*) &hints, '\0', sizeof(hints));
  964. /*
  965. Note that IPv6 does not support broadcast, there is no 255.255.255.255 equivalent.
  966. Multicast can be used over a specific link, but the user must provide that address plus %scope_id.
  967. */
  968. if (ip == 0 || ip[0] == '\0') {
  969. ip = 0;
  970. hints.ai_flags |= AI_PASSIVE; /* Bind to 0.0.0.0 and :: */
  971. }
  972. v6 = ipv6(ip);
  973. hints.ai_socktype = SOCK_STREAM;
  974. if (ip) {
  975. hints.ai_family = v6 ? AF_INET6 : AF_INET;
  976. } else {
  977. hints.ai_family = AF_UNSPEC;
  978. }
  979. itosbuf(portBuf, sizeof(portBuf), port, 10);
  980. /*
  981. Try to sleuth the address to avoid duplicate address lookups. Then try IPv4 first then IPv6.
  982. */
  983. res = 0;
  984. if (getaddrinfo(ip, portBuf, &hints, &res) != 0) {
  985. return -1;
  986. }
  987. /*
  988. Prefer IPv4 if IPv6 not requested
  989. */
  990. for (r = res; r; r = r->ai_next) {
  991. if (v6) {
  992. if (r->ai_family == AF_INET6) {
  993. break;
  994. }
  995. } else {
  996. if (r->ai_family == AF_INET) {
  997. break;
  998. }
  999. }
  1000. }
  1001. if (r == NULL) {
  1002. r = res;
  1003. }
  1004. memset(addr, 0, sizeof(*addr));
  1005. memcpy((char*) addr, (char*) r->ai_addr, (int) r->ai_addrlen);
  1006. *addrlen = (int) r->ai_addrlen;
  1007. *family = r->ai_family;
  1008. *protocol = r->ai_protocol;
  1009. freeaddrinfo(res);
  1010. return 0;
  1011. }
  1012. #else
  1013. PUBLIC int socketInfo(char *ip, int port, int *family, int *protocol, struct sockaddr_storage *addr, Socklen *addrlen)
  1014. {
  1015. struct sockaddr_in sa;
  1016. memset((char*) &sa, '\0', sizeof(struct sockaddr_in));
  1017. sa.sin_family = AF_INET;
  1018. sa.sin_port = htons((short) (port & 0xFFFF));
  1019. if (ip && *ip) {
  1020. sa.sin_addr.s_addr = inet_addr((char*) ip);
  1021. } else {
  1022. sa.sin_addr.s_addr = INADDR_ANY;
  1023. }
  1024. if (sa.sin_addr.s_addr == INADDR_NONE) {
  1025. #if VXWORKS
  1026. /*
  1027. VxWorks only supports one interface and this code only supports IPv4
  1028. */
  1029. sa.sin_addr.s_addr = (ulong) hostGetByName((char*) ip);
  1030. if (sa.sin_addr.s_addr < 0) {
  1031. assert(0);
  1032. return 0;
  1033. }
  1034. #else
  1035. struct hostent *hostent;
  1036. hostent = gethostbyname2(ip, AF_INET);
  1037. if (hostent == 0) {
  1038. hostent = gethostbyname2(ip, AF_INET6);
  1039. if (hostent == 0) {
  1040. return -1;
  1041. }
  1042. }
  1043. memcpy((char*) &sa.sin_addr, (char*) hostent->h_addr_list[0], (ssize) hostent->h_length);
  1044. #endif
  1045. }
  1046. memcpy((char*) addr, (char*) &sa, sizeof(sa));
  1047. *addrlen = sizeof(struct sockaddr_in);
  1048. *family = sa.sin_family;
  1049. *protocol = 0;
  1050. return 0;
  1051. }
  1052. #endif
  1053. /*
  1054. Return a numerical IP address and port for the given socket info
  1055. */
  1056. PUBLIC int socketAddress(struct sockaddr *addr, int addrlen, char *ip, int ipLen, int *port)
  1057. {
  1058. #if (ME_UNIX_LIKE || ME_WIN_LIKE)
  1059. char service[NI_MAXSERV];
  1060. #if ME_WIN_LIKE || defined(IN6_IS_ADDR_V4MAPPED)
  1061. if (addr->sa_family == AF_INET6) {
  1062. struct sockaddr_in6* addr6 = (struct sockaddr_in6*) addr;
  1063. if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
  1064. struct sockaddr_in addr4;
  1065. memset(&addr4, 0, sizeof(addr4));
  1066. addr4.sin_family = AF_INET;
  1067. addr4.sin_port = addr6->sin6_port;
  1068. memcpy(&addr4.sin_addr.s_addr, addr6->sin6_addr.s6_addr + 12, sizeof(addr4.sin_addr.s_addr));
  1069. memcpy(addr, &addr4, sizeof(addr4));
  1070. addrlen = sizeof(addr4);
  1071. }
  1072. }
  1073. #endif
  1074. if (getnameinfo(addr, addrlen, ip, ipLen, service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV | NI_NOFQDN)) {
  1075. return -1;
  1076. }
  1077. if (port) {
  1078. *port = atoi(service);
  1079. }
  1080. #else
  1081. struct sockaddr_in *sa;
  1082. #if HAVE_NTOA_R
  1083. sa = (struct sockaddr_in*) addr;
  1084. inet_ntoa_r(sa->sin_addr, ip, ipLen);
  1085. #else
  1086. uchar *cp;
  1087. sa = (struct sockaddr_in*) addr;
  1088. cp = (uchar*) &sa->sin_addr;
  1089. fmt(ip, ipLen, "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
  1090. #endif
  1091. if (port) {
  1092. *port = ntohs(sa->sin_port);
  1093. }
  1094. #endif
  1095. return 0;
  1096. }
  1097. /*
  1098. Looks like an IPv6 address if it has 2 or more colons
  1099. */
  1100. static int ipv6(cchar *ip)
  1101. {
  1102. char *cp;
  1103. int colons;
  1104. if (ip == 0 || *ip == 0) {
  1105. /*
  1106. Listening on just a bare port means IPv4 only.
  1107. */
  1108. return 0;
  1109. }
  1110. colons = 0;
  1111. for (cp = (char*) ip; ((*cp != '\0') && (colons < 2)) ; cp++) {
  1112. if (*cp == ':') {
  1113. colons++;
  1114. }
  1115. }
  1116. return colons >= 2;
  1117. }
  1118. /*
  1119. Parse address and return the IP address and port components. Handles ipv4 and ipv6 addresses.
  1120. If the IP portion is absent, *pip is set to null. If the port portion is absent, port is set to the defaultPort.
  1121. If a ":*" port specifier is used, *pport is set to -1;
  1122. When an address contains an ipv6 port it should be written as:
  1123. aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh:iiii
  1124. or
  1125. [aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh:iiii]:port
  1126. If supplied an IPv6 address, the backets are stripped in the returned IP address.
  1127. This routine parses any "https://" prefix.
  1128. Caller must free *pip
  1129. */
  1130. PUBLIC int socketParseAddress(cchar *address, char **pip, int *pport, int *secure, int defaultPort)
  1131. {
  1132. char *ip, *cp;
  1133. ip = 0;
  1134. if (defaultPort < 0) {
  1135. defaultPort = 80;
  1136. }
  1137. *secure = strncmp(address, "https", 5) == 0;
  1138. if ((cp = strstr(address, "://")) != 0) {
  1139. address = &cp[3];
  1140. }
  1141. if (ipv6(address)) {
  1142. error("---> ipv6\n");
  1143. /*
  1144. IPv6. If port is present, it will follow a closing bracket ']'
  1145. */
  1146. if ((cp = strchr(address, ']')) != 0) {
  1147. cp++;
  1148. if ((*cp) && (*cp == ':')) {
  1149. *pport = (*++cp == '*') ? -1 : atoi(cp);
  1150. /* Set ipAddr to ipv6 address without brackets */
  1151. ip = sclone(address + 1);
  1152. if ((cp = strchr(ip, ']')) != 0) {
  1153. *cp = '\0';
  1154. }
  1155. } else {
  1156. /* Handles [a:b:c:d:e:f:g:h:i] case (no port)- should not occur */
  1157. ip = sclone(address + 1);
  1158. if ((cp = strchr(ip, ']')) != 0) {
  1159. *cp = '\0';
  1160. }
  1161. if (*ip == '\0') {
  1162. ip = 0;
  1163. }
  1164. /* No port present, use callers default */
  1165. *pport = defaultPort;
  1166. }
  1167. } else {
  1168. /* Handles a:b:c:d:e:f:g:h:i case (no port) */
  1169. ip = sclone(address);
  1170. /* No port present, use callers default */
  1171. *pport = defaultPort;
  1172. }
  1173. } else {
  1174. error("---> ipv4\n");
  1175. /*
  1176. ipv4
  1177. */
  1178. ip = sclone(address);
  1179. if ((cp = strchr(ip, ':')) != 0) {
  1180. *cp++ = '\0';
  1181. if (*cp == '*') {
  1182. *pport = -1;
  1183. } else {
  1184. *pport = atoi(cp);
  1185. }
  1186. if (*ip == '*' || *ip == '\0') {
  1187. wfree(ip);
  1188. ip = 0;
  1189. }
  1190. } else if (strchr(ip, '.')) {
  1191. *pport = defaultPort;
  1192. } else {
  1193. if (isdigit((uchar) *ip)) {
  1194. *pport = atoi(ip);
  1195. wfree(ip);
  1196. ip = 0;
  1197. } else {
  1198. /* No port present, use callers default */
  1199. *pport = defaultPort;
  1200. }
  1201. }
  1202. }
  1203. if (pip) {
  1204. *pip = ip;
  1205. } else if (ip) {
  1206. wfree(ip);
  1207. }
  1208. return 0;
  1209. }
  1210. PUBLIC bool socketIsV6(int sid)
  1211. {
  1212. WebsSocket *sp;
  1213. if ((sp = socketPtr(sid)) == NULL) {
  1214. return 0;
  1215. }
  1216. return sp->ip && ipv6(sp->ip);
  1217. }
  1218. PUBLIC bool socketAddressIsV6(cchar *ip)
  1219. {
  1220. return ip && ipv6(ip);
  1221. }
  1222. PUBLIC WebsSocket **socketGetList(void)
  1223. {
  1224. return socketList;
  1225. }
  1226. /*
  1227. Copyright (c) Embedthis Software. All Rights Reserved.
  1228. This software is distributed under commercial and open source licenses.
  1229. You may use the Embedthis GoAhead open source license or you may acquire
  1230. a commercial license from Embedthis Software. You agree to be fully bound
  1231. by the terms of either license. Consult the LICENSE.md distributed with
  1232. this software for full details and other copyrights.
  1233. */