socket.c 35 KB

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