2
votes

I've created connected UDP socket with this function

/* Creates connected udp socket */
int
udp_connect( const char *host, const char *serv)
{
    int             sockfd, n;
    struct addrinfo hints, *res, *ressave;

    bzero(&hints, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    if ( ( n = getaddrinfo( host, serv, &hints, &res)) != 0)
        err_quit( "udp_connect error for %s, %s: %s",
                 host, serv, gai_strerror(n));
    ressave = res;
    do {
        sockfd = socket( res->ai_family, res->ai_socktype, res->ai_protocol);
        if ( sockfd < 0)
            continue;   /* ignore this one */
                /* The call to connect with a UDP socket does not send anything
                 * to the peer. If something is wrong ( the peer is unreachable
                 * or there is no server at the specified port), the caller 
                 * does not discover that until it sends 
                 * a datagram to the peer */
        if ( connect( sockfd, res->ai_addr, res->ai_addrlen) == 0)
            break;      /* success */
        Close( sockfd); /* ignore this one */
    } while ( ( res = res->ai_next) != NULL);

    if ( res == NULL)   /* errno set from final connect() */
        err_sys( "udp_connect error for %s, %s", host, serv);

    freeaddrinfo( ressave);
    return( sockfd);
}

I would like to do a test how it behaves when peer is actually unreachable. Since call to connect() cannot result in this information we need to actually send something. I will describe what do I do and what do I get in the following snippet:

printf( "sending to %s\n", Sock_ntop_host( sa, salen));
// prints: sending to 127.0.0.1

Sendto( sockfd, "", 1, 0, sa, salen);   /* send 1-byte datagram */
// prints: nbytes:1
// it is sent, I check via tcpdump or with Wireshark that datagram
// has been sent and ICMP "destination unreachable" comes back from host

printf( "sent, errno:%d,%s\n", errno, strerror(errno));
// prints: sent, errno:0,Success

n = Recvfrom( sockfd, recvline, MAXLINE, 0, NULL, NULL);
// never gets here
printf( "received n=%d\n", n);

The Sendto function is a wrapper over sendto that just prints error and exits:

void
Sendto(int fd, const void *ptr, size_t nbytes, int flags,
       const struct sockaddr *sa, socklen_t salen)
{
    if ( sendto(fd, ptr, nbytes, flags, sa, salen) == -1)
        exit(-1);//err_sys("sendto error");
    printf( "nbytes:%d\n",nbytes); // prints: nbytes:1
}

ssize_t
Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
         struct sockaddr *sa, socklen_t *salenptr)
{
    ssize_t     n;

    if ( (n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)
        err_sys("recvfrom error");
    return(n);
}

So the call to Recvfrom blocks forever while Sendto returnes errno with code Success. How then should I code this to get notification about ICMP response? is this possible without timeout on socket?

1
Whatever is inside SendTo() needs to check the return code of sendmsg() or whatever system call you are using, and if -1 check errno for EUNREACH.user207421
@EJP Sendto is just wrapper over sendto with checking returned code. There is no sendmsg, errno is Success4pie0
There is no such thing as "errno is Success". Please post the actual code.user207421
errno is never zero, except possibly when you first start executing your program: maybe not even then. It is invalid to even test it unless an immediately preceding system call has returned -1. That's why I keep asking you to post the actual code. I'm not interested in your description of what you think it does. It doesn't work, ergo your preconceptions about it aren't correct. Post the code.user207421
Nonsense. This is Unix systems programming 101. You must test the result of any system call for -1. It doesn't matter whether it's send(), sendto(), sendmsg(), listen(), bind(), recv(), whatever. I suggest you try it instead of arguing. I certainly can't help you if you're going to ignore my advice.user207421

1 Answers

3
votes

Once you connect() a UDP socket, you can use send() and recv() instead of sendto() and recvfrom(). recv() will report an ICMP error for a connected socket.