Initial commit of newLISP.
[newlisp.git] / nl-sock.c
blob2fdcf0a47e589df866f066d6190258fc8398b52b
1 /* nl-sock.c
3 Copyright (C) 2008 Lutz Mueller
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.
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.
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/>.
19 /* this file is in the process of beeing ifdeffed to IPv6, but not completed yet
21 in the makefile_xxx add -DIPV6 in the CC compile flags
25 #ifdef IPV6
26 #define ADDR_TYPE AF_INET6
27 #define ICMP_TYPE IPPROTO_ICMPV6
28 #else
29 #define ADDR_TYPE AF_INET
30 #define ICMP_TYPE IPPROTO_ICMP
31 #endif
33 #include "newlisp.h"
34 #include <string.h>
36 #ifdef WIN_32
37 #include <winsock2.h>
38 #include <ws2tcpip.h>
39 #define fdopen win32_fdopen
40 #define SHUT_RDWR 2
41 #define gethostbyname2(A, B) gethostbyname(A)
42 #else
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/socket.h>
46 #include <sys/un.h>
47 #include <sys/ioctl.h>
48 #include <sys/wait.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/in.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_icmp.h>
53 #include <netinet/icmp6.h>
54 #include <netdb.h>
55 #include <arpa/inet.h>
56 #endif
58 #ifdef SOLARIS
59 #include <stropts.h>
60 #include <sys/conf.h>
61 #include <netinet/in_systm.h>
62 #define gethostbyname2(A, B) gethostbyname(A)
63 #ifndef TRU64
64 #define FIONREAD I_NREAD
65 #endif
66 #endif
68 #ifdef OS2
69 #define socklen_t int
70 #define SHUT_RDWR 2
71 #endif
73 #ifndef INADDR_NONE
74 #define INADDR_NONE (unsigned) -1
75 #endif
77 #ifndef AF_UNIX
78 #define AF_UNIX PF_UNIX
79 #endif
81 #ifndef SUN_LEN
82 #define SUN_LEN(su) \
83 (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
84 #endif
86 #include "protos.h"
88 #define MAX_PENDING_CONNECTS 128
89 #define NO_FLAGS_SET 0
91 #ifdef WIN_32
92 #define socklen_t int
93 #define close closesocket
94 #else
95 #define SOCKET_ERROR -1
96 #define INVALID_SOCKET -1
97 #endif
100 #define ERR_INET_OPEN_SOCKET 1
101 #define ERR_INET_HOST_UNKNOWN 2
102 #define ERR_INET_INVALID_SERVICE 3
103 #define ERR_INET_CONNECT_FAILED 4
104 #define ERR_INET_ACCEPT 5
105 #define ERR_INET_CONNECTION_DROPPED 6
106 #define ERR_INET_CONNECTION_BROKEN 7
107 #define ERR_INET_READ 8
108 #define ERR_INET_WRITE 9
109 #define ERR_INET_CANNOT_BIND 10
110 #define ERR_INET_TOO_MUCH_SOCKETS 11
111 #define ERR_INET_LISTEN_FAILED 12
112 #define ERR_INET_BAD_FORMED_IP 13
113 #define ERR_INET_SELECT_FAILED 14
114 #define ERR_INET_PEEK_FAILED 15
115 #define ERR_INET_NOT_VALID_SOCKET 16
116 #define ERR_INET_TIMEOUT 17
117 #define MAX_NET_ERROR 17
119 #define isnum(A) ((A)>= '0' && (A) <= '9')
121 typedef struct
123 int socket;
124 int family;
125 void * next;
126 } INET_SESSION;
128 INET_SESSION * netSessions = NULL;
130 int deleteInetSession(int sock);
131 int getSocketFamily(int sock);
133 #define READY_READ 0
134 #define READY_WRITE 1
136 int errorIdx = 0;
138 extern int logTraffic;
139 extern int noPromptMode;
141 /* with MinGW gcc 3.4.5 not needed
142 #ifdef WIN_32
143 struct timezone {
144 int tz_minuteswest;
145 int tz_dsttime;
147 int gettimeofday(struct timeval * tv, struct timezone * tz);
148 #endif
152 /********************** session functions *******************/
154 int createInetSession(int sock, int family)
156 INET_SESSION * iSession;
158 iSession = (INET_SESSION *)malloc(sizeof(INET_SESSION));
160 iSession->socket = sock;
161 iSession->family = family;
163 if(netSessions == NULL)
165 netSessions = iSession;
166 iSession->next = NULL;
168 else
170 iSession->next = netSessions;
171 netSessions = iSession;
173 return(TRUE);
176 int deleteInetSession(int sock)
178 INET_SESSION * session;
179 INET_SESSION * previous;
181 if(netSessions == NULL)
182 return(0);
183 else
184 session = previous = netSessions;
186 while(session)
188 if(session->socket == sock)
190 if(session == netSessions)
191 netSessions = session->next;
192 else
193 previous->next = session->next;
194 free((char *)session);
195 return(TRUE);
197 previous = session;
198 session = session->next;
201 return(FALSE);
205 int getSocketFamily(int sock)
207 INET_SESSION * session;
209 session = netSessions;
211 while(session)
213 if(session->socket == sock)
214 return(session->family);
215 session = session->next;
218 return(-1);
221 /********************* user functions **************************/
224 CELL * p_netClose(CELL * params)
226 UINT sock;
228 getInteger(params, &sock);
229 deleteInetSession((int)sock);
231 if(!getFlag(params->next))
232 shutdown(sock, SHUT_RDWR);
234 if(close((int)sock) == SOCKET_ERROR)
235 return(netError(ERR_INET_NOT_VALID_SOCKET));
237 errorIdx = 0;
238 return(trueCell);
242 CELL * p_netSessions(CELL * params)
244 INET_SESSION * session;
245 INET_SESSION * sPtr;
246 CELL * sList;
247 CELL * last;
249 session = netSessions;
250 sList = getCell(CELL_EXPRESSION);
251 last = NULL;
253 while(session)
255 sPtr = session;
256 session = session->next;
257 if(last == NULL)
259 last = stuffInteger(sPtr->socket);
260 sList->contents = (UINT)last;
262 else
264 last->next = stuffInteger(sPtr->socket);
265 last = last->next;
269 return(sList);
274 /*********************************************************************/
276 CELL * p_netService(CELL * params)
278 struct servent * pSe;
279 char * service;
280 char * protocol;
281 int port;
283 params = getString(params, &service);
284 getString(params, &protocol);
286 if((pSe = getservbyname(service, protocol)) == NULL)
287 return(netError(ERR_INET_INVALID_SERVICE));
289 port = (int)ntohs(pSe->s_port);
291 errorIdx = 0;
292 return(stuffInteger((UINT)port));
296 CELL * p_netConnect(CELL * params)
298 UINT ttl = 3;
299 char * remoteHostName;
300 int type;
301 UINT portNo;
302 char * protocol = NULL;
303 int sock;
305 params = getString(params, &remoteHostName);
306 #ifndef WIN_32
307 if(params == nilCell)
309 if((sock = netConnectLocal(remoteHostName)) == SOCKET_ERROR)
310 return(netError(errorIdx));
311 else
312 return(stuffInteger((UINT)sock));
314 #endif
316 params = getInteger(params, &portNo);
318 type = SOCK_STREAM;
319 if(params != nilCell)
321 params = getString(params, &protocol);
322 *protocol = toupper(*protocol);
323 type = SOCK_DGRAM;
324 if(*protocol == 'M')
326 if(params != nilCell)
327 getInteger(params, &ttl);
331 if((sock = netConnect(remoteHostName, (int)portNo, type, protocol, (int)ttl)) == SOCKET_ERROR)
332 return(netError(errorIdx));
334 createInetSession(sock, AF_INET);
336 errorIdx = 0;
337 return(stuffInteger((UINT)sock));
341 #ifndef WIN_32
342 /* create local domain UNIX socket */
343 int netConnectLocal(char * path)
345 int sock;
346 struct sockaddr_un remote_sun;
348 if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == SOCKET_ERROR)
350 errorIdx = ERR_INET_OPEN_SOCKET;
351 return(SOCKET_ERROR);
354 remote_sun.sun_family = AF_UNIX;
355 strncpy(remote_sun.sun_path, path, sizeof(remote_sun.sun_path) - 1);
356 remote_sun.sun_path[sizeof (remote_sun.sun_path) - 1] = '\0';
357 if (connect(sock, (struct sockaddr *)&remote_sun, SUN_LEN(&remote_sun)) == -1)
359 close(sock);
360 errorIdx = ERR_INET_CONNECT_FAILED;
361 return(SOCKET_ERROR);
364 createInetSession(sock, AF_UNIX);
366 errorIdx = 0;
367 return(sock);
369 #endif
371 /* create internet socket */
372 int netConnect(char * remoteHostName, int portNo, int type, char * prot, int ttl)
374 #ifdef IPV6
375 struct sockaddr_in6 dest_sin;
376 struct in6_addr iaddr;
377 #else
378 struct sockaddr_in dest_sin;
379 struct in_addr iaddr;
380 #endif
381 struct hostent * pHe;
382 int sock, idx;
383 /* char opt; */
384 int opt;
386 /* create socket */
387 if((sock = socket(ADDR_TYPE, type, 0)) == INVALID_SOCKET)
389 errorIdx = ERR_INET_OPEN_SOCKET;
390 return(SOCKET_ERROR);
393 if(prot != NULL) if(*prot == 'M' || *prot == 'B')
395 memset(&iaddr, 0, sizeof(iaddr));
396 #ifdef IPV6
397 /* iaddr = IN6ADDR_ANY_INIT; */
398 iaddr = in6addr_any;
399 #else
400 iaddr.s_addr = INADDR_ANY;
401 #endif
403 if(*prot == 'M')
405 setsockopt(sock, 0, IP_MULTICAST_IF, (const void *)&iaddr, sizeof(iaddr));
406 opt = ttl;
407 setsockopt(sock, 0, IP_MULTICAST_TTL, (const void *)&opt, sizeof(opt));
410 if(*prot == 'B')
412 opt = 1;
413 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const void *)&opt, sizeof(opt));
417 if((pHe = gethostbyname2(remoteHostName, ADDR_TYPE)) == NULL)
419 errorIdx = ERR_INET_HOST_UNKNOWN;
420 return(SOCKET_ERROR);
423 for(idx = 0; ; idx++)
425 #ifdef IPV6
426 memcpy((char *)&(dest_sin.sin6_addr), pHe->h_addr_list[idx], pHe->h_length);
427 dest_sin.sin6_port = htons((u_short)portNo);
428 dest_sin.sin6_family = AF_INET6;
429 #else
430 memcpy((char *)&(dest_sin.sin_addr), pHe->h_addr_list[idx], pHe->h_length);
431 dest_sin.sin_port = htons((u_short)portNo);
432 dest_sin.sin_family = AF_INET;
433 memset(&(dest_sin.sin_zero), '\0', sizeof(dest_sin.sin_zero));
434 #endif
435 if(connect(sock,(struct sockaddr *)&dest_sin, sizeof(dest_sin)) == 0)
436 break;
438 if(pHe->h_addr_list[idx+1] != NULL)
439 continue;
441 close(sock);
442 errorIdx = ERR_INET_CONNECT_FAILED;
443 return(SOCKET_ERROR);
446 errorIdx = 0;
447 return(sock);
450 /********* should be called after listen/accept notification **********/
452 CELL * p_netAccept(CELL * params)
454 int sock;
455 UINT listenSock;
457 getInteger(params, &listenSock);
459 if((sock = netAccept((int)listenSock)) == INVALID_SOCKET)
460 return(netError(ERR_INET_ACCEPT));
462 return(stuffInteger(sock));
466 int netAccept(int listenSock)
468 int sock, family;
469 #ifdef IPV6
470 struct sockaddr_in6 dest_sin;
471 #else
472 struct sockaddr_in dest_sin;
473 #endif
474 #ifndef WIN_32
475 struct sockaddr_un dest_sun;
476 #endif
477 socklen_t dest_slen;
479 family = getSocketFamily(listenSock);
481 #ifndef WIN_32
482 if(family == AF_UNIX)
484 dest_slen = sizeof(struct sockaddr_un);
485 sock = accept(listenSock, (struct sockaddr *) &dest_sun, &dest_slen);
487 else
488 #endif
490 #ifdef IPV6
491 dest_slen = sizeof(struct sockaddr_in6);
492 #else
493 dest_slen = sizeof(struct sockaddr_in);
494 #endif
495 sock = accept(listenSock, (struct sockaddr *) &dest_sin, (void *)&dest_slen);
498 if(sock != INVALID_SOCKET)
500 createInetSession(sock, family);
501 errorIdx = 0;
504 return(sock);
508 /******************* returns remote IP and port number *************/
510 #define LOCAL_INFO 0
511 #define PEER_INFO 1
514 int getPeerName(int sock, int peerLocalFlag, char * IPaddress)
516 socklen_t address_sin_len;
517 #ifdef IPV6
518 struct sockaddr_in6 address_sin;
519 #else
520 struct sockaddr_in address_sin;
521 #endif
523 if(getSocketFamily(sock) == AF_UNIX)
525 snprintf(IPaddress, 6, "local");
526 return(0);
529 *IPaddress = 0;
530 address_sin_len = sizeof(address_sin);
531 if(peerLocalFlag == LOCAL_INFO)
533 if(getsockname(sock,
534 (struct sockaddr *)&address_sin, (void *)&address_sin_len)
535 == SOCKET_ERROR)
536 return(0);
538 else
540 if(getpeername(sock,
541 (struct sockaddr *)&address_sin, (void *)&address_sin_len)
542 == SOCKET_ERROR)
543 return(0);
546 /* return address IP number */
547 #ifdef IPV6
548 inet_ntop(AF_INET6, &address_sin.sin6_addr, IPaddress, 40);
549 return(ntohs(address_sin.sin6_port));
550 #else
551 snprintf(IPaddress, 16, inet_ntoa(address_sin.sin_addr));
552 return(ntohs(address_sin.sin_port));
553 #endif
557 CELL * p_netLocal(CELL * params)
559 return(netPeerLocal(params, LOCAL_INFO));
562 CELL * p_netPeer(CELL * params)
564 return(netPeerLocal(params, PEER_INFO));
568 CELL * netPeerLocal(CELL * params, int peerLocalFlag)
570 CELL * result;
571 CELL * cell;
572 #ifdef IPV6
573 char name[40];
574 #else
575 char name[16];
576 #endif
577 UINT addressPort, sock;
579 getInteger(params, &sock);
580 if((addressPort = getPeerName((int)sock, peerLocalFlag, name)) == SOCKET_ERROR)
581 return(nilCell);
583 result = getCell(CELL_EXPRESSION);
584 result->contents = (UINT)stuffString(name);
585 cell = (CELL *)result->contents;
586 cell->next = stuffInteger((UINT)addressPort);
588 errorIdx = 0;
589 return(result);
593 CELL * p_netLookup(CELL * params)
595 #ifdef IPV6
596 struct sockaddr_in6 address;
597 #else
598 union ipSpec
600 unsigned int no;
601 unsigned char chr[4];
602 } ip;
604 struct sockaddr_in address;
605 #endif
606 struct hostent * pHe;
607 char * hostString;
608 char IPaddress[16];
609 int forceByName = 0;
611 params = getString(params, &hostString);
612 forceByName = getFlag(params);
614 /* get hostname from ip-number */
615 #ifdef IPV6
616 if((isDigit((unsigned char)*hostString) || (hostString[0] == ':')) && !forceByName)
618 if(inet_pton(AF_INET6, hostString, &address.sin6_addr) == 0)
619 return(netError(ERR_INET_BAD_FORMED_IP));
621 if((pHe = gethostbyaddr(&address.sin6_addr, AF_INET6, PF_INET6)) == NULL)
622 return(nilCell);
624 return(stuffString((char *)pHe->h_name));
626 #else
627 if(isDigit((unsigned char)*hostString) && !forceByName)
629 if((ip.no = inet_addr(hostString)) == INADDR_NONE)
630 return(netError(ERR_INET_BAD_FORMED_IP));
632 if((pHe = gethostbyaddr((char *) &ip.no,4,PF_INET)) == NULL)
633 return(nilCell);
635 return(stuffString((char *)pHe->h_name));
637 #endif
639 /* get ip-number from hostname */
640 if((pHe = gethostbyname2(hostString, ADDR_TYPE)) == NULL)
641 return(nilCell);
643 #ifdef IPV6
644 memcpy((char *)&(address.sin6_addr), pHe->h_addr_list[0], pHe->h_length);
645 inet_ntop(AF_INET6, &address.sin6_addr, IPaddress, 40);
646 #else
647 memcpy((char *)&(address.sin_addr), pHe->h_addr_list[0], pHe->h_length);
648 snprintf(IPaddress, 16, inet_ntoa(address.sin_addr));
649 #endif
651 errorIdx = 0;
652 return(stuffString(IPaddress));
655 CELL * netReceive(int sock, SYMBOL * readSymbol, size_t readSize, CELL * params);
657 CELL * p_netReceive(CELL * params)
659 UINT sock;
660 SYMBOL * readSymbol;
661 size_t readSize;
663 params = getInteger(params, &sock);
664 params = getSymbol(params, &readSymbol);
665 params = getInteger(params, (UINT *)&readSize);
667 return(netReceive((int)sock, readSymbol, readSize, params));
670 CELL * netReceive(int sock, SYMBOL * readSymbol, size_t readSize, CELL * params)
672 char * waitFor;
673 ssize_t bytesReceived;
674 size_t length;
675 int found;
676 STREAM netStream;
677 char chr;
678 CELL * cell;
680 if(isProtected(readSymbol->flags))
681 return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(readSymbol)));
683 memset(&netStream, 0, sizeof(netStream));
685 if(params == nilCell)
687 openStrStream(&netStream, readSize, 0);
688 found = 1;
689 bytesReceived = recv(sock, netStream.buffer, readSize, NO_FLAGS_SET);
691 else
693 getString(params, &waitFor);
694 openStrStream(&netStream, MAX_LINE, 0);
695 found = bytesReceived = 0;
696 length = strlen(waitFor);
697 while(bytesReceived < (int)readSize)
699 if(recv(sock, &chr, 1, NO_FLAGS_SET) <= 0)
701 bytesReceived = 0;
702 break;
704 writeStreamChar(&netStream, chr);
705 if(++bytesReceived < length) continue;
706 if(strncmp(waitFor, netStream.ptr - length, length) == 0)
708 found = 1;
709 break;
715 if(bytesReceived == 0 || found == 0)
717 closeStrStream(&netStream);
718 deleteInetSession(sock);
719 close(sock);
720 return(netError(ERR_INET_CONNECTION_DROPPED));
723 if(bytesReceived == SOCKET_ERROR)
725 closeStrStream(&netStream);
726 deleteInetSession(sock);
727 close(sock);
728 return(netError(ERR_INET_READ));
731 cell = stuffStringN(netStream.buffer, bytesReceived);
732 closeStrStream(&netStream);
734 deleteList((CELL *)readSymbol->contents);
735 readSymbol->contents = (UINT)cell;
737 errorIdx = 0;
738 return(stuffInteger(bytesReceived));
743 CELL * netReceiveFrom(int sock, size_t readSize, int closeFlag)
745 int portNo;
746 char * buffer;
747 ssize_t bytesReceived;
748 #ifdef IPV6
749 struct sockaddr_in6 remote_sin;
750 #else
751 struct sockaddr_in remote_sin;
752 #endif
753 CELL * cell;
754 CELL * result;
755 #ifdef WIN_32
756 int remote_sin_len;
757 #else
758 #ifdef TRU64
759 unsigned long remote_sin_len;
760 #else
761 socklen_t remote_sin_len;
762 #endif
763 #endif
764 char IPaddress[16];
766 buffer = (char *)allocMemory(readSize + 1);
767 remote_sin_len = sizeof(remote_sin);
768 memset(&remote_sin, 0, sizeof(remote_sin));
770 bytesReceived = recvfrom(sock, buffer, readSize, 0,
771 (struct sockaddr *)&remote_sin, &remote_sin_len);
773 if(bytesReceived == SOCKET_ERROR)
775 freeMemory(buffer);
776 close(sock);
777 return(netError(ERR_INET_READ));
780 #ifdef IPV6
781 inet_ntop(AF_INET6, &remote_sin.sin6_addr, IPaddress, 40);
782 portNo = ntohs(remote_sin.sin6_port);
783 #else
784 snprintf(IPaddress, 16, inet_ntoa(remote_sin.sin_addr));
785 portNo = ntohs(remote_sin.sin_port);
786 #endif
789 cell = result = getCell(CELL_EXPRESSION);
790 cell->contents = (UINT)stuffStringN(buffer, bytesReceived);
791 cell = (CELL *)cell->contents;
792 cell->next = stuffString(IPaddress);
793 ((CELL*)cell->next)->next = stuffInteger(portNo);
795 freeMemory(buffer);
797 if(closeFlag) close(sock);
799 errorIdx = 0;
800 return(result);
804 CELL * p_netReceiveUDP(CELL * params)
806 UINT portNo;
807 int sock;
808 size_t readSize;
809 INT64 wait = 0;
810 INT64 elapsed;
811 char * ifaddr = NULL;
813 params = getInteger(params, &portNo);
814 params = getInteger(params, (UINT *)&readSize);
815 if(params != nilCell)
817 params = getInteger64(params, &wait);
818 if(params != nilCell)
819 getString(params, &ifaddr);
822 if((sock = netListenOrDatagram((int)portNo, SOCK_DGRAM, ifaddr, NULL)) == SOCKET_ERROR)
823 return(nilCell);
825 /* if timeout parameter given wait for socket to be readable */
826 if(wait > 0)
828 if((elapsed = wait_ready(sock, wait, READY_READ)) <= 0)
830 close(sock);
831 if(elapsed == 0) return(netError(ERR_INET_TIMEOUT));
832 else netError(ERR_INET_SELECT_FAILED);
836 return(netReceiveFrom(sock, readSize, TRUE));
840 CELL * p_netReceiveFrom(CELL * params)
842 UINT sock;
843 size_t readSize;
845 params = getInteger(params, &sock);
846 getInteger(params, (UINT*)&readSize);
848 return(netReceiveFrom((int)sock, readSize, FALSE));
852 /**********************************************************************/
854 CELL * p_netSend(CELL * params)
856 UINT sock;
857 size_t size, size2;
858 char * buffer;
859 ssize_t bytesSent;
861 params = getInteger(params, &sock);
862 params = getStringSize(params, &buffer, &size, TRUE);
864 if(params->type != CELL_NIL)
866 getInteger(params, (UINT *)&size2);
867 if(size2 < size) size = size2;
870 if((bytesSent = sendall((int)sock, buffer, size)) == SOCKET_ERROR)
872 deleteInetSession((int)sock);
873 close((int)sock);
874 return(netError(ERR_INET_WRITE));
877 errorIdx = 0;
878 return(stuffInteger(bytesSent));
881 #define SEND_TO_UDP 0
882 #define SEND_TO_SOCK 1
884 CELL * netSendTo(CELL * params, int type)
886 char * remoteHost;
887 UINT remotePort;
888 #ifdef IPV6
889 struct sockaddr_in6 dest_sin;
890 #else
891 struct sockaddr_in dest_sin;
892 #endif
893 struct hostent * pHe;
894 size_t size;
895 char * buffer;
896 ssize_t bytesSent;
897 UINT sock;
898 /* char one = 1; */
899 int one = 1;
901 params = getString(params, &remoteHost);
902 params = getInteger(params, &remotePort);
903 params = getStringSize(params, &buffer, &size, TRUE);
905 if((pHe = gethostbyname2(remoteHost, ADDR_TYPE)) == NULL)
906 return(netError(ERR_INET_HOST_UNKNOWN));
908 if(type == SEND_TO_UDP) /* for 'net-send-udp' */
910 if((sock = socket(ADDR_TYPE, SOCK_DGRAM, 0)) == INVALID_SOCKET)
911 return(netError(ERR_INET_OPEN_SOCKET));
913 if(getFlag(params))
914 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const void *)&one, sizeof(one));
916 else /* SEND_TO_SOCK , socket may or may not be UDP, for 'net-send-to' */
918 params = getInteger(params, &sock);
921 #ifdef IPV6
922 memcpy((char *)&(dest_sin.sin6_addr), pHe->h_addr_list[0], pHe->h_length);
923 dest_sin.sin6_port = htons((u_short)remotePort);
924 dest_sin.sin6_family = AF_INET6;
925 #else
926 memcpy((char *)&(dest_sin.sin_addr), pHe->h_addr_list[0], pHe->h_length);
927 dest_sin.sin_port = htons((u_short)remotePort);
928 dest_sin.sin_family = AF_INET;
929 memset(&(dest_sin.sin_zero), '\0', 8);
930 #endif
932 bytesSent = sendto((int)sock, buffer, size, NO_FLAGS_SET,
933 (struct sockaddr *)&dest_sin, sizeof(dest_sin));
935 if(type == SEND_TO_UDP) close((int)sock);
937 if(bytesSent == SOCKET_ERROR)
938 return(netError(ERR_INET_WRITE));
940 errorIdx = 0;
941 return(stuffInteger(bytesSent));
945 CELL * p_netSendUDP(CELL * params)
947 return(netSendTo(params, SEND_TO_UDP));
951 CELL * p_netSendTo(CELL * params)
953 return(netSendTo(params, SEND_TO_SOCK));
957 /************************* listen **************************************/
959 CELL * p_netListen(CELL * params)
961 UINT portNo;
962 char * ifAddr = NULL;
963 char * option = NULL;
964 char * mcAddr = NULL;
965 int sock, type;
966 CELL * cell;
968 type = SOCK_STREAM;
969 cell = evaluateExpression(params);
970 params = params->next;
972 #ifndef WIN_32
973 if(cell->type == CELL_STRING)
975 if((sock = netListenLocal((char *)cell->contents)) == SOCKET_ERROR)
976 return(netError(errorIdx));
977 else
978 return(stuffInteger((UINT)sock));
980 #endif
982 getIntegerExt(cell, &portNo, FALSE);
984 if(params != nilCell)
986 params = getString(params, &ifAddr);
987 if(*ifAddr == 0) ifAddr = NULL;
988 if(params != nilCell)
990 params = getString(params, &option);
991 if(*option == 'u' || *option == 'U')
992 type = SOCK_DGRAM;
993 else if(*option == 'm' || *option == 'M')
995 type = SOCK_DGRAM;
996 mcAddr = ifAddr;
997 ifAddr = NULL;
1003 if((sock = netListenOrDatagram((int)portNo, type, ifAddr, mcAddr)) == SOCKET_ERROR)
1004 return(nilCell);
1006 return(stuffInteger(sock));
1009 #ifndef WIN_32
1010 int netListenLocal(char * name)
1012 int sock;
1013 struct sockaddr_un local_sun;
1015 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1016 local_sun.sun_family = AF_UNIX;
1017 strncpy(local_sun.sun_path, name, sizeof(local_sun.sun_path) - 1);
1018 local_sun.sun_path[sizeof (local_sun.sun_path) - 1] = '\0';
1019 unlink(local_sun.sun_path);
1021 #ifdef OS2
1022 if(bind(sock, (struct sockaddr *)&local_sun, sizeof(struct sockaddr_un)) == -1)
1023 #else
1024 if(bind(sock, (struct sockaddr *)&local_sun, SUN_LEN(&local_sun)) != 0)
1025 #endif
1027 close(sock);
1028 errorIdx = ERR_INET_CANNOT_BIND;
1029 return(SOCKET_ERROR);
1032 if(listen(sock, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
1034 close(sock);
1035 errorIdx = ERR_INET_LISTEN_FAILED;
1036 return(SOCKET_ERROR);
1039 createInetSession(sock, AF_UNIX);
1041 errorIdx = 0;
1042 return(sock);
1044 #endif
1047 int netListenOrDatagram(int portNo, int type, char * ifAddr, char * mcAddr)
1049 int sock;
1050 int one = 1;
1051 /* char one = 1; */
1052 #ifdef IPV6
1053 struct sockaddr_in6 local_sin;
1054 #else
1055 struct sockaddr_in local_sin;
1056 #endif
1057 struct hostent * pHe;
1058 struct ip_mreq mcast;
1060 if((sock = socket(ADDR_TYPE, type, 0)) == INVALID_SOCKET)
1062 errorIdx = ERR_INET_OPEN_SOCKET;
1063 return SOCKET_ERROR;
1066 memset(&local_sin, 0, sizeof(local_sin));
1068 if(ifAddr != NULL && *ifAddr != 0)
1070 if((pHe = gethostbyname2(ifAddr, ADDR_TYPE)) == NULL)
1072 errorIdx = ERR_INET_HOST_UNKNOWN;
1073 return(SOCKET_ERROR);
1075 #ifdef IPV6
1076 memcpy((char *)&(local_sin.sin6_addr), pHe->h_addr_list[0], pHe->h_length);
1079 else
1080 local_sin.sin6_addr = in6addr_any;
1082 #else
1083 memcpy((char *)&(local_sin.sin_addr), pHe->h_addr_list[0], pHe->h_length);
1085 else
1086 local_sin.sin_addr.s_addr = INADDR_ANY;
1087 #endif
1089 #ifdef IPV6
1090 local_sin.sin6_port = htons((u_short)portNo);
1091 local_sin.sin6_family = AF_INET6;
1092 #else
1093 local_sin.sin_port = htons((u_short)portNo);
1094 local_sin.sin_family = AF_INET;
1095 #endif
1097 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void*)&one, sizeof(one));
1099 if(bind(sock, (struct sockaddr *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
1101 close(sock);
1102 errorIdx = ERR_INET_CANNOT_BIND;
1103 return(SOCKET_ERROR);
1106 if(mcAddr != NULL)
1108 memset(&mcast, 0, sizeof(mcast));
1109 mcast.imr_multiaddr.s_addr = inet_addr(mcAddr);
1110 #ifdef IPV6
1111 /* mcast.imr_interface.s_addr = IN6ADDR_ANY_INIT; */
1112 #else
1113 mcast.imr_interface.s_addr = INADDR_ANY;
1114 #endif
1115 setsockopt(sock, 0, IP_ADD_MEMBERSHIP, (const void *)&mcast, sizeof(mcast));
1118 if(type == SOCK_STREAM)
1120 if(listen(sock, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
1122 close(sock);
1123 errorIdx = ERR_INET_LISTEN_FAILED;
1124 return(SOCKET_ERROR);
1128 createInetSession(sock, AF_INET);
1130 errorIdx = 0;
1131 return(sock);
1135 /* returns number of bytes ready to read */
1136 CELL * p_netPeek(CELL * params)
1138 UINT sock;
1139 #ifdef WIN_32
1140 unsigned long result;
1141 #else
1142 int result;
1143 #endif
1145 getInteger(params, &sock);
1147 if(ioctl((int)sock, FIONREAD, &result) == SOCKET_ERROR)
1148 return(netError(ERR_INET_PEEK_FAILED));
1150 errorIdx = 0;
1151 return(stuffInteger((UINT)result));
1155 typedef struct
1157 int sock;
1158 void * next;
1159 } SOCKLIST;
1162 /* checks a socket for readability/writeability */
1163 CELL * p_netSelect(CELL * params)
1165 long value;
1166 INT64 wait;
1167 char * mode;
1168 struct timeval timeOut;
1169 fd_set socketSet;
1170 SOCKLIST * sockPtr;
1171 SOCKLIST * sockList = NULL;
1172 CELL * cell;
1173 CELL * list = NULL;
1174 struct timeval* tmvPtr;
1176 errorIdx = 0;
1178 FD_ZERO(&socketSet);
1180 cell = evaluateExpression(params);
1181 if(isNumber(cell->type))
1182 getIntegerExt(cell, (UINT*)&value, FALSE);
1183 else if(isList(cell->type))
1185 cell = (CELL*)cell->contents;
1186 if(cell == nilCell) return(getCell(CELL_EXPRESSION));
1187 sockList = sockPtr = allocMemory(sizeof(SOCKLIST));
1188 sockPtr->sock = cell->contents;
1189 sockPtr->next = NULL;
1190 FD_SET(sockPtr->sock, &socketSet);
1191 value = 1;
1192 while((cell = cell->next) != nilCell)
1194 sockPtr->next = allocMemory(sizeof(SOCKLIST));
1195 sockPtr = sockPtr->next;
1196 sockPtr->sock = cell->contents;
1197 sockPtr->next = NULL;
1198 if(value == FD_SETSIZE)
1199 return(netError(ERR_INET_TOO_MUCH_SOCKETS));
1200 else value++;
1201 FD_SET(sockPtr->sock, &socketSet);
1204 else return(errorProcExt(ERR_LIST_OR_NUMBER_EXPECTED, params));
1206 params = getString(params->next, &mode);
1207 getInteger64(params, &wait);
1209 tmvPtr = (wait == -1) ? NULL : &timeOut;
1210 timeOut.tv_sec = wait/1000000;
1211 timeOut.tv_usec = wait - timeOut.tv_sec * 1000000;
1213 if(sockList == NULL)
1215 FD_SET((int)value, &socketSet);
1216 value = 1;
1219 /* printf("%d %d %d\n", timeOut.tv_sec, timeOut.tv_usec, sizeof(timeOut.tv_sec)); */
1221 if(*mode == 'r')
1222 value = select(FD_SETSIZE, &socketSet, NULL, NULL, tmvPtr);
1223 else if(*mode == 'w')
1224 value = select(FD_SETSIZE, NULL, &socketSet, NULL, tmvPtr);
1225 else if(*mode == 'e')
1226 value = select(FD_SETSIZE, NULL, NULL, &socketSet, tmvPtr);
1228 if(value >= 0)
1230 if((sockPtr = sockList) == NULL)
1232 if(value == 0) return(nilCell);
1233 else return(trueCell);
1236 cell = getCell(CELL_EXPRESSION);
1237 while(sockPtr != NULL)
1239 if(FD_ISSET(sockPtr->sock, &socketSet))
1241 if(list == NULL)
1243 list = cell;
1244 cell->contents = (UINT)stuffInteger(sockPtr->sock);
1245 cell = (CELL *)cell->contents;
1247 else
1249 cell->next = stuffInteger(sockPtr->sock);
1250 cell = cell->next;
1253 sockPtr = sockPtr->next;
1254 free(sockList);
1255 sockList = sockPtr;
1258 if(list == NULL) return(cell);
1259 else return(list);
1262 netError(ERR_INET_SELECT_FAILED);
1264 if(sockList == NULL) return(nilCell);
1265 return(getCell(CELL_EXPRESSION));
1268 extern char logFile[];
1270 void writeLog(char * text, int newLine)
1272 int handle;
1274 #ifdef WIN_32
1275 handle = open(logFile, O_RDWR | O_APPEND | O_BINARY | O_CREAT, S_IREAD | S_IWRITE);
1276 #else
1277 handle = open(logFile, O_RDWR | O_APPEND | O_BINARY | O_CREAT,
1278 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); /* rw-rw-rw */
1279 #endif
1281 write(handle, text, strlen(text));
1282 if(newLine) write(handle, &LINE_FEED, strlen(LINE_FEED));
1283 close(handle);
1287 FILE * serverFD(int port, char * domain, int reconnect)
1289 static int sock, connection;
1290 char name[18];
1291 char text[80];
1292 time_t t;
1294 if(!reconnect)
1296 #ifndef WIN_32
1297 if(port != 0)
1298 sock = netListenOrDatagram(port, SOCK_STREAM, NULL, NULL);
1299 else
1300 sock = netListenLocal(domain);
1301 #else
1302 sock = netListenOrDatagram(port, SOCK_STREAM, NULL, NULL);
1303 #endif
1305 if(sock == SOCKET_ERROR)
1307 snprintf(text, 78, "newLISP v.%d listening on %s", version, domain);
1308 writeLog(text, TRUE);
1309 return(NULL);
1312 else
1314 deleteInetSession(connection);
1315 close(connection);
1318 if((connection = netAccept(sock)) == SOCKET_ERROR)
1319 return NULL;
1321 createInetSession(connection, (port != 0) ? AF_INET : AF_UNIX);
1323 /* print log */
1324 getPeerName(connection, PEER_INFO, name);
1325 t = time(NULL);
1326 snprintf(text, 78, "Connected to %s on %s", name, ctime(&t));
1327 /* printf(text); */
1328 writeLog(text, 0);
1330 return(fdopen(connection, "r+"));
1333 /******************************* distributed computing ***********************/
1335 #define MAX_BUFF 1024
1336 CELL * netEvalError(int errNo);
1338 typedef struct
1340 char * host;
1341 int port;
1342 int sock;
1343 int timeOut;
1344 STREAM * netStream;
1345 CELL * result;
1346 void * next;
1347 } NETEVAL;
1349 void freeSessions(NETEVAL * base);
1351 CELL * p_netEval(CELL * params)
1353 CELL * cell = NULL;
1354 CELL * list = NULL;
1355 NETEVAL * session = NULL;
1356 NETEVAL * base = NULL;
1357 char * host;
1358 char * prog;
1359 UINT port;
1360 int ready;
1361 int sock;
1362 size_t size, count = 0;
1363 ssize_t bytes;
1364 long timeOut = MAX_LONG;
1365 int start, elapsed = 0;
1366 CELL * result;
1367 STREAM * netStream;
1368 CELL * netEvalIdle = NULL;
1369 char buffer[MAX_BUFF];
1370 STREAM evalStream;
1371 int rawMode = FALSE;
1372 int singleSession = FALSE;
1373 jmp_buf errorJumpSave;
1374 int errNo;
1375 int resultStackIdxSave;
1377 list = evaluateExpression(params);
1378 if(list->type == CELL_STRING)
1380 host = (char *)list->contents;
1381 params = getIntegerExt(params->next, &port, TRUE);
1382 params = getStringSize(params, &prog, &size, TRUE);
1383 list = nilCell;
1384 singleSession = TRUE;
1385 goto SINGLE_SESSION;
1387 else if(list->type == CELL_EXPRESSION)
1389 list = (CELL*)list->contents;
1390 params = params->next;
1392 else return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
1394 CREATE_SESSION:
1395 if(!isList(list->type))
1396 return(errorProcExt(ERR_LIST_EXPECTED, list));
1397 cell = (CELL *)list->contents;
1399 /* get node parameters, since 8.9.8 evaluated */
1400 memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
1401 if((errNo = setjmp(errorJump)) != 0)
1403 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1404 freeSessions(base);
1405 longjmp(errorJump, errNo);
1407 cell = getStringSize(cell, &host, &size, TRUE);
1408 cell = getInteger(cell, &port);
1409 cell = getStringSize(cell, &prog, &size, TRUE);
1410 rawMode = getFlag(cell);
1412 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1414 SINGLE_SESSION:
1415 if(base == NULL)
1417 base = session = allocMemory(sizeof(NETEVAL));
1418 memset(base, 0, sizeof(NETEVAL));
1420 else
1422 session->next = allocMemory(sizeof(NETEVAL));
1423 session = session->next;
1424 memset(session, 0, sizeof(NETEVAL));
1427 #ifndef WIN_32
1428 if(port != 0)
1429 sock = netConnect(host, (int)port, SOCK_STREAM, NULL, 3);
1430 else
1431 sock = netConnectLocal(host);
1432 #else
1433 sock = netConnect(host, (int)port, SOCK_STREAM, NULL, 3);
1434 #endif
1436 if(sock == SOCKET_ERROR)
1438 session->result = netEvalError(errorIdx);
1439 goto CONTINUE_CREATE_SESSION;
1442 session->host = host;
1443 session->port = port;
1444 session->sock = sock;
1446 if( sendall(sock, "[cmd]\n", 6) == SOCKET_ERROR ||
1447 sendall(sock, prog, size) == SOCKET_ERROR ||
1448 sendall(sock, "(exit)\n[/cmd]\n", 14) == SOCKET_ERROR )
1450 close(sock);
1451 session->result = netEvalError(ERR_INET_WRITE);
1452 goto CONTINUE_CREATE_SESSION;
1455 session->netStream = (void *)allocMemory(sizeof(STREAM));
1456 memset(session->netStream, 0, sizeof(STREAM));
1457 openStrStream(session->netStream, MAX_BUFF, 0);
1458 /* prepend quote for evaluation */
1459 writeStreamChar(session->netStream, '\'');
1460 createInetSession(sock, AF_INET);
1461 count++;
1462 CONTINUE_CREATE_SESSION:
1463 list = list->next;
1464 if(list != nilCell) goto CREATE_SESSION;
1466 /* get timeout and optional handler symbol */
1467 session = base;
1468 if(params != nilCell)
1469 params = getInteger(params, (UINT *)&timeOut);
1470 if(params != nilCell)
1471 netEvalIdle = params;
1473 /* printf("timeout %d idle-loop %X\n", timeOut, netEvalIdle); */
1475 /* collect data from host in each active session */
1476 while(count)
1478 resultStackIdxSave = resultStackIdx;
1479 if( (netStream = session->netStream) == NULL)
1481 session = session->next;
1482 if(session == NULL) session = base;
1483 continue;
1486 start = milliSecTime();
1488 if(netEvalIdle)
1490 cell = getCell(CELL_EXPRESSION);
1491 cell->contents = (UINT)copyCell(netEvalIdle);
1492 pushResult(cell);
1493 if(!evaluateExpressionSafe(cell, &errNo))
1495 freeSessions(base);
1496 longjmp(errorJump, errNo);
1500 bytes = -1;
1501 ready = wait_ready(session->sock, 100, READY_READ);
1502 if(ready > 0)
1504 memset(buffer, 0, MAX_BUFF);
1505 bytes = recv(session->sock, buffer, MAX_BUFF, NO_FLAGS_SET);
1506 if(bytes) writeStreamStr(netStream, buffer, bytes);
1508 if(ready < 0 || bytes == 0 || elapsed >= timeOut)
1510 /* printf("count=%d ready=%d bytes=%d elapsed=%d\n", count, ready, bytes, elapsed); */
1511 if(elapsed >= timeOut) result = copyCell(nilCell);
1512 else if(rawMode) /* get raw buffer without the quote */
1513 result = stuffStringN(netStream->buffer + 1, netStream->position - 1);
1514 else
1516 makeStreamFromString(&evalStream, netStream->buffer);
1517 memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
1518 if((errNo = setjmp(errorJump)) != 0)
1520 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1521 freeSessions(base);
1522 longjmp(errorJump, errNo);
1524 result = evaluateStream(&evalStream, 0, TRUE);
1525 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
1528 if(netEvalIdle)
1530 session->result = cell = getCell(CELL_EXPRESSION);
1531 cell->contents = (UINT)stuffString(session->host);
1532 cell = (CELL *)cell->contents;
1533 cell->next = stuffInteger(session->port);
1534 cell = cell->next;
1535 cell->next = result;
1537 else
1538 session->result = result;
1540 closeStrStream(netStream);
1541 deleteInetSession(session->sock);
1542 close(session->sock);
1543 free(netStream);
1544 session->netStream = NULL;
1546 if(netEvalIdle)
1548 list = getCell(CELL_EXPRESSION);
1549 list->contents = (UINT)copyCell(netEvalIdle);
1550 cell = getCell(CELL_QUOTE);
1551 cell->contents = (UINT)session->result;
1552 ((CELL*)list->contents)->next = cell;
1553 pushResult(list);
1554 if(!evaluateExpressionSafe(list, &errNo))
1556 freeSessions(base);
1557 longjmp(errorJump, errNo);
1561 count--;
1564 /* check for rollover at midnight */
1565 if(milliSecTime() >= start)
1566 elapsed += milliSecTime() - start;
1567 else
1568 elapsed += milliSecTime();
1570 session = session->next;
1571 if(session == NULL) session = base;
1573 cleanupResults(resultStackIdxSave);
1576 /* free all sessions and configure result */
1577 result = NULL;
1578 while(base != NULL)
1580 if(netEvalIdle == NULL)
1582 if(result == NULL)
1584 if(singleSession)
1585 result = base->result;
1586 else
1588 result = getCell(CELL_EXPRESSION);
1589 result->contents = (UINT)base->result;
1590 cell = base->result;
1593 else
1595 cell->next = base->result;
1596 cell = cell->next;
1599 session = base;
1600 base = base->next;
1601 free(session);
1604 if(elapsed > timeOut)
1605 errorIdx = ERR_INET_TIMEOUT;
1606 else errorIdx = 0;
1607 if(netEvalIdle == NULL) return(result);
1608 return(trueCell);
1612 void freeSessions(NETEVAL * base)
1614 NETEVAL * session;
1616 while(base != NULL)
1618 if(base->netStream != NULL)
1620 if(base->result != NULL)
1621 deleteList(base->result);
1622 closeStrStream(base->netStream);
1623 deleteInetSession(base->sock);
1624 close(base->sock);
1625 free(base->netStream);
1626 base->netStream = NULL;
1628 session = base;
1629 base = base->next;
1630 free(session);
1634 int sendall(int sock, char * buffer, int len)
1636 int bytesSend = 0;
1637 int n;
1639 while(bytesSend < len)
1641 if((n = send(sock, buffer + bytesSend, len - bytesSend, NO_FLAGS_SET)) == SOCKET_ERROR)
1642 return(SOCKET_ERROR);
1643 bytesSend += n;
1646 return(bytesSend);
1649 /*********************** error handling ***************************************/
1651 char * netErrorMsg[] =
1653 "No error",
1654 "Cannot open socket",
1655 "Host name not known",
1656 "Not a valid service",
1657 "Connection failed",
1658 "Accept failed",
1659 "Connection closed",
1660 "Connection broken",
1661 "Socket recv failed",
1662 "Socket send failed",
1663 "Cannot bind socket",
1664 "Too much sockets in net-select",
1665 "Listen failed",
1666 "Badly formed IP",
1667 "Select failed",
1668 "Peek failed",
1669 "Not a valid socket",
1670 "Operation timed out"
1674 CELL * netError(int errorNo)
1676 errorIdx = errorNo;
1677 return(nilCell);
1680 CELL * netEvalError(int errorNo)
1682 errorIdx = errorNo;
1683 return(p_netLastError(NULL));
1686 CELL * p_netLastError(CELL * params)
1688 CELL * cell;
1689 char str[64];
1691 if(errorIdx == 0 || errorIdx > MAX_NET_ERROR) return(nilCell);
1693 cell = getCell(CELL_EXPRESSION);
1694 cell->contents = (UINT)stuffInteger(errorIdx);
1695 snprintf(str, 63, "ERR: %s", netErrorMsg[errorIdx]);
1696 ((CELL*)cell->contents)->next = stuffString(str);
1698 return(cell);
1702 #ifdef NET_PING
1703 /* net-ping */
1706 CELL * p_netPing(CELL * params)
1708 CELL * address;
1709 UINT maxwait = 1000, listmode = 0;
1710 UINT flag = 0;
1711 UINT count = 0;
1713 address = evaluateExpression(params);
1714 if(address->type == CELL_EXPRESSION)
1716 address = (CELL *)address->contents;
1717 listmode = 1;
1719 else if(address->type != CELL_STRING)
1720 return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, address));
1722 params = params->next;
1723 if(params != nilCell)
1725 params = getInteger(params, &maxwait);
1726 if(params != nilCell)
1727 params = getInteger(params, &count);
1728 flag = getFlag(params);
1731 return(ping(address, (int)maxwait, (int)listmode, (int)count, (int)flag));
1734 #if defined(IPV6)
1735 /* datalen 56 + iplen 60 + icmplen 76 */
1736 #define PLEN 192 /* 192 or 64 ? */
1737 #else
1738 #define PLEN 64
1739 #endif
1741 CELL * ping(CELL * address, int maxwait, int listmode, int maxCount, int flag)
1743 char * host;
1744 char * ptr;
1745 char * hostaddr = NULL;
1746 struct hostent *hp;
1747 unsigned char packet[PLEN];
1748 struct ip *ip;
1749 #ifdef IPV6
1750 struct icmp6_hdr *icp = (struct icmp6_hdr *) packet;
1751 struct sockaddr_in6 whereto;
1752 struct sockaddr_in6 from;
1753 struct icmp6_filter filter;
1754 char IPaddress[40];
1755 #else
1756 struct sockaddr_in whereto;
1757 struct sockaddr_in from;
1758 struct icmp *icp = (struct icmp *) packet;
1759 #endif
1760 int s, sockopt;
1761 #ifdef TRU64
1762 unsigned long fromlen;
1763 #else
1764 #ifdef OS2
1765 int fromlen;
1766 #else
1767 unsigned int fromlen;
1768 #endif
1769 #endif
1770 int broadcast = 0;
1771 int size, ipNo, startIp = 0, endIp = 0;
1772 int timeout = 0, tdiff;
1773 int sendCount = 0, receiveCount = 0, ping_sequence = 0;
1774 size_t len;
1775 struct timeval tv, tp;
1776 CELL * result = NULL;
1777 CELL * link = NULL;
1778 char buff[64];
1780 if ((s = socket(ADDR_TYPE, SOCK_RAW, ICMP_TYPE)) < 0)
1781 return(netError(ERR_INET_OPEN_SOCKET));
1783 #ifdef IPV6
1784 ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &filter);
1785 setsockopt (s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter));
1786 sockopt = 1;
1787 /* setsockopt (s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &sockopt, sizeof (sockopt)); */
1788 #endif
1790 gettimeofday(&tv, NULL );
1792 /* for each list-IP */
1793 while(address != nilCell)
1795 mySleep(1);
1796 if(address->type != CELL_STRING)
1798 shutdown(s, SHUT_RDWR);
1799 return(errorProcExt(ERR_STRING_EXPECTED, address));
1802 host = (char *)address->contents;
1803 len = address->aux - 1;
1805 #ifndef IPv6
1806 if(strncmp(host + len - 2, ".*", 2) == 0)
1808 startIp = 1;
1809 endIp = 254;
1810 len--;
1812 else
1814 startIp = endIp = 0;
1815 ptr = host + len - 1;
1816 while(isdigit((int)*ptr)) --ptr;
1817 if(*ptr == '-')
1819 endIp = atoi(ptr + 1);
1820 --ptr;
1821 while(isdigit((int)*ptr)) --ptr;
1822 if(*ptr == '.')
1824 startIp = atoi(ptr + 1);
1825 len = ptr - host + 1;
1827 else endIp = startIp = 0;
1828 if(endIp < startIp) endIp = startIp;
1831 #endif
1833 /* ping ip range */
1834 for(ipNo = startIp; ipNo <= endIp; ipNo++)
1836 if(startIp)
1838 if(hostaddr == NULL) hostaddr = alloca(len + 4);
1839 memcpy(hostaddr, host, len);
1840 snprintf(hostaddr + len, 4, "%d", ipNo);
1842 else
1843 hostaddr = host;
1845 /* target host address info */
1846 /* printf("->%s\n", hostaddr); */
1847 #ifdef IPV6
1848 memset((char *)&whereto, 0, sizeof(struct sockaddr_in6));
1849 whereto.sin6_family = AF_INET6;
1850 if(!(hp = gethostbyname2(hostaddr, AF_INET6)))
1852 shutdown(s, SHUT_RDWR);
1853 return(netError(ERR_INET_HOST_UNKNOWN));
1855 memcpy((char *)&(whereto.sin6_addr), hp->h_addr_list[0], hp->h_length);
1856 #else
1857 memset((char *)&whereto, 0, sizeof(struct sockaddr_in));
1858 whereto.sin_family = AF_INET;
1859 if(!(hp = gethostbyname2(hostaddr, AF_INET)))
1861 shutdown(s, SHUT_RDWR);
1862 return(netError(ERR_INET_HOST_UNKNOWN));
1864 memcpy((void *)&whereto.sin_addr, hp->h_addr, hp->h_length);
1865 broadcast = ((whereto.sin_addr.s_addr & 0x000000ff) == 255);
1866 #endif
1867 if(broadcast)
1869 sockopt = 1;
1870 setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &sockopt, sizeof(sockopt));
1873 /* ping */
1874 memset(icp, 0, PLEN);
1875 #ifdef IPV6
1876 icp->icmp6_type = ICMP6_ECHO_REQUEST;
1877 icp->icmp6_code = 0;
1878 icp->icmp6_cksum = 0;
1879 icp->icmp6_seq = ping_sequence;
1880 icp->icmp6_id = getpid() & 0xFFFF;
1881 gettimeofday((struct timeval *)&icp->icmp6_data8[4], NULL);
1883 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
1884 setsockopt(s, SOL_RAW, IPV6_CHECKSUM, (char *)&sockopt, sizeof(sockopt));
1885 sockopt = 1;
1886 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *)&sockopt, sizeof(sockopt));
1889 #else
1890 icp->icmp_type = ICMP_ECHO;
1891 icp->icmp_code = 0;
1892 icp->icmp_cksum = 0;
1893 icp->icmp_seq = ping_sequence;
1894 icp->icmp_id = getpid() & 0xFFFF;
1895 gettimeofday((struct timeval *)&icp[1], NULL);
1896 icp->icmp_cksum = in_cksum((unsigned short *) icp, PLEN );
1897 #endif
1898 while(wait_ready(s, 10000, READY_WRITE) <= 0)
1900 gettimeofday(&tp, NULL);
1901 if((timeout = (timediff(tp, tv) > maxwait))) break;
1902 continue;
1905 size = sendto(s, packet, PLEN, 0,(struct sockaddr *)&whereto, sizeof(struct sockaddr));
1906 if(size != PLEN)
1908 if(errno == EHOSTUNREACH || errno == EHOSTDOWN)
1910 if(flag)
1912 snprintf(buff, 16, "errno: %d", errno);
1913 #ifdef IPV6
1914 memset(IPaddress, 0, 40);
1915 inet_ntop(AF_INET6, &whereto.sin6_addr, IPaddress, 40);
1916 link = addResult(&result, link,
1917 makePair(stuffString(IPaddress), stuffString(buff)));
1918 #else
1919 link = addResult(&result, link,
1920 makePair(stuffString(inet_ntoa(whereto.sin_addr)), stuffString(buff)));
1921 #endif
1923 if( !(listmode || startIp) ) break;
1924 continue;
1926 shutdown(s, SHUT_RDWR);
1927 return(netError(ERR_INET_WRITE));
1930 sendCount++;
1932 if(!listmode) break;
1933 address = address->next;
1936 /* wait for response(s) */
1937 if(maxCount == 0) maxCount = sendCount;
1938 while(sendCount)
1940 memset(packet, 0, PLEN);
1941 fromlen = sizeof(from);
1943 if(wait_ready(s, 1000, READY_READ) <= 0)
1945 gettimeofday(&tp, NULL);
1946 if((timeout = (timediff(tp, tv) > maxwait))) break;
1947 continue;
1950 if ( (len = recvfrom(s, packet, PLEN, 0, (struct sockaddr *)&from, &fromlen)) < 0)
1951 continue;
1953 ip = (struct ip *) packet;
1954 gettimeofday(&tp, NULL);
1955 #ifdef IPV6
1956 icp = (struct icmp6_hdr *)packet;
1957 if(icp->icmp6_type != ICMP6_ECHO_REPLY) continue;
1958 if(icp->icmp6_id != (getpid() & 0xFFFF)) continue;
1959 tdiff = timediff64(tp, *(struct timeval *)&icp->icmp6_data8[4]);
1960 #else
1961 icp = (struct icmp *)(packet + (ip->ip_hl << 2));
1962 if(icp->icmp_id != (getpid() & 0xFFFF)) continue;
1963 tdiff = timediff64(tp, *(struct timeval *)&icp[1]);
1964 #endif
1966 #ifdef IPV6
1967 inet_ntop(AF_INET6, &from.sin6_addr, IPaddress, 40);
1968 link = addResult(&result, link,
1969 makePair(stuffString(IPaddress), stuffInteger(tdiff)));
1970 #else
1971 link = addResult(&result, link,
1972 makePair(stuffString(inet_ntoa(from.sin_addr)), stuffInteger(tdiff)));
1973 #endif
1975 if(++receiveCount == maxCount) break;
1976 if( !(broadcast || listmode || startIp) ) break;
1979 shutdown(s, SHUT_RDWR);
1980 ping_sequence++;
1981 if(timeout) errorIdx = ERR_INET_TIMEOUT;
1982 else errorIdx = 0;
1983 return(result == NULL ? getCell(CELL_EXPRESSION) : result);
1986 CELL * addResult(CELL * * result, CELL * cell, CELL * new)
1988 if(*result == NULL)
1990 *result = getCell(CELL_EXPRESSION);
1991 ((CELL *)(*result))->contents = (UINT)new;
1993 else
1994 cell->next = new;
1996 return(new);
1999 CELL * makePair(CELL * left, CELL * right)
2001 CELL * cell = getCell(CELL_EXPRESSION);
2003 cell->contents = (UINT)left;
2004 left->next = right;
2006 return(cell);
2009 int in_cksum(unsigned short * addr, int len)
2011 int nleft = len;
2012 unsigned short *w = addr;
2013 unsigned short answer;
2014 int sum = 0;
2016 while( nleft > 1 ) {
2017 sum += *w++;
2018 nleft -= 2;
2021 if( nleft == 1 ) {
2022 u_short u = 0;
2023 *(unsigned char *)(&u) = *(unsigned char *)w ;
2024 sum += u;
2027 sum = (sum >> 16) + (sum & 0xffff);
2028 sum += (sum >> 16);
2029 answer = ~sum;
2030 return (answer);
2033 #endif /* NET_PING */
2036 /* check socket for readability or error
2037 return 0 if the time limit expires or -1
2038 on error
2040 int wait_ready(int sock, INT64 wait, int mode)
2042 struct timeval timeOut;
2043 fd_set socketSet;
2045 FD_ZERO(&socketSet);
2046 FD_SET(sock, &socketSet);
2048 timeOut.tv_sec = wait/1000000;
2049 timeOut.tv_usec = wait - timeOut.tv_sec * 1000000;
2051 if(mode == READY_READ)
2052 return(select(FD_SETSIZE, &socketSet, NULL, &socketSet, &timeOut));
2053 else
2054 return(select(FD_SETSIZE, NULL, &socketSet, &socketSet, &timeOut));
2058 /* ----------------------------- socket->filestream stuff for win32 ------------------------*/
2060 #ifdef WIN_32
2063 These functions use the FILE structure to store the raw file handle in '->_file' and
2064 set ->_flag to 0xFFFF, to identify this as a faked FILE structure.
2067 FILE * win32_fdopen(int handle, const char * mode)
2069 FILE * fPtr;
2071 if((fPtr = (FILE *)malloc(sizeof(FILE))) == NULL)
2072 return(NULL);
2074 memset(fPtr, 0, sizeof(FILE));
2077 #ifdef WIN_32
2078 fPtr->_file = handle;
2079 fPtr->_flag = 0xFFFF;
2080 #endif
2082 return(fPtr);
2085 int win32_fclose(FILE * fPtr)
2087 if(isSocketStream(fPtr))
2088 return(close(getSocket(fPtr)));
2091 return(fclose(fPtr));
2095 /* for a full fprintf with format string and parameters
2096 see version previous to 9.0.2
2098 int win32_fprintf(FILE * fPtr, char * buffer)
2100 int pSize;
2102 if(!isSocketStream(fPtr))
2103 return(fprintf(fPtr, buffer));
2105 pSize = strlen(buffer);
2107 if((pSize = sendall(getSocket(fPtr), buffer, pSize)) == SOCKET_ERROR)
2109 close(getSocket(fPtr));
2110 return(-1);
2113 return(pSize);
2116 int win32_fgetc(FILE * fPtr)
2118 char chr;
2120 if(!isSocketStream(fPtr))
2121 return(fgetc(fPtr));
2123 if(recv(getSocket(fPtr), &chr, 1, NO_FLAGS_SET) <= 0)
2125 close(getSocket(fPtr));
2126 return(-1);
2129 return(chr);
2133 char * win32_fgets(char * buffer, int size, FILE * fPtr)
2135 int bytesReceived = 0;
2136 char chr;
2138 if(!isSocketStream(fPtr))
2139 return(fgets(buffer, size - 1, fPtr));
2141 while(bytesReceived < size)
2143 if(recv(getSocket(fPtr), &chr, 1, NO_FLAGS_SET) <= 0)
2145 close(getSocket(fPtr));
2146 return(NULL);
2149 *(buffer + bytesReceived++) = chr;
2151 if(chr == '\n') break;
2154 *(buffer + bytesReceived) = 0;
2156 return(buffer);
2159 #endif
2161 /* eof */