net.c (5611B)
1 /* 06feb13abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include "pico.h" 6 7 #include <netdb.h> 8 #include <arpa/inet.h> 9 #include <netinet/in.h> 10 #include <sys/socket.h> 11 12 static void ipErr(any ex, char *s) { 13 err(ex, NULL, "IP %s error: %s", s, strerror(errno)); 14 } 15 16 // (port ['T] 'cnt|(cnt . cnt) ['var]) -> cnt 17 any doPort(any ex) { 18 any x, y; 19 int type, sd, n; 20 unsigned short port; 21 struct sockaddr_in6 addr; 22 23 x = cdr(ex); 24 type = SOCK_STREAM; 25 if ((y = EVAL(car(x))) == T) 26 type = SOCK_DGRAM, x = cdr(x), y = EVAL(car(x)); 27 if ((sd = socket(AF_INET6, type, 0)) < 0) 28 ipErr(ex, "socket"); 29 closeOnExec(ex, sd); 30 n = 0; 31 if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &n, sizeof(n)) < 0) 32 ipErr(ex, "IPV6_V6ONLY"); 33 memset(&addr, 0, sizeof(addr)); 34 addr.sin6_family = AF_INET6; 35 addr.sin6_addr = in6addr_any; 36 if (isNum(y)) { 37 if ((port = (unsigned short)xCnt(ex,y)) != 0) { 38 n = 1; 39 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) < 0) 40 ipErr(ex, "SO_REUSEADDR"); 41 } 42 } 43 else if (isCell(y)) 44 port = (unsigned short)xCnt(ex,car(y)); 45 else 46 argError(ex,y); 47 for (;;) { 48 addr.sin6_port = htons(port); 49 if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) >= 0) 50 break; 51 if (!isCell(y) || ++port > xCnt(ex,cdr(y))) 52 close(sd), ipErr(ex, "bind"); 53 } 54 if (type == SOCK_STREAM && listen(sd,5) < 0) 55 close(sd), ipErr(ex, "listen"); 56 if (!isNil(y = EVAL(cadr(x)))) { 57 socklen_t len = sizeof(addr); 58 if (getsockname(sd, (struct sockaddr*)&addr, &len) < 0) 59 close(sd), ipErr(ex, "getsockname"); 60 NeedVar(ex,y); 61 CheckVar(ex,y); 62 val(y) = boxCnt(ntohs(addr.sin6_port)); 63 } 64 return boxCnt(sd); 65 } 66 67 static any tcpAccept(int sd) { 68 int i, f, sd2; 69 char s[INET6_ADDRSTRLEN]; 70 struct sockaddr_in6 addr; 71 72 f = nonblocking(sd); 73 i = 200; do { 74 socklen_t len = sizeof(addr); 75 if ((sd2 = accept(sd, (struct sockaddr*)&addr, &len)) >= 0) { 76 fcntl(sd, F_SETFL, f); 77 #ifndef __linux__ 78 fcntl(sd2, F_SETFL, 0); 79 #endif 80 inet_ntop(AF_INET6, &addr.sin6_addr, s, INET6_ADDRSTRLEN); 81 val(Adr) = mkStr(s); 82 initInFile(sd2,NULL), initOutFile(sd2); 83 return boxCnt(sd2); 84 } 85 usleep(100000); // 100 ms 86 } while (errno == EAGAIN && --i >= 0); 87 fcntl(sd, F_SETFL, f); 88 return NULL; 89 } 90 91 // (accept 'cnt) -> cnt | NIL 92 any doAccept(any ex) { 93 return tcpAccept((int)evCnt(ex, cdr(ex))) ?: Nil; 94 } 95 96 // (listen 'cnt1 ['cnt2]) -> cnt | NIL 97 any doListen(any ex) { 98 any x; 99 int sd; 100 long ms; 101 102 sd = (int)evCnt(ex, x = cdr(ex)); 103 x = cdr(x); 104 ms = isNil(x = EVAL(car(x)))? -1 : xCnt(ex,x); 105 for (;;) { 106 if (!waitFd(ex, sd, ms)) 107 return Nil; 108 if (x = tcpAccept(sd)) 109 return x; 110 } 111 } 112 113 // (host 'any) -> sym 114 any doHost(any x) { 115 x = evSym(cdr(x)); 116 { 117 struct addrinfo *lst, *p; 118 char host[NI_MAXHOST]; 119 char nm[bufSize(x)]; 120 121 bufString(x, nm); 122 if (getaddrinfo(nm, NULL, NULL, &lst)) 123 return Nil; 124 x = Nil; 125 for (p = lst; p; p = p->ai_next) { 126 if (getnameinfo(p->ai_addr, p->ai_addrlen, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD) == 0 && host[0]) { 127 x = mkStr(host); 128 break; 129 } 130 } 131 freeaddrinfo(lst); 132 return x; 133 } 134 } 135 136 static struct addrinfo *server(int type, any node, any service) { 137 struct addrinfo hints, *lst; 138 char nd[bufSize(node)], sv[bufSize(service)]; 139 140 memset(&hints, 0, sizeof(hints)); 141 hints.ai_family = AF_UNSPEC; 142 hints.ai_socktype = type; 143 bufString(node, nd), bufString(service, sv); 144 return getaddrinfo(nd, sv, &hints, &lst)? NULL : lst; 145 } 146 147 // (connect 'any1 'any2) -> cnt | NIL 148 any doConnect(any ex) { 149 struct addrinfo *lst, *p; 150 any port; 151 int sd; 152 cell c1; 153 154 Push(c1, evSym(cdr(ex))); 155 port = evSym(cddr(ex)); 156 for (p = lst = server(SOCK_STREAM, Pop(c1), port); p; p = p->ai_next) { 157 if ((sd = socket(p->ai_family, p->ai_socktype, 0)) >= 0) { 158 if (connect(sd, p->ai_addr, p->ai_addrlen) == 0) { 159 closeOnExec(ex, sd); 160 initInFile(sd,NULL), initOutFile(sd); 161 freeaddrinfo(lst); 162 return boxCnt(sd); 163 } 164 close(sd); 165 } 166 } 167 freeaddrinfo(lst); 168 return Nil; 169 } 170 171 /*** UDP send/receive ***/ 172 #define UDPMAX 4096 173 static byte *UdpBuf, *UdpPtr; 174 175 static void putUdp(int c) { 176 if (UdpPtr == UdpBuf + UDPMAX) 177 err(NULL, NULL, "UDP overflow"); 178 *UdpPtr++ = c; 179 } 180 181 static int getUdp(void) { 182 if (UdpPtr == UdpBuf + UDPMAX) 183 return -1; 184 return *UdpPtr++; 185 } 186 187 // (udp 'any1 'any2 'any3) -> any 188 // (udp 'cnt) -> any 189 any doUdp(any ex) { 190 any x, y; 191 cell c1; 192 struct addrinfo *lst, *p; 193 int sd; 194 byte buf[UDPMAX]; 195 196 x = cdr(ex), data(c1) = EVAL(car(x)); 197 if (!isCell(x = cdr(x))) { 198 if (recv((int)xCnt(ex, data(c1)), buf, UDPMAX, 0) < 0) 199 return Nil; 200 getBin = getUdp, UdpPtr = UdpBuf = buf; 201 return binRead(ExtN) ?: Nil; 202 } 203 Save(c1); 204 data(c1) = xSym(data(c1)); 205 y = evSym(x); 206 drop(c1); 207 if (lst = server(SOCK_DGRAM, data(c1), y)) { 208 x = cdr(x), x = EVAL(car(x)); 209 putBin = putUdp, UdpPtr = UdpBuf = buf, binPrint(ExtN, x); 210 for (p = lst; p; p = p->ai_next) { 211 if ((sd = socket(p->ai_family, p->ai_socktype, 0)) >= 0) { 212 sendto(sd, buf, UdpPtr-buf, 0, p->ai_addr, p->ai_addrlen); 213 close(sd); 214 freeaddrinfo(lst); 215 return x; 216 } 217 } 218 freeaddrinfo(lst); 219 } 220 return Nil; 221 }