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