lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Actually, it didn't work. I tested again on a non-existent local IP
address and it refuses to time out !!!!

:-(

-- G.

On 7/14/06, Guido Sohne <guido@sohne.net> wrote:
On 7/14/06, David Jones <drj@pobox.com> wrote:
> Generally it's unsafe to longjmp out of a signal handler.  Pretty
> much the only thing you can do in a signal handler portably and
> safely is to set a variable of type sig_atomic_t and return.  Of
> course, your platform may provide more guarantees (I doubt it).

I thought so too. I've ditched the alarm/longjmp approach and am using
setsockopt to tell the socket to use given receive and send timeouts,
and also telling the socket not to linger ...

> What's your C platform?

uClibc/uClinux running on a MC68VZ328 (Motorola 68000 variant,
Dragonball @ 33 Mhz)

> Your problem is general and thorny.  In the ideal world everything
> that might block (network, files, locks, threads, user input, alarms,
> etc) should be select(2)able, but sometimes you just can't get at the
> underlying fd.

I'd rather avoid select if I can. Code is thorny enough as it is :-)

> You may be able to make your select non-blocking before trying connect.

I tried this. It appears to work.

network.lua:

function net.ping(host, timeout)
        local ret, err = socket.ping(host, timeout)
        print('ret: ' .. tostring(ret) .. ' err: ' .. tostring(err))
end

net.ping('10.0.0.100', 3)
net.ping('www.google.com', 3)
net.ping('64.233.161.99', 10)

gives me

# lua ne*
ret: true err: nil
ret: nil err: bad IP address: Success
ret: nil err: ping write incomplete: Network is unreachable

using the below implementation of ping (adapted from busybox, adding
linger and timeouts)

#define DEFDATALEN      56
#define MAXIPLEN        60
#define MAXICMPLEN      76

static int pPing(lua_State *L)
{
        struct in_addr hostaddr;
        struct hostent *h;
        struct sockaddr_in pingaddr;
        struct icmp *pkt;
        struct timeval timeout;
        struct linger lingrr;
        int pingsock, c, secs, ret;
        const char *host;
        char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];

        host = lua_tostring(L, 1);
        secs = (int) lua_tonumber(L, 2);

        if ((pingsock = socket(AF_INET, SOCK_RAW, 1)) < 0)      /* 1 == ICMP */
                goto notreachable;

        memset(&pingaddr, 0, sizeof(struct sockaddr_in));
        pingaddr.sin_family = AF_INET;

        if (!(h = gethostbyname(host)))
                goto notreachable;

        memcpy(&(pingaddr.sin_addr), h->h_addr, sizeof(pingaddr.sin_addr));

        pkt = (struct icmp *) packet;
        memset(pkt, 0, sizeof(packet));
        pkt->icmp_type = ICMP_ECHO;
        pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));

        /* set timeout to user supplied value */
        timeout.tv_sec = secs;
        timeout.tv_usec = 0;

        /* set socket to linger for user supplied time */
        lingrr.l_onoff = 1;
        lingrr.l_linger = secs;

    if (setsockopt (pingsock, SOL_SOCKET, SO_LINGER, (char *)&lingrr,
sizeof lingrr) < 0)
                goto notreachable;
        if (setsockopt (pingsock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof timeout) < 0)
                goto notreachable;
        if (setsockopt (pingsock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof timeout) < 0)
                goto notreachable;

        c = sendto(pingsock, packet, sizeof(packet), 0,
                           (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));

        if (c < 0 || c != sizeof(packet)) {
                goto notreachable;
        }

        /* listen for replies */
        while (1) {
                struct sockaddr_in from;
                socklen_t fromlen = sizeof(from);

                if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
                                                  (struct sockaddr *) &from, (socklen_t *)&fromlen)) < 0) {
                        if (errno == EINTR)
                                continue;
                        if (errno == ETIMEDOUT)
                                goto notreachable;
                        continue;
                }
                if (c >= 76) {                  /* ip + icmp */
                        struct iphdr *iphdr = (struct iphdr *) packet;

                        pkt = (struct icmp *) (packet + (iphdr->ihl << 2));     /* skip ip hdr */
                        if (pkt->icmp_type == ICMP_ECHOREPLY)
                                break;
                }
        }

        close(pingsock);
        lua_pushboolean(L, 1);
        return 1;

notreachable:
        ret = pusherror(L, NULL);
        close(pingsock);
        return ret;
}

static int in_cksum(unsigned short *buf, int sz)
{
        int nleft = sz;
        int sum = 0;
        unsigned short *w = buf;
        unsigned short ans = 0;

        while (nleft > 1) {
                sum += *w++;
                nleft -= 2;
        }

        if (nleft == 1) {
                *(unsigned char *) (&ans) = *(unsigned char *) w;
                sum += ans;
        }

        sum = (sum >> 16) + (sum & 0xFFFF);
        sum += (sum >> 16);
        ans = ~sum;
        return (ans);
}

Hope this helps someone later :-)

-- G.