mplisp

miniPicoLisp with FFI and modules for Buddy BDD library, OpenGL, Gtk and GMP
git clone https://logand.com/git/mplisp.git/
Log | Files | Refs

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 }