net.c (5549B)
1 /* 20nov07abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 #include "pico.h" 6 7 #include <netdb.h> 8 #include <sys/socket.h> 9 #include <arpa/inet.h> 10 #include <netinet/tcp.h> 11 #include <netinet/in.h> 12 13 static void ipErr(any ex, char *s) { 14 err(ex, NULL, "IP %s error: %s", s, strerror(errno)); 15 } 16 17 static int ipSocket(any ex, int type) { 18 int sd; 19 20 if ((sd = socket(AF_INET, type, 0)) < 0) 21 ipErr(ex, "socket"); 22 return sd; 23 } 24 25 static any tcpAccept(any ex, int sd) { 26 int i, sd2; 27 struct sockaddr_in addr; 28 struct timespec tv = {0,100000000}; // 100 ms 29 30 blocking(NO, ex, sd); 31 i = 200; do { 32 socklen_t len = sizeof(addr); 33 if ((sd2 = accept(sd, (struct sockaddr*)&addr, &len)) >= 0) { 34 blocking(YES, ex, sd2); 35 val(Adr) = mkStr(inet_ntoa(addr.sin_addr)); 36 initInFile(sd2,NULL), initOutFile(sd2); 37 return boxCnt(sd2); 38 } 39 nanosleep(&tv,NULL); 40 } while (errno == EAGAIN && --i >= 0); 41 blocking(YES, ex, sd); 42 return NULL; 43 } 44 45 // (port ['T] 'cnt|(cnt . cnt) ['var]) -> cnt 46 any doPort(any ex) { 47 any x, y; 48 int type, n, sd; 49 unsigned short port; 50 cell c1; 51 struct sockaddr_in addr; 52 53 memset(&addr, 0, sizeof(addr)); 54 addr.sin_family = AF_INET; 55 addr.sin_addr.s_addr = htonl(INADDR_ANY); 56 x = cdr(ex); 57 type = SOCK_STREAM; 58 if ((y = EVAL(car(x))) == T) 59 type = SOCK_DGRAM, x = cdr(x), y = EVAL(car(x)); 60 sd = ipSocket(ex, type); 61 if (isNum(y)) { 62 if ((port = (unsigned short)xCnt(ex,y)) != 0) { 63 n = 1; 64 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) < 0) 65 ipErr(ex, "setsockopt"); 66 } 67 } 68 else if (isCell(y)) 69 port = (unsigned short)xCnt(ex,car(y)); 70 else 71 argError(ex,y); 72 for (;;) { 73 addr.sin_port = htons(port); 74 if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) >= 0) 75 break; 76 if (!isCell(y) || ++port > xCnt(ex,cdr(y))) 77 close(sd), ipErr(ex, "bind"); 78 } 79 if (type == SOCK_STREAM && listen(sd,5) < 0) 80 close(sd), ipErr(ex, "listen"); 81 if (!isNil(data(c1) = EVAL(cadr(x)))) { 82 socklen_t len = sizeof(addr); 83 if (getsockname(sd, (struct sockaddr*)&addr, &len) < 0) 84 close(sd), ipErr(ex, "getsockname"); 85 Save(c1); 86 NeedVar(ex,data(c1)); 87 CheckVar(ex,data(c1)); 88 if (isSym(data(c1))) 89 Touch(ex,data(c1)); 90 val(data(c1)) = boxCnt(ntohs(addr.sin_port)); 91 drop(c1); 92 } 93 return boxCnt(sd); 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(ex,sd)) 109 return x; 110 } 111 } 112 113 // (accept 'cnt) -> cnt | NIL 114 any doAccept(any ex) { 115 return tcpAccept(ex, (int)evCnt(ex, cdr(ex))) ?: Nil; 116 } 117 118 // (host 'any) -> sym 119 any doHost(any x) { 120 struct in_addr in; 121 struct hostent *p; 122 123 x = evSym(cdr(x)); 124 { 125 char nm[bufSize(x)]; 126 127 bufString(x, nm); 128 if (inet_aton(nm, &in) && (p = gethostbyaddr((char*)&in, sizeof(in), AF_INET))) 129 return mkStr(p->h_name); 130 return Nil; 131 } 132 } 133 134 static bool server(any host, unsigned short port, struct sockaddr_in *addr) { 135 struct hostent *p; 136 char nm[bufSize(host)]; 137 138 bufString(host, nm); 139 memset(addr, 0, sizeof(struct sockaddr_in)); 140 if (!inet_aton(nm, &addr->sin_addr)) { 141 if (!(p = gethostbyname(nm)) || p->h_length == 0) 142 return NO; 143 addr->sin_addr.s_addr = ((struct in_addr*)p->h_addr_list[0])->s_addr; 144 } 145 addr->sin_port = htons(port); 146 addr->sin_family = AF_INET; 147 return YES; 148 } 149 150 // (connect 'any 'cnt) -> cnt | NIL 151 any doConnect(any ex) { 152 int sd, port; 153 cell c1; 154 struct sockaddr_in addr; 155 156 Push(c1, evSym(cdr(ex))); 157 port = evCnt(ex, cddr(ex)); 158 if (!server(Pop(c1), (unsigned short)port, &addr)) 159 return Nil; 160 sd = ipSocket(ex, SOCK_STREAM); 161 if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 162 close(sd); 163 return Nil; 164 } 165 initInFile(sd,NULL), initOutFile(sd); 166 return boxCnt(sd); 167 } 168 169 // (nagle 'cnt 'flg) -> cnt 170 any doNagle(any ex) { 171 any x, y; 172 int sd, opt; 173 174 x = cdr(ex), y = EVAL(car(x)); 175 sd = (int)xCnt(ex,y); 176 x = cdr(x), opt = isNil(EVAL(car(x)))? 1 : 0; 177 if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(int)) < 0) 178 ipErr(ex, "setsockopt"); 179 return y; 180 } 181 182 /*** UDP send/receive ***/ 183 #define UDPMAX 4096 184 static byte *UdpBuf, *UdpPtr; 185 186 static void putUdp(int c) { 187 *UdpPtr++ = c; 188 if (UdpPtr == UdpBuf + UDPMAX) 189 err(NULL, NULL, "UDP overflow"); 190 } 191 192 static int getUdp(void) { 193 if (UdpPtr == UdpBuf + UDPMAX) 194 return -1; 195 return *UdpPtr++; 196 } 197 198 // (udp 'any1 'cnt 'any2) -> any 199 // (udp 'cnt) -> any 200 any doUdp(any ex) { 201 any x; 202 int sd; 203 cell c1; 204 struct sockaddr_in addr; 205 byte buf[UDPMAX]; 206 207 x = cdr(ex), data(c1) = EVAL(car(x)); 208 if (!isCell(x = cdr(x))) { 209 if (recv((int)xCnt(ex, data(c1)), buf, UDPMAX, 0) < 0) 210 return Nil; 211 getBin = getUdp, UdpPtr = UdpBuf = buf; 212 return binRead() ?: Nil; 213 } 214 Save(c1); 215 if (!server(xSym(data(c1)), (unsigned short)evCnt(ex,x), &addr)) 216 x = Nil; 217 else { 218 x = cdr(x), x = EVAL(car(x)); 219 sd = ipSocket(ex, SOCK_DGRAM); 220 putBin = putUdp, UdpPtr = UdpBuf = buf, binPrint(x); 221 sendto(sd, buf, UdpPtr-buf, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); 222 close(sd); 223 } 224 drop(c1); 225 return x; 226 }