1 /* nl-sock.c
2 
3     Copyright (C) 2016 Lutz Mueller
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 
20 
21 #include "newlisp.h"
22 #include <string.h>
23 
24 #ifdef WINDOWS
25 
26 #include <winsock2.h>
27 #pragma push_macro("UINT")
28 #undef UINT /* avoid clash with newLISP UINT */
29 #include <ws2tcpip.h>
30 #pragma pop_macro("UINT")
31 #include <ws2spi.h>
32 
33 #define fdopen win_fdopen
34 #define SHUT_RDWR 2
35 #define gethostbyname2(A, B) gethostbyname(A)
36 
37 #else /* UNIX */
38 
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #include <sys/ioctl.h>
44 #include <sys/wait.h>
45 #define __FAVOR_BSD
46 #include <netinet/in_systm.h>
47 #include <netinet/in.h>
48 #include <netinet/ip.h>
49 #include <netinet/tcp.h>
50 #include <netinet/udp.h>
51 #include <netinet/ip_icmp.h>
52 #ifndef OS2
53 #include <netinet/icmp6.h>
54 #endif
55 #include <netdb.h>
56 #include <arpa/inet.h>
57 
58 #ifndef IPPROTO_DIVERT
59 #define IPPROTO_DIVERT 254
60 #endif
61 
62 /* Android needs it */
63 #ifndef ICMP6_FILTER
64 #define ICMP6_FILTER 1
65 #endif
66 
67 #endif /* end UNIX */
68 
69 #ifdef CYGWIN
70 #include <netinet/icmp6.h> /* not on Cygwin, get from other OS */
71 
72 #define ICMP_ECHO 8
73 
74 struct icmp
75 {
76    unsigned char icmp_type;
77    unsigned char icmp_code;
78    unsigned short icmp_cksum;
79    unsigned short icmp_id;
80    unsigned short icmp_seq;
81 };
82 #endif /* end CYGWIN */
83 
84 #if defined(SOLARIS) || defined(TRU64) || defined(AIX)
85 #include <stropts.h>
86 #include <sys/conf.h>
87 #include <netinet/in_systm.h>
88 #define gethostbyname2(A, B) gethostbyname(A)
89 #endif
90 
91 #ifdef SOLARIS
92 #define FIONREAD I_NREAD
93 #endif
94 
95 #ifdef OS2
96 #define socklen_t int
97 #define SHUT_RDWR 2
98 #endif
99 
100 #ifndef INADDR_NONE
101 #define INADDR_NONE (unsigned) -1
102 #endif
103 
104 #ifndef AF_UNIX
105 #define AF_UNIX PF_UNIX
106 #endif
107 
108 #ifndef SUN_LEN
109 #define SUN_LEN(su) \
110     (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
111 #endif
112 
113 #include "protos.h"
114 
115 #define MAX_PENDING_CONNECTS 128
116 #define NO_FLAGS_SET 0
117 
118 #ifdef WINDOWS
119 #define close closesocket /* for file operations on Windows use _close */
120 #else
121 #define SOCKET_ERROR -1
122 #define INVALID_SOCKET -1
123 #endif
124 
125 #define isnum(A) ((A)>= '0' && (A) <= '9')
126 
127 IO_SESSION * ioSessions = NULL;
128 
129 int isSessionSocket(int sock);
130 int getSocketFamily(int sock);
131 
132 #ifndef EMSCRIPTEN
133 #define READY_READ 0
134 #define READY_WRITE 1
135 
136 UINT netErrorIdx = 0;
137 
138 extern int logTraffic;
139 extern int noPromptMode;
140 
141 int ADDR_FAMILY = AF_INET; /* the default is IPv4 */
142 int ICMP_TYPE;
143 #define STRADDR_LEN 40
144 
145 
146 /*  set the default interface and select IPv4 or IPv6 mode */
147 
148 struct sockaddr * defaultIn = NULL;
149 void * defaultInAddr = NULL; /* either (struct in6_addr *) or (struct in_adr *) */
150 char * defaultInterface = NULL;
151 socklen_t defaultInLen;
152 
153 extern int opsys;
initDefaultInAddr()154 void initDefaultInAddr()
155 {
156 struct sockaddr_in6 * address6;
157 struct sockaddr_in * address;
158 
159 if(defaultIn != NULL) free(defaultIn);
160 defaultInLen = (ADDR_FAMILY == AF_INET6) ?
161     sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
162 
163 defaultIn = callocMemory(defaultInLen);
164 
165 if(ADDR_FAMILY == AF_INET6)
166     {
167     address6 = (struct sockaddr_in6 *)defaultIn;
168     address6->sin6_addr = in6addr_any;
169     defaultInAddr = &address6->sin6_addr;
170     address6->sin6_family = AF_INET6;
171     ICMP_TYPE = IPPROTO_ICMPV6;
172     opsys |= 0x200;
173     }
174 else
175     {
176     address = (struct sockaddr_in *)defaultIn;
177     address->sin_addr.s_addr = INADDR_ANY;
178     defaultInAddr = &address->sin_addr;
179     address->sin_family = AF_INET;
180     ICMP_TYPE = IPPROTO_ICMP;
181     opsys &= ~0x200;
182     }
183 
184 }
185 #endif /* ifndef EMSCRIPTEN */
186 
187 /********************** IO session functions *******************/
188 
createIOsession(int handle,int family)189 IO_SESSION * createIOsession(int handle, int family)
190 {
191 IO_SESSION * iSession;
192 
193 iSession = (IO_SESSION *)calloc(sizeof(IO_SESSION), 1);
194 
195 iSession->handle = handle;
196 iSession->family = family;
197 
198 if(ioSessions == NULL)
199     {
200     ioSessions = iSession;
201     iSession->next = NULL;
202     }
203 else
204     {
205     iSession->next = ioSessions;
206     ioSessions = iSession;
207     }
208 
209 return(iSession);
210 }
211 
deleteIOsession(int handle)212 int deleteIOsession(int handle)
213 {
214 IO_SESSION * session;
215 IO_SESSION * previous;
216 
217 if(ioSessions == NULL)
218     return(0);
219 else
220     session = previous = ioSessions;
221 
222 while(session)
223     {
224     if(session->handle == handle)
225         {
226         if(session == ioSessions)
227             ioSessions = session->next;
228         else
229             previous->next = session->next;
230         if(session->stream != NULL)
231             fclose(session->stream);
232         else close(handle);
233         free((char *)session);
234         return(TRUE);
235         }
236     previous = session;
237     session = session->next;
238     }
239 
240 return(FALSE);
241 }
242 
243 
isSessionSocket(int sock)244 int isSessionSocket(int sock)
245 {
246 IO_SESSION * session;
247 
248 if(ioSessions == NULL)
249     return(FALSE);
250 
251 session = ioSessions;
252 while(session)
253     {
254     if(session->handle == sock)
255         return(TRUE);
256     session = session->next;
257     }
258 
259 return(FALSE);
260 }
261 
getSocketFamily(int sock)262 int getSocketFamily(int sock)
263 {
264 IO_SESSION * session;
265 
266 session = ioSessions;
267 
268 while(session)
269     {
270     if(session->handle == sock)
271         return(session->family);
272     session = session->next;
273     }
274 
275 return(-1);
276 }
277 
278 
getIOstream(int handle)279 FILE * getIOstream(int handle)
280 {
281 IO_SESSION * session;
282 
283 session = ioSessions;
284 
285 while(session)
286     {
287     if(session->handle == handle)
288         return(session->stream);
289     session = session->next;
290     }
291 
292 return(NULL);
293 }
294 
295 /* ========================= IO session functions end ===================== */
296 #ifndef EMSCRIPTEN
297 #ifdef WINDOWS
ipstrFromSockAddr(struct sockaddr * addr,char * host,int len)298 int ipstrFromSockAddr(struct sockaddr * addr, char * host, int len)
299 {
300 WSAAddressToString(addr, defaultInLen, NULL, host, (LPDWORD)&len);
301 return(TRUE);
302 }
303 #else /* UNIX */
ipstrFromSockAddr(struct sockaddr * addr,char * host,int len)304 int ipstrFromSockAddr(struct sockaddr * addr, char * host, int len)
305 {
306 struct sockaddr_in6 * saddr6 = (struct sockaddr_in6 *)addr;
307 struct sockaddr_in * saddr =(struct sockaddr_in *)addr;
308 
309 if(addr->sa_family == AF_INET6)
310     inet_ntop(AF_INET6, &saddr6->sin6_addr, host, len);
311 else
312     strncpy(host, inet_ntoa(saddr->sin_addr), len);
313 return(TRUE);
314 }
315 #endif
316 
317 /* ANDROID and WINDOWS need this */
318 #ifndef in_port_t
319 #define in_port_t short int
320 #endif
321 
portFromSockAddr(struct sockaddr * addr)322 in_port_t portFromSockAddr(struct sockaddr * addr)
323 {
324 in_port_t * portPtr = (in_port_t *)&addr->sa_data[0];
325 
326 return(ntohs(*portPtr));
327 }
328 
329 
setSockaddrPort(struct sockaddr * addr,in_port_t port)330 void setSockaddrPort(struct sockaddr * addr, in_port_t port)
331 {
332 in_port_t * portPtr = (in_port_t *)&addr->sa_data[0];
333 
334 *portPtr = htons(port);
335 }
336 
337 /********************* user functions **************************/
338 
339 
p_netClose(CELL * params)340 CELL * p_netClose(CELL * params)
341 {
342 UINT sock;
343 
344 getInteger(params, &sock);
345 if(!deleteIOsession((int)sock))
346     return(netError(ERR_INET_NOT_VALID_SOCKET));
347 
348 netErrorIdx = 0;
349 return(trueCell);
350 }
351 
352 
p_netSessions(CELL * params)353 CELL * p_netSessions(CELL * params)
354 {
355 IO_SESSION * session;
356 IO_SESSION * sPtr;
357 CELL * sList;
358 
359 session = ioSessions;
360 sList = getCell(CELL_EXPRESSION);
361 
362 while(session)
363     {
364     sPtr = session;
365     session = session->next;
366     if(sPtr->family != AF_UNSPEC || getFlag(params))
367         addList(sList, stuffInteger(sPtr->handle));
368     }
369 
370 return(sList);
371 }
372 
373 
374 /*********************************************************************/
375 
p_netService(CELL * params)376 CELL * p_netService(CELL * params)
377 {
378 struct servent * pSe;
379 char * service = NULL;
380 char * protocol = NULL;
381 CELL * cell;
382 UINT port;
383 
384 params = getEvalDefault(params, &cell);
385 getString(params, &protocol);
386 if(cell->type == CELL_STRING)
387     {
388     service = (char *)cell->contents;
389 
390     if((pSe = getservbyname(service, protocol)) == NULL)
391         return(netError(ERR_INET_INVALID_SERVICE));
392 
393     port = (int)ntohs(pSe->s_port);
394 
395     netErrorIdx = 0;
396     return(stuffInteger((UINT)port));
397     }
398 if(isNumber(cell->type))
399     {
400     getIntegerExt(cell, &port, FALSE);
401 
402     if((pSe = getservbyport(htons(port), protocol)) == NULL)
403         return(netError(ERR_INET_INVALID_SERVICE));
404 
405     netErrorIdx = 0;
406     return(stuffString(pSe->s_name));
407     }
408 
409 return(errorProcExt(ERR_NUMBER_OR_STRING_EXPECTED, cell));
410 }
411 
p_netConnect(CELL * params)412 CELL * p_netConnect(CELL * params)
413 {
414 CELL * cell;
415 char * remoteHostName;
416 UINT portNo;
417 UINT topt = CONNECT_TIMEOUT; /* default ms timeout from newlisp.h */
418 int sock;
419 int type;
420 int protocol = 0;
421 
422 params = getString(params, &remoteHostName);
423 #ifndef WINDOWS
424 if(params == nilCell)
425     {
426     if((sock = netConnectLocal(remoteHostName)) == SOCKET_ERROR)
427         return(netError(netErrorIdx));
428     else
429         return(stuffInteger((UINT)sock));
430     }
431 
432 #endif
433 
434 params = getInteger(params, &portNo);
435 type = SOCK_STREAM;
436 if(params != nilCell)
437     {
438     cell = evaluateExpression(params);
439     if(cell->type == CELL_STRING)
440         {
441         protocol = toupper(*(char *)cell->contents);
442         if(!(protocol == 'M' || protocol == 'B' || protocol == 'U'))
443             return(errorProc(ERR_INVALID_OPTION));
444         type = SOCK_DGRAM;
445         if(protocol == 'M') /* get ttl */
446             {
447             if(params->next != nilCell)
448                 /* topt is ttl in this case */
449                 getInteger(params->next, &topt);
450             else topt = 3;
451             }
452         }
453     else if(isNumber(cell->type))
454         /* topt is ms timeout */
455         getIntegerExt(cell, &topt, FALSE);
456     else
457         return(errorProcExt(ERR_NUMBER_OR_STRING_EXPECTED, cell));
458     }
459 
460 if((sock = netConnect(remoteHostName,
461         (int)portNo, type, protocol, (int)topt)) == SOCKET_ERROR)
462     return(netError(netErrorIdx));
463 
464 createIOsession(sock, ADDR_FAMILY);
465 
466 netErrorIdx = 0;
467 return(stuffInteger((UINT)sock));
468 }
469 
470 
471 #ifndef WINDOWS
472 /* create local domain UNIX socket */
netConnectLocal(char * path)473 int netConnectLocal(char * path)
474 {
475 int sock;
476 struct sockaddr_un remote_sun;
477 
478 if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == SOCKET_ERROR)
479     {
480     netErrorIdx = ERR_INET_OPEN_SOCKET;
481     return(SOCKET_ERROR);
482     }
483 
484 remote_sun.sun_family = AF_UNIX;
485 strncpy(remote_sun.sun_path, path, sizeof(remote_sun.sun_path) - 1);
486 remote_sun.sun_path[sizeof (remote_sun.sun_path) - 1] = '\0';
487 if (connect(sock, (struct sockaddr *)&remote_sun, SUN_LEN(&remote_sun)) == -1)
488     {
489     close(sock);
490     netErrorIdx = ERR_INET_CONNECT_FAILED;
491     return(SOCKET_ERROR);
492     }
493 
494 createIOsession(sock, AF_UNIX);
495 
496 netErrorIdx = 0;
497 return(sock);
498 }
499 #endif
500 
501 
blockSocket(int sock)502 int blockSocket(int sock)
503 {
504 #ifdef WINDOWS
505 u_long arg = 0;
506 return(ioctlsocket(sock, FIONBIO, &arg));
507 #else /* UNIX */
508 int arg;
509 arg = fcntl(sock, F_GETFL, NULL);
510 arg &= (~O_NONBLOCK);
511 return(fcntl(sock, F_SETFL, arg));
512 #endif
513 }
514 
515 #ifdef UNBLOCK
unblockSocket(int sock)516 int unblockSocket(int sock)
517 {
518 #ifdef WINDOWS
519 u_long arg = 1;
520 return(ioctlsocket(sock, FIONBIO, &arg));
521 #else /* Unix */
522 int arg;
523 arg = fcntl(sock, F_GETFL, NULL);
524 arg &= (~O_NONBLOCK);
525 return(fcntl(sock, F_SETFL, arg));
526 #endif
527 }
528 #endif
529 
530 /* create internet socket
531    if prot = NULL then topt is timeout in ms, else topt is ttl (time to live)
532 */
netConnect(char * remoteHostName,int portNo,int type,int prot,int topt)533 int netConnect(char * remoteHostName, int portNo, int type, int prot, int topt)
534 {
535 struct addrinfo hints, *res, *res0;
536 char portStr[10];
537 int sock, opt;
538 #if defined(WINDOWS) || defined(EMSCRIPTEN)
539 u_long arg = 1;
540 #else
541 int arg, value;
542 socklen_t socklen = sizeof(sock);
543 #endif
544 int result = -1;
545 int sinlen;
546 
547 /* create socket */
548 if((sock = socket(ADDR_FAMILY, type, 0)) == INVALID_SOCKET)
549     {
550     netErrorIdx = ERR_INET_OPEN_SOCKET;
551     return(SOCKET_ERROR);
552     }
553 
554 if(prot == 0) /* topt is timeout in millisecs */
555     {
556 #ifdef WINDOWS
557     if(ioctlsocket(sock, FIONBIO, &arg) != 0)
558         {
559         netErrorIdx = ERR_INET_CANNOT_CHANGE_SOCK_BLOCK;
560         return(SOCKET_ERROR);
561         }
562 #else /* UNIX */
563     arg = fcntl(sock, F_GETFL, NULL);
564     if(fcntl(sock, F_SETFL, arg | O_NONBLOCK) < 0)
565         {
566         netErrorIdx = ERR_INET_CANNOT_CHANGE_SOCK_BLOCK;
567         return(SOCKET_ERROR);
568         }
569 #endif
570     }
571 else if(prot == 'M' || prot == 'B')
572     {
573     sinlen = (ADDR_FAMILY == AF_INET6) ? sizeof(struct in6_addr) : sizeof(struct in_addr);
574 
575     if(prot == 'M')
576         {
577         setsockopt(sock, 0, IP_MULTICAST_IF, (const void *)defaultInAddr, sinlen);
578         opt = topt; /* ttl time to live */
579         setsockopt(sock, 0, IP_MULTICAST_TTL, (const void *)&opt, sizeof(opt));
580         }
581 
582     if(prot == 'B')
583         {
584         opt = 1;
585         setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const void *)&opt, sizeof(opt));
586         }
587     }
588 
589 if(type == SOCK_DGRAM && *remoteHostName == 0)
590     return(sock);
591 
592 memset(&hints, 0, sizeof(hints));
593 hints.ai_family = (ADDR_FAMILY == AF_INET6) ? PF_INET6 : PF_INET;
594 hints.ai_socktype = SOCK_STREAM;
595 snprintf(portStr, 10, "%d", portNo);
596 
597 if(getaddrinfo(remoteHostName, portStr, &hints, &res0) != 0)
598     {
599     netErrorIdx = ERR_INET_HOST_UNKNOWN;
600     return(SOCKET_ERROR);
601     }
602 
603 for(res = res0; res; res = res->ai_next)
604     {
605     result = connect(sock, res->ai_addr, res->ai_addrlen);
606     if(result < 0)
607         {
608 #ifdef WINDOWS
609         if(WSAGetLastError() == WSAEWOULDBLOCK)
610 #else
611         if(errno == EINPROGRESS)
612 #endif
613             {
614             if((result = wait_ready(sock, topt * 1000, READY_WRITE)) <= 0)
615                 {
616                 netErrorIdx = result < 0 ? ERR_INET_CONNECT_FAILED : ERR_INET_TIMEOUT;
617                 goto CONNECT_FAILED;
618                 }
619 #ifndef WINDOWS
620             getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&value, &socklen);
621             if (value)
622                 {
623                 netErrorIdx =  ERR_INET_CONNECT_FAILED;
624                 goto CONNECT_FAILED;
625                 }
626 #endif
627             result = 0;
628             break;
629             }
630         else
631             {
632             netErrorIdx =  ERR_INET_CONNECT_FAILED;
633             goto CONNECT_FAILED;
634             }
635         break;
636         }
637     else break; /* result == 0 */
638     }
639 
640 if(result != 0)
641     {
642     netErrorIdx = ERR_INET_CONNECT_FAILED;
643     goto CONNECT_FAILED;
644     }
645 
646 if(blockSocket(sock) != 0)
647     {
648     netErrorIdx = ERR_INET_CANNOT_CHANGE_SOCK_BLOCK;
649     goto CONNECT_FAILED;
650     }
651 
652 freeaddrinfo(res0);
653 netErrorIdx = 0;
654 return(sock);
655 
656 CONNECT_FAILED:
657 freeaddrinfo(res0);
658 close(sock);
659 return(SOCKET_ERROR);
660 }
661 
662 /* take and empty sockaddr and fill in from portNo, socket type and interface
663    if ifAddr is defined as NULL or and empty string assume sockaddr at defaultIn
664    which is initialized to INADDR_ANY in initDefaultInAddr()
665 */
getHostAddr(struct sockaddr * address,int stype,char * ifAddr)666 int getHostAddr(struct sockaddr * address, int stype, char * ifAddr)
667 {
668 struct addrinfo hints, *res;
669 int error;
670 
671 if(ifAddr != NULL && *ifAddr != '\0')
672     {
673     memset(&hints, 0, sizeof(hints));
674     hints.ai_family = (ADDR_FAMILY == AF_INET6) ? PF_INET6 : PF_INET;
675     hints.ai_socktype = stype;
676 
677     if((error = getaddrinfo(ifAddr, NULL, &hints, &res)) != 0)
678         return(error);
679 
680     memcpy(address, res->ai_addr, res->ai_addrlen);
681 
682     freeaddrinfo(res);
683     return(0);
684     }
685 
686 memcpy(address, defaultIn, defaultInLen);
687 return(0);
688 }
689 
690 
p_netInterface(CELL * params)691 CELL * p_netInterface(CELL * params)
692 {
693 char * ifAddr;
694 char IPaddress[STRADDR_LEN];
695 
696 netErrorIdx = 0;
697 
698 if(params != nilCell)
699     {
700     params = getString(params, &ifAddr);
701     if(getHostAddr((struct sockaddr *)defaultIn, 0, ifAddr) != 0)
702         return(netError(ERR_INET_HOST_UNKNOWN));
703     }
704 
705 getnameinfo((struct sockaddr *)defaultIn, defaultInLen,
706     IPaddress, STRADDR_LEN, NULL, 0, NI_NUMERICHOST);
707 return(stuffString(IPaddress));
708 }
709 
710 
p_netIpv(CELL * params)711 CELL * p_netIpv(CELL * params)
712 {
713 UINT protocol = (ADDR_FAMILY == AF_INET6) ? 6 : 4;
714 
715 if(params != nilCell)
716     {
717     getInteger(params, &protocol);
718     if(protocol != 4 && protocol != 6)
719         return(errorProc(ERR_INVALID_PARAMETER));
720     if(protocol == 6)
721         {
722         ADDR_FAMILY = AF_INET6;
723         opsys |= 512;
724         }
725     else
726         {
727         ADDR_FAMILY = AF_INET;
728         opsys &= ~512;
729         }
730     initDefaultInAddr();
731     }
732 
733 return(stuffInteger(protocol));
734 }
735 
736 
737 /********* should be called after listen/accept notification **********/
738 
p_netAccept(CELL * params)739 CELL * p_netAccept(CELL * params)
740 {
741 int sock;
742 UINT listenSock;
743 
744 getInteger(params, &listenSock);
745 
746 if((sock = netAccept((int)listenSock)) == INVALID_SOCKET)
747     return(netError(ERR_INET_ACCEPT));
748 
749 netErrorIdx = 0;
750 return(stuffInteger(sock));
751 }
752 
753 
netAccept(int listenSock)754 int netAccept(int listenSock)
755 {
756 int sock, family;
757 struct sockaddr * dest_sin;
758 socklen_t dest_slen;
759 #ifndef WINDOWS
760 struct sockaddr_un dest_sun;
761 #endif
762 
763 family = getSocketFamily(listenSock);
764 
765 #ifndef WINDOWS
766 if(family == AF_UNIX)
767     {
768     dest_slen = sizeof(struct sockaddr_un);
769     sock = accept(listenSock, (struct sockaddr *) &dest_sun,  &dest_slen);
770     }
771 else
772 #endif
773     {
774     dest_slen = (ADDR_FAMILY == AF_INET6) ?
775         sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
776 
777     dest_sin = alloca(dest_slen);
778 
779     sock = accept(listenSock, dest_sin, (void *)&dest_slen);
780     }
781 
782 if(sock != INVALID_SOCKET)
783     {
784     createIOsession(sock, family);
785     netErrorIdx = 0;
786     }
787 
788 return(sock);
789 }
790 
791 
792 /******************* returns IP and port number from socket *************/
793 
794 #define LOCAL_INFO 0
795 #define PEER_INFO 1
796 
getIpPortFromSocket(int sock,int peerLocalFlag,char * IPaddress)797 int getIpPortFromSocket(int sock, int peerLocalFlag, char * IPaddress)
798 {
799 int family;
800 socklen_t address_sin_len;
801 struct sockaddr * address_sin;
802 
803 family = getSocketFamily(sock);
804 address_sin_len = (family == AF_INET6) ?
805         sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
806 address_sin = alloca(address_sin_len);
807 
808 *IPaddress = 0;
809 
810 if(family == AF_UNIX)
811     {
812     strncpy(IPaddress, "local", 6);
813     return(0);
814     }
815 
816 if(peerLocalFlag == LOCAL_INFO)
817     {
818     if(getsockname(sock, address_sin, (void *)&address_sin_len) == SOCKET_ERROR)
819         return(SOCKET_ERROR);
820     }
821 else
822     if(getpeername(sock, address_sin, (void *)&address_sin_len) == SOCKET_ERROR)
823         return(SOCKET_ERROR);
824 
825 /* return address and port, IP number, address family taken fron address_sin  */
826 ipstrFromSockAddr((struct sockaddr *)address_sin, IPaddress, STRADDR_LEN);
827 return(portFromSockAddr((struct sockaddr *)address_sin));
828 }
829 
830 
p_netLocal(CELL * params)831 CELL * p_netLocal(CELL * params)
832 {
833 return(netPeerLocal(params, LOCAL_INFO));
834 }
835 
p_netPeer(CELL * params)836 CELL * p_netPeer(CELL * params)
837 {
838 return(netPeerLocal(params, PEER_INFO));
839 }
840 
841 
netPeerLocal(CELL * params,int peerLocalFlag)842 CELL * netPeerLocal(CELL * params, int peerLocalFlag)
843 {
844 CELL * result;
845 CELL * cell;
846 char name[STRADDR_LEN];
847 UINT addressPort, sock;
848 
849 getInteger(params, &sock);
850 if((addressPort = getIpPortFromSocket((int)sock, peerLocalFlag, name)) == SOCKET_ERROR)
851     return(netError(ERR_INET_NOT_VALID_SOCKET));
852 
853 result = makeCell(CELL_EXPRESSION, (UINT)stuffString(name));
854 
855 cell = (CELL *)result->contents;
856 cell->next = stuffInteger((UINT)addressPort);
857 
858 netErrorIdx = 0;
859 return(result);
860 }
861 
p_netLookup(CELL * params)862 CELL * p_netLookup(CELL * params)
863 {
864 char * hostString;
865 int forceByName = 0;
866 struct addrinfo hints, *res;
867 char hbuf[NI_MAXHOST];
868 int flags = NI_NUMERICHOST;
869 
870 netErrorIdx = 0;
871 params = getString(params, &hostString);
872 forceByName = getFlag(params);
873 
874 if( ((ADDR_FAMILY == AF_INET6) && strstr(hostString, ":") && !forceByName)
875     ||
876     ((ADDR_FAMILY == AF_INET) && isDigit((unsigned char)*hostString) && !forceByName) )
877     flags = NI_NAMEREQD;
878 
879 memset(&hints, 0, sizeof(hints));
880 
881 hints.ai_family = (ADDR_FAMILY == AF_INET6) ? PF_INET6 : PF_INET;
882 hints.ai_socktype = SOCK_STREAM;
883 /* hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; */
884 
885 if(getaddrinfo(hostString, NULL, &hints, &res) != 0)
886     return(netError(ERR_INET_HOST_UNKNOWN));
887 
888 if(getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, flags) != 0)
889     {
890     freeaddrinfo(res);
891     return(netError(ERR_INET_HOST_UNKNOWN));
892     }
893 
894 freeaddrinfo(res);
895 return(stuffString(hbuf));
896 }
897 
898 
899 CELL * netReceive(int sock, SYMBOL * readSymbol, size_t readSize, CELL * params);
900 
901 
p_netReceive(CELL * params)902 CELL * p_netReceive(CELL * params)
903 {
904 UINT sock;
905 SYMBOL * readSymbol;
906 size_t readSize;
907 CELL * cell;
908 
909 params = getInteger(params, &sock);
910 params = getEvalDefault(params, &cell);
911 
912 if(!symbolCheck)
913     return(errorProcExt(ERR_SYMBOL_EXPECTED, cell));
914 if(symbolCheck->contents != (UINT)cell)
915     return(errorProc(ERR_IS_NOT_REFERENCED));
916 
917 readSymbol = symbolCheck;
918 params = getInteger(params, (UINT *)&readSize);
919 
920 return(netReceive((int)sock, readSymbol, readSize, params));
921 }
922 
923 
netReceive(int sock,SYMBOL * readSymbol,size_t readSize,CELL * params)924 CELL * netReceive(int sock, SYMBOL * readSymbol, size_t readSize, CELL * params)
925 {
926 char * waitFor;
927 ssize_t bytesReceived;
928 size_t length;
929 int found;
930 STREAM netStream = {NULL, NULL, 0, 0, 0};
931 char chr;
932 CELL * cell;
933 
934 if(isProtected(readSymbol->flags))
935     return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(readSymbol)));
936 
937 if(params == nilCell)
938     {
939     openStrStream(&netStream, readSize, 0);
940     found = 1;
941     bytesReceived  = recv(sock, netStream.buffer, readSize, NO_FLAGS_SET);
942     }
943 else
944     {
945     getString(params, &waitFor);
946     openStrStream(&netStream, MAX_LINE, 0);
947     found = bytesReceived = 0;
948     length = strlen(waitFor);
949     while(bytesReceived < (int)readSize)
950         {
951         if(recv(sock, &chr, 1, NO_FLAGS_SET) <= 0)
952             {
953             bytesReceived = 0;
954             break;
955             }
956         writeStreamChar(&netStream, chr);
957          if(++bytesReceived < length) continue;
958         if(strncmp(waitFor,  netStream.ptr - length, length) == 0)
959             {
960             found = 1;
961             break;
962             }
963         }
964 
965     }
966 
967 if(bytesReceived == 0 || found == 0)
968     {
969     closeStrStream(&netStream);
970     deleteIOsession(sock);
971     return(netError(ERR_INET_CONNECTION_DROPPED));
972     }
973 
974 if(bytesReceived == SOCKET_ERROR)
975     {
976     closeStrStream(&netStream);
977     deleteIOsession(sock);
978     return(netError(ERR_INET_READ));
979     }
980 
981 cell = stuffStringN(netStream.buffer, bytesReceived);
982 closeStrStream(&netStream);
983 
984 deleteList((CELL *)readSymbol->contents);
985 readSymbol->contents = (UINT)cell;
986 
987 netErrorIdx = 0;
988 return(stuffInteger(bytesReceived));
989 }
990 
991 
netReceiveFrom(int sock,size_t readSize,int closeFlag)992 CELL * netReceiveFrom(int sock, size_t readSize, int closeFlag)
993 {
994 int portNo;
995 int family;
996 char * buffer;
997 ssize_t bytesReceived;
998 struct sockaddr * remote;
999 char IPaddress[STRADDR_LEN];
1000 CELL * cell;
1001 CELL * result;
1002 #ifdef TRU64
1003 unsigned long remote_sin_len;
1004 #else
1005 socklen_t remote_sin_len;
1006 #endif
1007 
1008 buffer = (char *)allocMemory(readSize + 1);
1009 
1010 family = getSocketFamily(sock);
1011 remote_sin_len = (family == AF_INET6) ?
1012     sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
1013 remote = alloca(remote_sin_len);
1014 memset(remote, 0, remote_sin_len);
1015 
1016 bytesReceived = recvfrom(sock, buffer, readSize, 0,
1017     (struct sockaddr *)remote, &remote_sin_len);
1018 
1019 if(bytesReceived == SOCKET_ERROR)
1020     {
1021     freeMemory(buffer);
1022     deleteIOsession(sock);
1023     return(netError(ERR_INET_READ));
1024     }
1025 
1026 ipstrFromSockAddr((struct sockaddr *)remote, IPaddress, STRADDR_LEN);
1027 portNo = portFromSockAddr((struct sockaddr *)remote);
1028 
1029 cell = result = makeCell(CELL_EXPRESSION, (UINT)stuffStringN(buffer, bytesReceived));
1030 
1031 cell = (CELL *)cell->contents;
1032 cell->next = stuffString(IPaddress);
1033 ((CELL*)cell->next)->next = stuffInteger(portNo);
1034 
1035 freeMemory(buffer);
1036 
1037 if(closeFlag)
1038     {
1039     deleteIOsession(sock);
1040     }
1041 
1042 netErrorIdx = 0;
1043 return(result);
1044 }
1045 
1046 
p_netReceiveUDP(CELL * params)1047 CELL * p_netReceiveUDP(CELL * params)
1048 {
1049 UINT portNo;
1050 int sock;
1051 size_t readSize;
1052 INT64 wait = 0;
1053 INT64 elapsed;
1054 char * ifaddr = NULL;
1055 
1056 params = getInteger(params, &portNo);
1057 params = getInteger(params, (UINT *)&readSize);
1058 if(params != nilCell)
1059     {
1060     params = getInteger64Ext(params, &wait, TRUE);
1061     if(params != nilCell)
1062         getString(params, &ifaddr);
1063     }
1064 
1065 if((sock = netListenOrDatagram((int)portNo, SOCK_DGRAM, ifaddr, NULL, 0)) == SOCKET_ERROR)
1066     return(nilCell);
1067 
1068 /* if timeout parameter given wait for socket to be readable */
1069 if(wait > 0)
1070         {
1071         if((elapsed = wait_ready(sock, wait, READY_READ)) <= 0)
1072                 {
1073                 close(sock);
1074                 if(elapsed == 0) return(netError(ERR_INET_TIMEOUT));
1075                 else netError(ERR_INET_SELECT_FAILED);
1076                 }
1077         }
1078 
1079 return(netReceiveFrom(sock, readSize, TRUE));
1080 }
1081 
1082 
p_netReceiveFrom(CELL * params)1083 CELL * p_netReceiveFrom(CELL * params)
1084 {
1085 UINT sock;
1086 size_t readSize;
1087 
1088 params = getInteger(params, &sock);
1089 getInteger(params, (UINT*)&readSize);
1090 
1091 return(netReceiveFrom((int)sock, readSize, FALSE));
1092 }
1093 
1094 
1095 /**********************************************************************/
1096 
p_netSend(CELL * params)1097 CELL * p_netSend(CELL * params)
1098 {
1099 UINT sock;
1100 size_t size, size2;
1101 char * buffer;
1102 ssize_t bytesSent;
1103 
1104 params = getInteger(params, &sock);
1105 params = getStringSize(params, &buffer, &size, TRUE);
1106 
1107 if(params->type != CELL_NIL)
1108     {
1109     getInteger(params, (UINT *)&size2);
1110     if(size2 < size) size = size2;
1111     }
1112 
1113 if((bytesSent = sendall((int)sock, buffer, size))  == SOCKET_ERROR)
1114     {
1115     deleteIOsession((int)sock);
1116     return(netError(ERR_INET_WRITE));
1117     }
1118 
1119 netErrorIdx = 0;
1120 return(stuffInteger(bytesSent));
1121 }
1122 
1123 
1124 #define SEND_TO_UDP 0
1125 #define SEND_TO_SOCK 1
1126 
netSendTo(CELL * params,int type)1127 CELL * netSendTo(CELL * params, int type)
1128 {
1129 char * remoteHost;
1130 UINT remotePort;
1131 struct sockaddr * destination;
1132 socklen_t destination_len;
1133 size_t size;
1134 char * buffer;
1135 ssize_t bytesSent;
1136 UINT sock;
1137 /* char one = 1; */
1138 int one = 1;
1139 
1140 params = getString(params, &remoteHost);
1141 params = getInteger(params, &remotePort);
1142 params = getStringSize(params, &buffer, &size, TRUE);
1143 
1144 destination_len = (ADDR_FAMILY == AF_INET6) ?
1145         sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
1146 destination = alloca(destination_len);
1147 
1148 if(*remoteHost != 0) /* 10.0.1 */
1149     {
1150     if(getHostAddr(destination, 0, remoteHost) != 0)
1151         return(netError(ERR_INET_HOST_UNKNOWN));
1152     setSockaddrPort(destination, remotePort);
1153     }
1154 
1155 if(type == SEND_TO_UDP) /* for 'net-send-udp' */
1156     {
1157     if((sock = socket(ADDR_FAMILY, SOCK_DGRAM, 0)) == INVALID_SOCKET)
1158         return(netError(ERR_INET_OPEN_SOCKET));
1159 
1160      if(getFlag(params))
1161         setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const void *)&one, sizeof(one));
1162     }
1163 else /* SEND_TO_SOCK , socket may or may not be UDP, for 'net-send-to' */
1164     {
1165     params = getInteger(params, &sock);
1166     }
1167 
1168 
1169 /* for socket opened with ip-address in (net-connect host port "udp")
1170    in this case issue (net-send-to "" port message socket) 10.0.1 */
1171 if(*remoteHost == 0)
1172     bytesSent = sendto((int)sock, buffer, size, NO_FLAGS_SET, NULL, 0);
1173 else
1174     bytesSent = sendto((int)sock, buffer, size, NO_FLAGS_SET,
1175         (struct sockaddr *)destination, destination_len);
1176 
1177 if(type == SEND_TO_UDP) close((int)sock);
1178 
1179 if(bytesSent == SOCKET_ERROR)
1180         return(netError(ERR_INET_WRITE));
1181 
1182 netErrorIdx = 0;
1183 return(stuffInteger(bytesSent));
1184 }
1185 
1186 
p_netSendUDP(CELL * params)1187 CELL * p_netSendUDP(CELL * params)
1188 {
1189 return(netSendTo(params, SEND_TO_UDP));
1190 }
1191 
1192 
p_netSendTo(CELL * params)1193 CELL * p_netSendTo(CELL * params)
1194 {
1195 return(netSendTo(params, SEND_TO_SOCK));
1196 }
1197 
1198 
1199 /************************* listen **************************************/
1200 
p_netListen(CELL * params)1201 CELL * p_netListen(CELL * params)
1202 {
1203 UINT portNo;
1204 char * ifAddr = NULL;
1205 char * option = NULL;
1206 char * mcAddr = NULL;
1207 int sock, type;
1208 int sockopt = 0;
1209 int opt;
1210 CELL * cell;
1211 
1212 type = SOCK_STREAM;
1213 cell = evaluateExpression(params);
1214 params = params->next;
1215 
1216 #ifndef WINDOWS
1217 if(cell->type == CELL_STRING)
1218     {
1219     if((sock = netListenLocal((char *)cell->contents)) == SOCKET_ERROR)
1220         return(netError(netErrorIdx));
1221     else
1222         return(stuffInteger((UINT)sock));
1223     }
1224 #endif
1225 
1226 getIntegerExt(cell, &portNo, FALSE);
1227 
1228 if(params != nilCell)
1229     {
1230     params = getString(params, &ifAddr);
1231     if(*ifAddr == 0) ifAddr = NULL;
1232     if(params != nilCell)
1233         {
1234         params = getString(params, &option);
1235         opt = toupper(*option);
1236         if(opt == 'U')
1237             type = SOCK_DGRAM;
1238 #ifndef WINDOWS
1239         else if(opt == 'D')
1240             {
1241             type = SOCK_RAW;
1242             sockopt = IPPROTO_DIVERT;
1243             }
1244 #endif
1245         else if(opt == 'M')
1246             {
1247             type = SOCK_DGRAM;
1248             mcAddr = ifAddr;
1249             ifAddr = NULL;
1250             }
1251         else
1252             errorProc(ERR_INVALID_OPTION);
1253         }
1254 
1255     }
1256 
1257 
1258 if((sock = netListenOrDatagram((int)portNo, type, ifAddr, mcAddr, sockopt))
1259         == SOCKET_ERROR)
1260     return(nilCell);
1261 
1262 return(stuffInteger(sock));
1263 }
1264 
1265 #ifndef WINDOWS
netListenLocal(char * name)1266 int netListenLocal(char * name)
1267 {
1268 int sock;
1269 struct sockaddr_un local_sun;
1270 
1271 sock  = socket(AF_UNIX, SOCK_STREAM, 0);
1272 local_sun.sun_family = AF_UNIX;
1273 strncpy(local_sun.sun_path, name, sizeof(local_sun.sun_path) - 1);
1274 local_sun.sun_path[sizeof (local_sun.sun_path) - 1] = '\0';
1275 unlink(local_sun.sun_path);
1276 
1277 #ifdef OS2
1278 if(bind(sock, (struct sockaddr *)&local_sun, sizeof(struct sockaddr_un)) == -1)
1279 #else
1280 if(bind(sock, (struct sockaddr *)&local_sun, SUN_LEN(&local_sun)) != 0)
1281 #endif
1282     {
1283     close(sock);
1284     netErrorIdx = ERR_INET_CANNOT_BIND;
1285     return(SOCKET_ERROR);
1286     }
1287 
1288 if(listen(sock, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
1289     {
1290     close(sock);
1291     netErrorIdx = ERR_INET_LISTEN_FAILED;
1292     return(SOCKET_ERROR);
1293     }
1294 
1295 createIOsession(sock, AF_UNIX);
1296 
1297 netErrorIdx = 0;
1298 return(sock);
1299 }
1300 #endif
1301 
1302 
netListenOrDatagram(int portNo,int stype,char * ifAddr,char * mcAddr,int option)1303 int netListenOrDatagram(int portNo, int stype, char * ifAddr, char * mcAddr, int option)
1304 {
1305 int sock, one = 1;
1306 struct sockaddr * local;
1307 struct ip_mreq mcast;
1308 socklen_t local_len;
1309 
1310 if((sock = socket(ADDR_FAMILY, stype, option)) == INVALID_SOCKET)
1311     {
1312     netErrorIdx = ERR_INET_OPEN_SOCKET;
1313     return SOCKET_ERROR;
1314     }
1315 
1316 local_len = (ADDR_FAMILY == AF_INET6) ?
1317     sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
1318 local = alloca(local_len);
1319 memset(local, 0, local_len);
1320 
1321 if(getHostAddr((struct sockaddr *)local, stype, ifAddr) != 0)
1322     return(SOCKET_ERROR);
1323 
1324 setSockaddrPort(local, portNo);
1325 
1326 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void*)&one, sizeof(one));
1327 
1328 if(bind(sock, (struct sockaddr *)local, local_len) == SOCKET_ERROR)
1329     {
1330     close(sock);
1331     netErrorIdx = ERR_INET_CANNOT_BIND;
1332     return(SOCKET_ERROR);
1333     }
1334 
1335 if(mcAddr != NULL)
1336     {
1337     memset(&mcast, 0, sizeof(mcast));
1338     mcast.imr_multiaddr.s_addr = inet_addr(mcAddr);
1339     if(ADDR_FAMILY == AF_INET)
1340         mcast.imr_interface.s_addr = INADDR_ANY;
1341 /* not handled/debugged
1342     else
1343         mcast.imr_interface.s_addr = IN6ADDR_ANY_INIT;
1344 */
1345     setsockopt(sock, 0, IP_ADD_MEMBERSHIP, (const void *)&mcast, sizeof(mcast));
1346     }
1347 
1348 if(stype == SOCK_STREAM)
1349     {
1350     if(listen(sock, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
1351         {
1352         close(sock);
1353         netErrorIdx = ERR_INET_LISTEN_FAILED;
1354         return(SOCKET_ERROR);
1355         }
1356     }
1357 
1358 createIOsession(sock, ADDR_FAMILY);
1359 
1360 netErrorIdx = 0;
1361 return(sock);
1362 }
1363 
1364 
1365 /* returns number of bytes ready to read */
p_netPeek(CELL * params)1366 CELL * p_netPeek(CELL * params)
1367 {
1368 UINT sock;
1369 #ifdef WINDOWS
1370 u_long result;
1371 #else
1372 int result;
1373 #endif
1374 
1375 getInteger(params, &sock);
1376 
1377 if(ioctl((int)sock, FIONREAD, &result) == SOCKET_ERROR)
1378     return(netError(ERR_INET_PEEK_FAILED));
1379 
1380 netErrorIdx = 0;
1381 return(stuffInteger((UINT)result));
1382 }
1383 
1384 
1385 typedef struct
1386     {
1387     int sock;
1388     void * next;
1389     } SOCKLIST;
1390 
1391 
1392 /* checks a socket for readability/writeability  */
p_netSelect(CELL * params)1393 CELL * p_netSelect(CELL * params)
1394 {
1395 INT64 wait;
1396 char * mode;
1397 struct timeval timeOut;
1398 fd_set socketSet;
1399 CELL * cell;
1400 CELL * list;
1401 CELL * sockListHead = NULL;
1402 CELL * sockListPtr;
1403 struct timeval* tmvPtr;
1404 UINT socket;
1405 int setSize = 0;
1406 
1407 netErrorIdx = 0;
1408 
1409 FD_ZERO(&socketSet);
1410 
1411 cell = evaluateExpression(params);
1412 if(isNumber(cell->type))
1413     getIntegerExt(cell, (UINT*)&socket, FALSE);
1414 else if(isList(cell->type))
1415     {
1416     cell = (CELL*)cell->contents;
1417     sockListHead = cell;
1418     while(cell != nilCell)
1419         {
1420         cell = getIntegerExt(cell, (UINT*)&socket, FALSE);
1421         if(setSize == FD_SETSIZE)
1422             return(netError(ERR_INET_TOO_MUCH_SOCKETS));
1423         else setSize++;
1424         FD_SET((int)socket, &socketSet);
1425         }
1426     }
1427 else return(errorProcExt(ERR_LIST_OR_NUMBER_EXPECTED, params));
1428 
1429 params = getString(params->next, &mode);
1430 getInteger64Ext(params, &wait, TRUE);
1431 
1432 tmvPtr = (wait == -1) ? NULL : &timeOut;
1433 timeOut.tv_sec = wait/1000000;
1434 timeOut.tv_usec = wait - timeOut.tv_sec * 1000000;
1435 
1436 if(sockListHead == NULL)
1437     FD_SET((int)socket, &socketSet);
1438 
1439 /* printf("%d %d %d\n", timeOut.tv_sec, timeOut.tv_usec, sizeof(timeOut.tv_sec));  */
1440 
1441 if(*mode == 'r')
1442     setSize = select(FD_SETSIZE, &socketSet, NULL, NULL, tmvPtr);
1443 else if(*mode == 'w')
1444     setSize = select(FD_SETSIZE, NULL, &socketSet, NULL, tmvPtr);
1445 else if(*mode == 'e')
1446     setSize = select(FD_SETSIZE, NULL, NULL, &socketSet, tmvPtr);
1447 else return(errorProcExt2(ERR_INVALID_PARAMETER, stuffString(mode)));
1448 
1449 if(setSize >= 0)
1450     {
1451     if(sockListHead == NULL)
1452         {
1453         if(setSize == 0) return(nilCell);
1454         else return(trueCell);
1455         }
1456 
1457     list = getCell(CELL_EXPRESSION);
1458     if(setSize == 0) return(list);
1459 
1460     sockListPtr = sockListHead;
1461     while(sockListPtr != nilCell)
1462         {
1463         sockListPtr = getIntegerExt(sockListPtr, &socket, FALSE);
1464         /* printf("testing %lu\n", socket); */
1465         if(FD_ISSET(socket, &socketSet))
1466             {
1467             addList(list, stuffInteger(socket));
1468             /* printf("adding %lu\n", socket); */
1469             }
1470         }
1471 
1472     return(list);
1473     }
1474 
1475 netError(ERR_INET_SELECT_FAILED);
1476 
1477 return(nilCell);
1478 }
1479 
1480 extern char logFile[];
1481 
writeLog(char * text,int newLine)1482 void writeLog(char * text, int newLine)
1483 {
1484 int handle;
1485 
1486 
1487 #ifdef WINDOWS
1488 handle = open(logFile, O_RDWR | O_APPEND | O_BINARY | O_CREAT, S_IREAD | S_IWRITE);
1489 #else
1490 handle = open(logFile, O_RDWR | O_APPEND | O_BINARY | O_CREAT,
1491           S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); /* rw-rw-rw */
1492 #endif
1493 
1494 if(write(handle, text, strlen(text)) < 0) return;
1495 if(newLine)
1496     if(write(handle, &LINE_FEED, LINE_FEED_LEN) < 0) return;
1497 #ifdef WINDOWS
1498 _close(handle);
1499 #else
1500 close(handle);
1501 #endif
1502 }
1503 
1504 FILE * win_fdopen(int handle, const char * mode);
1505 
serverFD(int port,char * domain,int reconnect)1506 FILE * serverFD(int port, char * domain, int reconnect)
1507 {
1508 static int sock, connection;
1509 char name[STRADDR_LEN];
1510 char text[80];
1511 time_t t;
1512 
1513 text[79] = 0;
1514 
1515 if(!reconnect)
1516     {
1517 #ifndef WINDOWS
1518     if(port != 0)
1519         sock = netListenOrDatagram(port, SOCK_STREAM, NULL, NULL, 0);
1520     else
1521         sock = netListenLocal(domain);
1522 #else
1523     sock = netListenOrDatagram(port, SOCK_STREAM, NULL, NULL, 0);
1524 #endif
1525 
1526     if(sock == SOCKET_ERROR) return(NULL);
1527     else {
1528         snprintf(text, 79, "newLISP v.%d listening on %s", version, domain);
1529         writeLog(text, TRUE);
1530         }
1531     }
1532 else
1533     {
1534     deleteIOsession(connection);
1535     }
1536 
1537 if((connection = netAccept(sock)) == SOCKET_ERROR)
1538     return NULL;
1539 
1540 /* avoid registering socket twice */
1541 if(!isSessionSocket(connection))
1542     createIOsession(connection, (port != 0) ? ADDR_FAMILY : AF_UNIX);
1543 
1544 /* print log */
1545 getIpPortFromSocket(connection, PEER_INFO, name);
1546 t = time(NULL);
1547 snprintf(text, 79, "Connected to %s on %s", name, ctime(&t));
1548 /* printf(text); */
1549 writeLog(text, 0);
1550 
1551 setenv("REMOTE_ADDR", name, 1);
1552 
1553 return(fdopen(connection, "r+"));
1554 }
1555 
1556 /******************************* distributed computing ***********************/
1557 
1558 
1559 #define MAX_BUFF 1024
1560 CELL * netEvalError(int errNo);
1561 
1562 typedef struct
1563     {
1564     char * host;
1565     int port;
1566     int sock;
1567     int timeOut;
1568     STREAM * netStream;
1569     CELL * result;
1570     void * next;
1571     } NETEVAL;
1572 
1573 void freeSessions(NETEVAL * base);
1574 
p_netEval(CELL * params)1575 CELL * p_netEval(CELL * params)
1576 {
1577 CELL * cell = NULL;
1578 CELL * list = NULL;
1579 NETEVAL * session = NULL;
1580 NETEVAL * base = NULL;
1581 char * host;
1582 char * prog;
1583 UINT port;
1584 int ready;
1585 int sock;
1586 size_t size, count = 0;
1587 ssize_t bytes;
1588 INT timeOut = 60000; /* milli secs */
1589 int start, elapsed = 0;
1590 CELL * result;
1591 STREAM * netStream;
1592 CELL * netEvalIdle = NULL;
1593 char buffer[MAX_BUFF];
1594 int rawMode = FALSE;
1595 int singleSession = FALSE;
1596 jmp_buf errorJumpSave;
1597 int errNo;
1598 UINT * resultStackIdxSave;
1599 
1600 list  = evaluateExpression(params);
1601 if(list->type == CELL_STRING)
1602     {
1603     host = (char *)list->contents;
1604     params = getIntegerExt(params->next, &port, TRUE);
1605     /* params = getStringSize(params, &prog, &size, TRUE); */
1606     /* convert to string if required (since 10.1.1) */
1607     prog = cellToString(evaluateExpression(params), &size, FALSE);
1608     params = params->next;
1609     list = nilCell;
1610     singleSession = TRUE;
1611     goto SINGLE_SESSION;
1612     }
1613 else if(list->type == CELL_EXPRESSION)
1614     {
1615     list = (CELL*)list->contents;
1616     params = params->next;
1617     }
1618 else return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
1619 
1620 CREATE_SESSION:
1621 if(!isList(list->type))
1622     return(errorProcExt(ERR_LIST_EXPECTED, list));
1623 cell = (CELL *)list->contents;
1624 
1625 /* get node parameters, since 8.9.8 evaluated */
1626 memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
1627 if((errNo = setjmp(errorJump)) != 0)
1628     {
1629     memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1630     freeSessions(base);
1631     longjmp(errorJump, errNo);
1632     }
1633 cell = getStringSize(cell, &host, &size, TRUE);
1634 cell = getInteger(cell, &port);
1635 prog = cellToString(evaluateExpression(cell), &size, FALSE);
1636 rawMode = getFlag(cell->next);
1637 
1638 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1639 
1640 SINGLE_SESSION:
1641 if(base == NULL)
1642     {
1643     base = session = allocMemory(sizeof(NETEVAL));
1644     memset(base, 0, sizeof(NETEVAL));
1645     }
1646 else
1647     {
1648     session->next = allocMemory(sizeof(NETEVAL));
1649     session = session->next;
1650     memset(session, 0, sizeof(NETEVAL));
1651     }
1652 
1653 /* timeout for making connection is always 15 secs,
1654    but variable timeOut is used during connection */
1655 #ifndef WINDOWS
1656 if(port != 0)
1657     sock = netConnect(host, (int)port, SOCK_STREAM, 0, 15000);
1658 else
1659     sock = netConnectLocal(host);
1660 #else
1661 sock = netConnect(host, (int)port, SOCK_STREAM, 0, 15000);
1662 #endif
1663 
1664 if(sock == SOCKET_ERROR)
1665         {
1666         session->result = netEvalError(netErrorIdx);
1667         goto CONTINUE_CREATE_SESSION;
1668         }
1669 
1670 session->host = host;
1671 session->port = port;
1672 session->sock = sock;
1673 
1674 if( sendall(sock, "[cmd]\n", 6)  == SOCKET_ERROR ||
1675     sendall(sock, prog, size) == SOCKET_ERROR ||
1676     sendall(sock, "(exit)\n[/cmd]\n", 14) == SOCKET_ERROR )
1677     {
1678     close(sock);
1679     session->result = netEvalError(ERR_INET_WRITE);
1680     goto CONTINUE_CREATE_SESSION;
1681     }
1682 
1683 session->netStream = (void *)allocMemory(sizeof(STREAM));
1684 memset(session->netStream, 0, sizeof(STREAM));
1685 openStrStream(session->netStream, MAX_BUFF, 0);
1686 createIOsession(sock, ADDR_FAMILY);
1687 count++;
1688 CONTINUE_CREATE_SESSION:
1689 list = list->next;
1690 if(list != nilCell) goto CREATE_SESSION;
1691 
1692 /* get timeout ms and optional handler symbol
1693    this is the timeout after connections  are made
1694    waiting for the result to come back */
1695 session = base;
1696 if(params != nilCell)
1697     params = getInteger(params, (UINT *)&timeOut);
1698 if(params != nilCell)
1699     netEvalIdle = params;
1700 
1701 /* printf("timeout %d idle-loop %X\n", timeOut, netEvalIdle); */
1702 
1703 /* collect data from host in each active session */
1704 
1705 while(count)
1706     {
1707     resultStackIdxSave = resultStackIdx;
1708     if( (netStream = session->netStream) == NULL)
1709         {
1710         session = session->next;
1711         if(session == NULL) session = base;
1712         continue;
1713         }
1714 
1715     start = milliSecTime();
1716 
1717     if(netEvalIdle)
1718         {
1719         cell = makeCell(CELL_EXPRESSION, (UINT)copyCell(netEvalIdle));
1720 
1721         pushResult(cell);
1722         if(!evaluateExpressionSafe(cell, &errNo))
1723             {
1724             freeSessions(base);
1725             longjmp(errorJump, errNo);
1726             }
1727         }
1728 
1729     bytes = -1; errNo = 0;
1730     ready = wait_ready(session->sock, 100, READY_READ);
1731     if(ready > 0)
1732         {
1733         memset(buffer, 0, MAX_BUFF);
1734         bytes = recv(session->sock, buffer, MAX_BUFF, NO_FLAGS_SET);
1735 
1736 /*
1737         if(bytes >= 0) printf("bytes:%ld=>%s<=\n", bytes, buffer);
1738 */
1739         if(bytes)
1740             {
1741 	    if(bytes == -1) bytes = 0;
1742             errNo = (memcmp(buffer, "\nERR: ", 6) == 0);
1743             writeStreamStr(netStream, buffer, bytes);
1744             }
1745         }
1746     if(ready < 0 || bytes == 0 || errNo || elapsed >= timeOut)
1747         {
1748 /*
1749         printf("count=%ld ready=%d bytes=%ld elapsed=%d\n", count, ready, bytes, elapsed);
1750 */
1751         if(elapsed >= timeOut) result = copyCell(nilCell);
1752         else if(rawMode || errNo) /* get raw buffer without the quote */
1753             result = stuffStringN(netStream->buffer, netStream->position);
1754         else
1755             {
1756             memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
1757             if((errNo = setjmp(errorJump)) != 0)
1758                 {
1759                 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1760                 freeSessions(base);
1761                 longjmp(errorJump, errNo);
1762                 }
1763             /* Only one expression should be sent out by net-eval. When contained
1764                in a string more than one can be sent out and will be evaluated,
1765                burt net-eval will only return the result of the last(10.6.3) one */
1766             result = sysEvalString(netStream->buffer, currentContext, nilCell, READ_EXPR_NET);
1767             /* changed from READ_EXPR+SYNC to READ_EXPR in 10.6.3 */
1768             memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1769             }
1770 
1771         if(netEvalIdle)
1772             {
1773             session->result = cell = makeCell(CELL_EXPRESSION, (UINT)stuffString(session->host));
1774 
1775             cell = (CELL *)cell->contents;
1776             cell->next = stuffInteger(session->port);
1777             cell = cell->next;
1778             cell->next = result;
1779             }
1780         else
1781             session->result = result;
1782 
1783         closeStrStream(netStream);
1784         deleteIOsession(session->sock);
1785         free(netStream);
1786         session->netStream = NULL;
1787 
1788         if(netEvalIdle)
1789             {
1790             list = makeCell(CELL_EXPRESSION, (UINT)copyCell(netEvalIdle));
1791             cell = makeCell(CELL_QUOTE, (UINT)session->result);
1792 
1793             ((CELL*)list->contents)->next = cell;
1794             pushResult(list);
1795             if(!evaluateExpressionSafe(list, &errNo))
1796                 {
1797                 freeSessions(base);
1798                 longjmp(errorJump, errNo);
1799                 }
1800             }
1801 
1802         count--;
1803         }
1804 
1805     /* check for rollover at midnight */
1806     if(milliSecTime() >= start)
1807         elapsed += milliSecTime() - start;
1808     else
1809         elapsed += milliSecTime();
1810 
1811     session = session->next;
1812     if(session == NULL) session = base;
1813 
1814     cleanupResults(resultStackIdxSave);
1815     }
1816 
1817 /* free all sessions and configure result */
1818 result = NULL;
1819 while(base != NULL)
1820     {
1821     if(netEvalIdle == NULL)
1822         {
1823         if(result == NULL)
1824             {
1825             if(singleSession)
1826                 result = base->result;
1827             else
1828                 {
1829                 result = makeCell(CELL_EXPRESSION, (UINT)base->result);
1830                 cell = base->result;
1831                 }
1832             }
1833         else
1834             {
1835             cell->next = base->result;
1836             cell = cell->next;
1837             }
1838         }
1839     session = base;
1840     base = base->next;
1841     free(session);
1842     }
1843 
1844 if(elapsed > timeOut)
1845     netErrorIdx = ERR_INET_TIMEOUT;
1846 else netErrorIdx = 0;
1847 if(netEvalIdle == NULL) return(result);
1848 return(trueCell);
1849 }
1850 
1851 
freeSessions(NETEVAL * base)1852 void freeSessions(NETEVAL * base)
1853 {
1854 NETEVAL * session;
1855 
1856 while(base != NULL)
1857     {
1858     if(base->netStream != NULL)
1859         {
1860         if(base->result != NULL)
1861           deleteList(base->result);
1862         closeStrStream(base->netStream);
1863         deleteIOsession(base->sock);
1864         free(base->netStream);
1865         base->netStream = NULL;
1866         }
1867     session = base;
1868     base = base->next;
1869     free(session);
1870     }
1871 }
1872 
sendall(int sock,char * buffer,int len)1873 int sendall(int sock, char * buffer, int len)
1874 {
1875 int bytesSend = 0;
1876 int n;
1877 
1878 while(bytesSend < len)
1879     {
1880     if((n = send(sock, buffer + bytesSend, len - bytesSend, NO_FLAGS_SET)) == SOCKET_ERROR)
1881         return(SOCKET_ERROR);
1882     bytesSend += n;
1883     }
1884 
1885 return(bytesSend);
1886 }
1887 
1888 /*********************** error handling ***************************************/
1889 
1890 char * netErrorMsg[] =
1891     {
1892     "No error",
1893     "Cannot open socket",
1894     "DNS resolution failed",
1895     "Not a valid service",
1896     "Connection failed",
1897     "Accept failed",
1898     "Connection closed",
1899     "Connection broken",
1900     "Socket recv failed",
1901     "Socket send failed",
1902     "Cannot bind socket",
1903     "Too many sockets",
1904     "Listen failed",
1905     "Badly formed IP",
1906     "Select failed",
1907     "Peek failed",
1908     "Not a valid socket",
1909     "Cannot block or unblock socket",
1910     "Operation timed out",
1911 /* for nl-web.c */
1912     "HTTP bad formed URL",
1913     "HTTP file operation failed",
1914     "HTTP transfer failed",
1915     "HTTP invalid response from server",
1916     "HTTP no response from server",
1917     "HTTP not content",
1918     "HTTP error in header",
1919     "HTTP error in chunked format"
1920     };
1921 
1922 
netError(int errorNo)1923 CELL * netError(int errorNo)
1924 {
1925 netErrorIdx = errorNo;
1926 return(nilCell);
1927 }
1928 
netEvalError(int errorNo)1929 CELL * netEvalError(int errorNo)
1930 {
1931 netErrorIdx = errorNo;
1932 return(p_netLastError(nilCell));
1933 }
1934 
p_netLastError(CELL * params)1935 CELL * p_netLastError(CELL * params)
1936 {
1937 CELL * result;
1938 char str[40];
1939 UINT numError = netErrorIdx;
1940 
1941 if(params != nilCell)
1942     getInteger(params, &numError);
1943 else
1944     if(numError == 0) return(nilCell);
1945 
1946 result = makeCell(CELL_EXPRESSION, (UINT)stuffInteger(numError));
1947 
1948 snprintf(str, 40, "%s", (numError > MAX_NET_ERROR) ? UNKNOWN_ERROR : netErrorMsg[numError]);
1949 ((CELL *)result->contents)->next = stuffString(str);
1950 
1951 return(result);
1952 }
1953 
1954 #ifndef NO_NET_PING
1955 /* net-ping
1956 
1957    Undocumented boolean flag parameter (after count) puts error info
1958    into the result list when a packet could not be sent.
1959 */
1960 
p_netPing(CELL * params)1961 CELL * p_netPing(CELL * params)
1962 {
1963 CELL * address;
1964 UINT maxwait = 1000, listmode = 0;
1965 UINT flag = 0;
1966 UINT count = 0;
1967 
1968 params = getEvalDefault(params, &address);
1969 if(address->type == CELL_EXPRESSION)
1970     {
1971     address = (CELL *)address->contents;
1972     listmode = 1;
1973     }
1974 else if(address->type != CELL_STRING)
1975   return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, address));
1976 
1977 if(params != nilCell)
1978     {
1979     params = getInteger(params, &maxwait);
1980     if(params != nilCell)
1981         params = getInteger(params, &count);
1982     flag = getFlag(params);
1983     }
1984 
1985 return(ping(address, (int)maxwait, (int)listmode, (int)count, (int)flag));
1986 }
1987 
1988 #define PLEN 64
1989 
ping(CELL * address,int maxwait,int listmode,int maxCount,int flag)1990 CELL * ping(CELL * address, int maxwait, int listmode, int maxCount, int flag)
1991 {
1992 char * host;
1993 char * ptr;
1994 char * hostaddr = NULL;
1995 unsigned char packet[PLEN];
1996 struct ip *ip;
1997 char IPaddress[STRADDR_LEN];
1998 struct icmp6_filter filter;
1999 struct icmp6_hdr *icp6 = (struct icmp6_hdr *) packet;
2000 struct icmp *icp = (struct icmp *) packet;
2001 struct sockaddr * whereto;
2002 struct sockaddr * from;
2003 int s;
2004 int sockopt = 1;
2005 #ifdef TRU64
2006 unsigned long sockaddr_len;
2007 #else
2008 #ifdef OS2
2009 int sockaddr_len;
2010 #else
2011 socklen_t sockaddr_len;
2012 #endif
2013 #endif
2014 int broadcast = 0;
2015 int size, ipNo, startIp = 0, endIp = 0;
2016 int timeout = 0, tdiff;
2017 int sendCount = 0, receiveCount = 0;
2018 ssize_t len;
2019 struct timeval tv, tp;
2020 CELL * result = NULL;
2021 CELL * link = NULL;
2022 char buff[64];
2023 
2024 #ifdef MAC_OSX /* no superuser rights necessary */
2025 if ((s = socket(ADDR_FAMILY, SOCK_DGRAM, ICMP_TYPE)) < 0)
2026 #else
2027 if ((s = socket(ADDR_FAMILY, SOCK_RAW, ICMP_TYPE)) < 0)
2028 #endif
2029     return(netError(ERR_INET_OPEN_SOCKET));
2030 
2031 sockaddr_len = (ADDR_FAMILY == AF_INET6) ?
2032     sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
2033 
2034 whereto = alloca(sockaddr_len);
2035 from = alloca(sockaddr_len);
2036 
2037 if(ADDR_FAMILY == AF_INET6)
2038     {
2039     ICMP6_FILTER_SETPASSALL (&filter);
2040     setsockopt (s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter));
2041     }
2042 
2043 gettimeofday(&tv, NULL );
2044 
2045 /* for each list-IP */
2046 while(address != nilCell)
2047     {
2048     mySleep(1);
2049     if(address->type != CELL_STRING)
2050         {
2051         shutdown(s, SHUT_RDWR);
2052         return(errorProcExt(ERR_STRING_EXPECTED, address));
2053         }
2054 
2055     host = (char *)address->contents;
2056     len = address->aux - 1;
2057 
2058     if(ADDR_FAMILY == AF_INET) /* IPv4 */
2059         {
2060         if(strncmp(host + len - 2, ".*", 2) == 0)
2061             {
2062             startIp = 1;
2063             endIp = 254;
2064             len--;
2065             }
2066         else
2067             {
2068             startIp = endIp = 0;
2069             ptr = host + len - 1;
2070             while(isdigit((int)*ptr)) --ptr;
2071             if(*ptr == '-')
2072                 {
2073                 endIp = atoi(ptr + 1);
2074                 --ptr;
2075                 while(isdigit((int)*ptr)) --ptr;
2076                 if(*ptr == '.')
2077                     {
2078                     startIp = atoi(ptr + 1);
2079                     len = ptr - host + 1;
2080                     }
2081                 else endIp = startIp = 0;
2082                 if(endIp < startIp) endIp = startIp;
2083                 if(endIp > 254) endIp = 254;
2084                 }
2085             }
2086         }
2087 
2088     /* ping ip range */
2089     for(ipNo = startIp; ipNo <= endIp; ipNo++)
2090         {
2091         if(startIp)
2092             {
2093             if(hostaddr == NULL) hostaddr = alloca(len + 4);
2094             memcpy(hostaddr, host, len);
2095             snprintf(hostaddr + len, 4, "%d", ipNo);
2096             }
2097         else
2098             hostaddr = host;
2099 
2100         /* target host address info */
2101         /* printf("->%s\n", hostaddr); */
2102 
2103         memset((char *)whereto, 0, sockaddr_len);
2104 #ifdef  MAC_OSX
2105         if(getHostAddr(whereto, SOCK_DGRAM, hostaddr) != 0)
2106 #else
2107         if(getHostAddr(whereto, SOCK_RAW, hostaddr) != 0)
2108 #endif
2109             {
2110             shutdown(s, SHUT_RDWR);
2111             return(netError(ERR_INET_HOST_UNKNOWN));
2112             }
2113 
2114         if(ADDR_FAMILY == AF_INET6)
2115             setSockaddrPort(whereto, htons(IPPROTO_ICMPV6));
2116         else if((broadcast = (strncmp(host + len - 4, ".255", 4) == 0)))
2117             setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &sockopt, sizeof(sockopt));
2118 
2119         /* ping setup ICMP packet */
2120         if(ADDR_FAMILY == AF_INET6)
2121             {
2122             memset(icp6, 0, PLEN);
2123             icp6->icmp6_type = ICMP6_ECHO_REQUEST;
2124             icp6->icmp6_id = getpid() & 0xFFFF;
2125             gettimeofday((struct timeval *)&icp6->icmp6_data8[4], NULL);
2126             }
2127         else
2128             {
2129             memset(icp, 0, PLEN);
2130             icp->icmp_type = ICMP_ECHO;
2131             icp->icmp_id = getpid() & 0xFFFF;
2132             gettimeofday((struct timeval *)&icp[1], NULL);
2133             icp->icmp_cksum = in_cksum((unsigned short *) icp, PLEN );
2134             }
2135 
2136         while(wait_ready(s, 10000, READY_WRITE) <= 0)
2137             {
2138             gettimeofday(&tp, NULL);
2139             if((timeout = (timediff_ms(tp, tv) > maxwait))) break;
2140             continue;
2141             }
2142 
2143         /* ping */
2144         size = sendto(s, packet, PLEN, 0,(struct sockaddr *)whereto, sockaddr_len);
2145         if(size != PLEN)
2146             {
2147             if(flag)
2148                 {
2149                 snprintf(buff, 64, "%s", strerror(errno));
2150                 ipstrFromSockAddr((struct sockaddr *)whereto, IPaddress, STRADDR_LEN);
2151                 link = addResult(&result, link,
2152                     makePair(stuffString(IPaddress), stuffString(buff)));
2153                 }
2154             if( !(listmode || startIp) ) break;
2155             continue;
2156             }
2157 
2158         sendCount++;
2159         }
2160     if(!listmode) break;
2161     address = address->next;
2162     }
2163 
2164 /* wait for response(s) */
2165 if(maxCount == 0) maxCount = sendCount;
2166 while(sendCount)
2167     {
2168 
2169     if(wait_ready(s, 1000, READY_READ) <= 0)
2170         {
2171         gettimeofday(&tp, NULL);
2172         if((timeout = (timediff_ms(tp, tv) > maxwait))) break;
2173         continue;
2174         }
2175 
2176     memset(packet, 0, PLEN);
2177     memset(from, 0, sockaddr_len);
2178     if ( (len = recvfrom(s, packet, PLEN, 0, (struct sockaddr *)from,
2179                         (socklen_t *)&sockaddr_len)) < 0)
2180         continue;
2181 
2182     ip = (struct ip *) packet;
2183     gettimeofday(&tp, NULL);
2184 
2185     if(ADDR_FAMILY == AF_INET6)
2186         {
2187         icp6 = (struct icmp6_hdr *)packet;
2188         if(icp6->icmp6_type != ICMP6_ECHO_REPLY) continue;
2189         if(icp6->icmp6_id != (getpid() & 0xFFFF)) continue;
2190         tdiff = timediff64_us(tp, *(struct timeval *)&icp6->icmp6_data8[4]);
2191         }
2192     else
2193         {
2194         icp = (struct icmp *)(packet + (ip->ip_hl << 2));
2195         if(icp->icmp_id != (getpid() & 0xFFFF)) continue;
2196         tdiff = timediff64_us(tp, *(struct timeval *)&icp[1]);
2197         }
2198 
2199     ipstrFromSockAddr((struct sockaddr *)from, IPaddress, STRADDR_LEN);
2200     link = addResult(&result, link,
2201             makePair(stuffString(IPaddress), stuffInteger(tdiff)));
2202 
2203     if(++receiveCount == maxCount) break;
2204     if( !(broadcast || listmode || startIp) ) break;
2205     }
2206 
2207 shutdown(s, SHUT_RDWR);
2208 
2209 if(timeout) netErrorIdx = ERR_INET_TIMEOUT;
2210 else netErrorIdx = 0;
2211 return(result == NULL ? getCell(CELL_EXPRESSION) : result);
2212 }
2213 
2214 
addResult(CELL ** result,CELL * cell,CELL * new)2215 CELL * addResult(CELL * * result, CELL * cell, CELL * new)
2216 {
2217 if(*result == NULL)
2218     *result = makeCell(CELL_EXPRESSION, (UINT)new);
2219 else
2220     cell->next = new;
2221 
2222 return(new);
2223 }
2224 
makePair(CELL * left,CELL * right)2225 CELL * makePair(CELL * left, CELL * right)
2226 {
2227 left->next = right;
2228 return(makeCell(CELL_EXPRESSION, (UINT)left));
2229 }
2230 
in_cksum(unsigned short * addr,int len)2231 unsigned short in_cksum(unsigned short * addr, int len)
2232 {
2233 int nleft = len;
2234 unsigned short *w = addr;
2235 unsigned short  answer;
2236 int sum = 0;
2237 
2238 while( nleft > 1 )  {
2239     sum += *w++;
2240     nleft -= 2;
2241     }
2242 
2243 if( nleft == 1 ) {
2244     u_short    u = 0;
2245     *(unsigned char *)(&u) = *(unsigned char *)w ;
2246     sum += u;
2247     }
2248 
2249 sum = (sum >> 16) + (sum & 0xffff);
2250 sum += (sum >> 16);
2251 answer = ~sum;
2252 return (answer);
2253 }
2254 
2255 #endif /* NO_NET_PING */
2256 
2257 
2258 /* check socket for readability or error
2259    return 0 if the time limit expires or -1
2260    on error
2261    tie limit in wait given in micro-secs
2262 */
wait_ready(int sock,INT64 wait_us,int mode)2263 int wait_ready(int sock, INT64 wait_us, int mode)
2264 {
2265 struct timeval timeOut;
2266 fd_set socketSet;
2267 
2268 FD_ZERO(&socketSet);
2269 FD_SET(sock, &socketSet);
2270 
2271 timeOut.tv_sec = wait_us/1000000;
2272 timeOut.tv_usec = wait_us - timeOut.tv_sec * 1000000;
2273 
2274 if(mode == READY_READ)
2275     return(select(sock + 1, &socketSet, NULL, NULL, &timeOut));
2276 else
2277     return(select(sock + 1, NULL, &socketSet, NULL, &timeOut));
2278 }
2279 
2280 
2281 /* ------------------------- raw sockets ---------------------------------------
2282 
2283    (net-packet packet)
2284 
2285    Checksums are only gnerated if set to zero in the packet.
2286 
2287    Packets start with the ip header followed by either a TCP, UDP or ICMP
2288    header and data.
2289 */
2290 
2291 /* for checksum calculation in TCP packets */
2292 struct pseudohdr
2293     {
2294     struct in_addr source_addr;
2295     struct in_addr dest_addr;
2296     unsigned char dummy;
2297     unsigned char protocol;
2298     unsigned short len;
2299     };
2300 
2301 
2302 #ifndef NO_NET_PACKET
2303 unsigned short pseudo_chks( struct ip * iph, char * packet, char * header, int data_offset);
2304 /* (net-packet str-packeA [int-config-flags]) */
2305 
p_netPacket(CELL * params)2306 CELL * p_netPacket(CELL * params)
2307 {
2308 char * packet;
2309 int sock;
2310 int one = 1;
2311 struct sockaddr_in dest_sin;
2312 size_t size;
2313 ssize_t bytesSent;
2314 struct ip * iph;
2315 struct tcphdr * tcph;
2316 struct udphdr * udph;
2317 struct icmp * icmph;
2318 int dport;
2319 /* ip_len  and ip_off must be check-summed in network order (big-Endian),
2320    but one or both must be given to the sendto() in host byte-order on
2321    some OS. As of 10.2.6 the following configFLags work for Mac OS X
2322    on PPC and Intel, Linux on Intel and OpenBSD on Intel.
2323 
2324    Curently net-packet is IPv4 only.
2325 */
2326 #if defined(MAC_OSX)
2327 UINT configFlags = 3; /* ntohs() for both ip_len and ip_off */
2328 #elif defined(LINUX)
2329 UINT configFlags = 1; /* ntohs() for ip_len only */
2330 #else /* works for OpenBSD */
2331 UINT configFlags = 0; /* none */
2332 #endif
2333 
2334 params = getStringSize(params, &packet, &size, TRUE);
2335 /* undocumented user-supplied extra configFlags parameter
2336    can have a value of 0,1,2,3
2337 */
2338 if(params != nilCell)
2339     getInteger(params, &configFlags);
2340 
2341 iph = (struct ip *)packet;
2342 
2343 if(iph->ip_sum == 0)
2344     iph->ip_sum = in_cksum((unsigned short *)iph, sizeof(struct ip));
2345 
2346 switch(iph->ip_p)
2347   {
2348   case IPPROTO_TCP:
2349     tcph = (struct tcphdr *)(packet + sizeof(struct ip));
2350 #ifdef ANDROID
2351     dport = tcph->dest;
2352     if(tcph->check == 0)
2353         tcph->check = pseudo_chks(iph, packet, (char *) tcph, tcph->doff * 4);
2354 #else
2355     dport = tcph->th_dport;
2356     if(tcph->th_sum == 0)
2357         tcph->th_sum = pseudo_chks(iph, packet, (char *) tcph, tcph->th_off * 4);
2358 #endif
2359     break;
2360   case IPPROTO_UDP:
2361     udph = (struct udphdr *)(packet + sizeof(struct ip));
2362     dport = udph->uh_dport;
2363     if(udph->uh_sum == 0)
2364         udph->uh_sum = pseudo_chks(iph, packet, (char *) udph, sizeof(struct udphdr));
2365     break;
2366   case IPPROTO_ICMP:
2367     icmph = (struct icmp *)(packet + sizeof(struct ip));
2368     dport = 0;
2369     if(icmph->icmp_cksum == 0)
2370     icmph->icmp_cksum = in_cksum((unsigned short *)icmph,
2371             ntohs(iph->ip_len) - iph->ip_hl * 4);
2372     break;
2373   default:
2374     return(nilCell);
2375   }
2376 
2377 if(configFlags & 0x1) iph->ip_len = ntohs(iph->ip_len);
2378 if(configFlags & 0x2) iph->ip_off = ntohs(iph->ip_off);
2379 
2380 memset(&dest_sin, 0, sizeof(dest_sin));
2381 dest_sin.sin_family = AF_INET;
2382 dest_sin.sin_port = dport;
2383 dest_sin.sin_addr = iph->ip_dst;
2384 
2385 if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
2386     return(netError(ERR_INET_OPEN_SOCKET));
2387 
2388 if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) < 0)
2389     return(netError(ERR_INET_OPEN_SOCKET));
2390 
2391 if((bytesSent = sendto(sock, packet, size, NO_FLAGS_SET,
2392         (struct sockaddr *)&dest_sin, sizeof(dest_sin))) != size)
2393     return(nilCell);
2394 
2395 return(stuffInteger(bytesSent));
2396 }
2397 
pseudo_chks(struct ip * iph,char * packet,char * header,int data_offset)2398 unsigned short pseudo_chks(
2399         struct ip * iph, char * packet, char * header, int data_offset)
2400 {
2401 /* packet was give with ip_len in net-work byte order */
2402 unsigned short checksum;
2403 int segment_len = ntohs(iph->ip_len) - iph->ip_hl * 4;
2404 int data_len = segment_len - data_offset;
2405 struct pseudohdr * pseudoh = alloca(sizeof(struct pseudohdr) + segment_len);
2406 
2407 pseudoh->source_addr = iph->ip_src;
2408 pseudoh->dest_addr = iph->ip_dst;
2409 pseudoh->dummy = 0;
2410 pseudoh->protocol = iph->ip_p;
2411 pseudoh->len = htons(segment_len);
2412 
2413 data_len = segment_len - data_offset;
2414 memcpy((char *)pseudoh + sizeof(struct pseudohdr), header, data_offset);
2415 memcpy((char *)pseudoh + sizeof(struct pseudohdr) + data_offset,
2416     packet + iph->ip_hl * 4 + data_offset, data_len);
2417 
2418 checksum = in_cksum((unsigned short *)pseudoh, sizeof(struct pseudohdr) + segment_len);
2419 #ifdef DEBUG
2420     printf("segment_len:%d\n", segment_len);
2421     printf("data_offset:%d\n", data_offset);
2422     printf("data_len:%d\n", data_len);
2423     printf("checksum:%x\n", ntohs(checksum));
2424 #endif
2425 return(checksum);
2426 }
2427 #endif /* NO_NET_PACKET */
2428 
2429 /* ------------------ socket->filestream stuff for windows ------------------------*/
2430 
2431 #ifdef WINDOWS
2432 extern int IOchannelIsSocketStream;
2433 
2434 /*
2435 These functions use the FILE structure to store the raw file handle in '->_file' and
2436 set ->_flag to 0xFFFF, to identify this as a faked FILE structure.
2437 Sinc 10.0.1 the IOchannelIsSocketStream flag is used to identify IOchannel as
2438 a fake file struct and extract the socket. Following win_fxxx routines
2439 are used to define fopen(), fclose(), fprintf(), fgetc() and fgets() in some *.c
2440 */
2441 
win_fdopen(int handle,const char * mode)2442 FILE * win_fdopen(int handle, const char * mode)
2443 {
2444 FILE * fPtr;
2445 
2446 if((fPtr = (FILE *)malloc(sizeof(FILE))) == NULL)
2447     return(NULL);
2448 
2449 memset(fPtr, 0, sizeof(FILE));
2450 
2451 fPtr->_file = handle;
2452 fPtr->_flag = 0xFFFF;
2453 
2454 return(fPtr);
2455 }
2456 
win_fclose(FILE * fPtr)2457 int win_fclose(FILE * fPtr)
2458 {
2459 if(IOchannelIsSocketStream)
2460    return(close(getSocket(fPtr)));
2461 
2462 return(fclose(fPtr));
2463 }
2464 
2465 
win_fprintf(FILE * fPtr,char * notused,char * buffer)2466 int win_fprintf(FILE * fPtr, char * notused, char * buffer)
2467 {
2468 int pSize;
2469 
2470 if(!IOchannelIsSocketStream)
2471     return(fprintf(fPtr, buffer));
2472 
2473 pSize = strlen(buffer);
2474 
2475 if((pSize = sendall(getSocket(fPtr), buffer, pSize)) == SOCKET_ERROR)
2476      {
2477      close(getSocket(fPtr));
2478      return(-1);
2479      }
2480 
2481 return(pSize);
2482 }
2483 
win_fgetc(FILE * fPtr)2484 int win_fgetc(FILE * fPtr)
2485 {
2486 char chr;
2487 
2488 if(!IOchannelIsSocketStream)
2489     return(fgetc(fPtr));
2490 
2491 if(recv(getSocket(fPtr), &chr, 1, NO_FLAGS_SET) <= 0)
2492     {
2493     close(getSocket(fPtr));
2494     return(-1);
2495     }
2496 
2497 return(chr);
2498 }
2499 
2500 
win_fgets(char * buffer,int size,FILE * fPtr)2501 char * win_fgets(char * buffer, int size, FILE * fPtr)
2502 {
2503 int bytesReceived = 0;
2504 char chr;
2505 
2506 if(!IOchannelIsSocketStream)
2507     return(fgets(buffer, size - 1, fPtr));
2508 
2509 while(bytesReceived < size)
2510     {
2511     if(recv(getSocket(fPtr), &chr, 1, NO_FLAGS_SET) <= 0)
2512         {
2513         close(getSocket(fPtr));
2514         return(NULL);
2515         }
2516 
2517     *(buffer + bytesReceived++) = chr;
2518 
2519     if(chr == '\n') break;
2520     }
2521 
2522 *(buffer + bytesReceived) = 0;
2523 
2524 return(buffer);
2525 }
2526 
2527 #endif /* WINDOWS */
2528 
2529 #else /* for EMSCRIPTEN define dummy writeLog() */
2530 
writeLog(char * text,int newLine)2531 void writeLog(char * text, int newLine) { return; }
2532 
2533 #endif /* ifndef EMSCRIPTEN */
2534 /* eof */
2535