lua-users home
lua-l archive

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


Actually it worked :-)

The while loop just kept on going because the system call was
returning EAGAIN. Adding a check for that solves the issue.

-- G.

On 7/14/06, Guido Sohne <guido@sohne.net> wrote:
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.
>