Date: Wed, 22 Oct 2003 19:53:10 -0700 From: Lev Walkin <vlm@netli.com> To: Edwin Groothuis <edwin@mavetju.org> Cc: freebsd-net@freebsd.org Subject: Re: UDP connect: Can't assign requested address or "how todetermine the outgoing IP address?" Message-ID: <3F974296.9040304@netli.com> In-Reply-To: <20031023023146.GA34131@k7.mavetju> References: <20031023023146.GA34131@k7.mavetju>
next in thread | previous in thread | raw e-mail | index | archive | help
Edwin Groothuis wrote: > Hello, > > I got a nice piece of code (see attachment) which could be used to > determine the outgoing IP address for an UDP socket. It works without > problem under Linux, but it fails on FreeBSD (-current and -stable) > during the call to connect() with the error: "Can't assign requested > address". The code looks like the udpcli09.c example in Richard > Stevens 'Unix Network Programming' book, which states it doesn't > work on SVR4 derived kernels. > > So, the question is, how can I determine the outgoing IP address > for a socket? Everything's fine apart from one thing: connect() does not like to connect to places with destination port equal to zero. > attached code can be compiled with "gcc -Wall -g -o a a.c && ./a" > > > > ------------------------------------------------------------------------ > > #include <sys/types.h> > #include <sys/socket.h> > #include <netinet/in.h> > #include <errno.h> > #include <netdb.h> > #include <string.h> > #include <stdio.h> > #include <unistd.h> > #include <stdlib.h> > > int guess_local_address(char *address_to_reach,char **loc); > > int main(void) { > char *loc; > > guess_local_address("218.185.88.1",&loc);printf("%s\n",loc); > guess_local_address("192.168.1.3",&loc);printf("%s\n",loc); > guess_local_address("127.0.0.1",&loc);printf("%s\n",loc); > return 0; > } > > int guess_local_address(char *address_to_reach,char **loc){ > int s,err; > struct addrinfo hints; > struct addrinfo *res=NULL; > struct sockaddr addr; > int sock; > > *loc=NULL; > > printf("Trying %s: ",address_to_reach); > > memset(&hints,0,sizeof(hints)); > hints.ai_family=PF_UNSPEC; > hints.ai_socktype=SOCK_DGRAM; > hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME; > > err=getaddrinfo(address_to_reach,NULL,&hints,&res); > if (err<0){ > printf("getaddrinfo: %s\n",gai_strerror(err)); > return -1; > } > if (res==NULL){ > printf("getaddrinfo reported nothing !"); > return -1; > } > sock=socket(res->ai_family,SOCK_DGRAM,0); > if (err<0){ > printf("Error in socket: %s\n",strerror(errno)); > return -1; > } > { > struct sockaddr_in servaddr; > memset(&servaddr,sizeof(servaddr),0); > servaddr.sin_family=AF_INET; > servaddr.sin_addr.s_addr=htonl(INADDR_ANY); > servaddr.sin_port=htons(0); > err=bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr)); > if (err<0){ > printf("Error in bind: %s\n",strerror(errno)); > return -1; > } > } > s=1; > err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&s,sizeof(int)); > if (err<0){ > printf("Error in setsockopt: %s\n",strerror(errno)); > return -1; > } /* * This will do. Note that it assumes AF_INET. */ ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(80); > err=connect(sock,res->ai_addr,res->ai_addrlen); > if (err<0) { > printf("Error in connect: %s\n",strerror(errno)); > return -1; > } > freeaddrinfo(res); > res=NULL; > s=sizeof(addr); > err=getsockname(sock,(struct sockaddr*)&addr,&s); > if (err<0) { > printf("Error in getsockname: %s\n",strerror(errno)); > return -1; > } > *loc=malloc(30); > err=getnameinfo(&addr,s,*loc,30,NULL,0,NI_NUMERICHOST); > if (err<0){ > printf("getnameinfo error:%s",strerror(errno)); > return -1; > } > close(sock); > return 0; > } > -- Lev Walkin vlm@netli.com
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3F974296.9040304>