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.
>