Search code examples
csocketsudpgetaddrinfo

C - getaddrinfo returns "Servname not supported for ai_socktype"


So, after I got this error, I've been looking for an answer in here, almost everyone had a difficult way to fix this error but no one explained why this error occurs at all, so I don't find this question to be exactly duplicate.

I wrote a TCP socket in C and I used "getaddrinfo" function to make the socket work with hostnames, well it worked perfectly! you can find my codes on github.

but when I tried to create a UDP socket by "getaddrinfo" I got this error:
Servname not supported for ai_socktype

client.c

const char *host = argv[1];
const char *service = argv[2];
const char *string = argv[3];

struct addrinfo addrCriteria;
memset(&addrCriteria, 0, sizeof(addrCriteria));
addrCriteria.ai_family = AF_UNSPEC;
addrCriteria.ai_socktype = SOCK_DGRAM;
addrCriteria.ai_protocol = IPPROTO_UDP;

struct addrinfo *servAddr;
int ret = getaddrinfo(host, service, &addrCriteria, &servAddr);
if(ret != 0)
    sysError(gai_strerror(ret));

I realized that when I give "service" a numeric input like 8080, no errors would return but when I use a string as service name like "tproxy" which points to port/8081, 'gai_strerror' returns mentioned error.

Obviously, gai_strerror says: "service names not supported for 'SOCK_DGRAM' socket types", but why? I mean the exact reason for "getaddrinfo" not supporting name services over UDP sockets?
Is there any other way to use service names with UDP sockets instead of port numbers? how?


Solution

  • TL;DR: There is no tproxy UDP port.


    If you look up the tproxy service for UDP sockets in your service database,

    getent services tproxy/udp
    

    You get no output, because tproxy is not an UDP service. If you look at all tproxy services regardless of the protocol, getent services | grep -e tproxy, you'll see

    tproxy    8081/tcp
    

    which means that tproxy service is only defined for TCP protocol.

    This means that if you ask getaddrinfo() for an UDP socket for service 8081, you will not find anything, because tproxy is only defined for TCP and not UDP.

    Compare to the case where you ask for and UDP socket for xmpp-client service. At least my service database (getent services xmpp-client/udp) responds with

    xmpp-client           5222/udp jabber-client
    

    and indeed, getaddrinfo() happily provides the socket description for such UDP sockets (using xmpp-client or jabber-client as the service).

    So, there are services like xmpp-client that do have both TCP and UDP ports defined. On my system, getent services | grep -e xmpp-client shows

    xmpp-client           5222/tcp jabber-client
    xmpp-client           5222/udp jabber-client
    

    Because TCP and UDP are different protocols over IP, it makes sense that a service could use a different port number for TCP and UDP communications. So, it is unreasonable to assume that the service database should just return the same port numbers for TCP and UDP sockets.

    In other words, you encounter the error because you mistakenly assume that because some service uses a TCP port, with a name registered in the service database, you should be able to use that name to specify an UDP port number, too.

    TCP and UDP are separate protocols, and their port number spaces are separate. For example, TCP port 512 is used by the Unix exec r-service, whereas UDP port 512 is used by the biff mail notification service.