• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Async UDP socket and ICMP error detection
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Async UDP socket and ICMP error detection


  • Subject: Async UDP socket and ICMP error detection
  • From: Frédéric Germain <email@hidden>
  • Date: Mon, 10 Feb 2014 19:06:43 +0100

Hi

I'm trying to port a software that is totally async, and use c-ares, a DNS resolver async library (ii's also used by libcurl or node.js internally).

I've found a problem with the XNU/libc version I'm working on (Darwin Kernel Version 13.0.0: Thu Sep 19 22:22:27 PDT 2013; root:xnu-2422.1.72~6/RELEASE_X86_64)

To make it simple, when I'm using a "connected" UDP socket to make the DNS request, and if a ICMP error happens because there is no DNS server actually, then it's not possible to know the ICMP error happens with poll (and kqueue I think...)

I wonder if there is a correct way, or a hack, to detect this.

I wrote a simple sample program, that works fine on Linux (poll exit giving POLLERR) when trying to make a UDP request to a bad server. 
When running on my Mac 10.9, poll exits with 0, which would mean poll timeout, with I have no timeout...

To use it :
> test on a no DNS server machine (supposedly localhost)
./testso 127.0.0.1 53

> test on google DNS (OK)
./testso 8.8.8.8 53

If someone know what to do, I'd be very happy to detect whose ICMP error with a poll or a kqueue :)

Cheers

Fred

------------------- testso.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <fcntl.h>
#include <errno.h>
#include <poll.h>

// taken and adapted from http://www.linuxhowtos.org/data/6/client.c

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    int flags;
    int ret;
    char buffer[256];
    struct pollfd polldata;
    // dns request for google.com
    unsigned char req[] = { 0xd3, 0xec, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
      0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 };
    unsigned char bigbuf[256];
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);

  /* Set the socket non-blocking. */
    flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

  /* Connect to the server. */
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0 && errno != EINPROGRESS && errno != ENETUNREACH) 
        error("ERROR connecting");

    // POLLOUT for connect (means nothing for udp socket...)
    polldata.fd = sockfd;
    polldata.events = POLLOUT;

    ret = poll(&polldata, 1, -1);

    if (ret == 1 && (polldata.revents & POLLHUP)) {
        printf("poll ret %d revents %x disconnected\n", ret, polldata.revents);
        exit(0);
    }

    if (ret == 1 && (polldata.revents & POLLOUT)) {
        printf("poll ret %d revents %x POLLOUT connected\n", ret, polldata.revents);
    }
    printf("poll ret %d revents %x\n", ret, polldata.revents);

    ret = send(sockfd, req, sizeof(req), 0);
    printf("send ret %d\n", ret);

    // POLLIN for data
    polldata.fd = sockfd;
    polldata.events = (-1) & ~POLLOUT & POLLNVAL;
    polldata.events = POLLIN |POLLPRI|POLLOUT|POLLRDNORM|POLLWRNORM|POLLRDBAND|POLLWRBAND;
    polldata.events = POLLIN |POLLPRI|POLLRDNORM|POLLRDBAND;

    errno=0;
    do { 
      ret = poll(&polldata, 1, -1);
      if (ret == 1 && (polldata.revents & POLLHUP)) {
          printf("poll ret %d revents %x disconnected\n", ret, polldata.revents);
          exit(0);
      }
      if (ret == 0) {
        printf("poll ret 0 while no timeout, should not happen\n");
        break;
      } else {
        printf("poll ret %d revents %x errno %d\n", ret, polldata.revents, errno);
      }
    } while (ret == 0);


    ret = recv(sockfd, bigbuf, sizeof(bigbuf), 0);
    printf("recv ret %d errno %d\n", ret, errno); // ECONNREFUSED = 61

    close(sockfd);
    return 0;
}
 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Prev by Date: Re: Customized package
  • Next by Date: Can a dylib have an entry point?
  • Previous by thread: Re: Customized package
  • Next by thread: Can a dylib have an entry point?
  • Index(es):
    • Date
    • Thread