Hi all, linking ii against uClibc gives a warning about it using gethostbyname(). I have modified it to use getaddrinfo():
diff --git a/ii.c b/ii.c index d93266c..117dcf5 100644 --- a/ii.c +++ b/ii.c @@ -8,6 +8,7 @@ #include <sys/socket.h> #include <sys/select.h> #include <netinet/in.h> +#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> @@ -23,7 +24,7 @@ #define PIPE_BUF 4096 #endif #define PING_TIMEOUT 300 -#define SERVER_PORT 6667 +#define SERVER_PORT "6667" enum { TOK_NICKSRV = 0, TOK_USER, TOK_CMD, TOK_CHAN, TOK_ARG, TOK_TEXT, TOK_LAST }; typedef struct Channel Channel; @@ -151,27 +152,32 @@ static void login(char *key, char *fullname) { write(irc, message, strlen(message)); /* login */ } -static int tcpopen(unsigned short port) { - int fd; - struct sockaddr_in sin; - struct hostent *hp = gethostbyname(host); - - memset(&sin, 0, sizeof(struct sockaddr_in)); - if(!hp) { - perror("ii: cannot retrieve host information"); - exit(EXIT_FAILURE); - } - sin.sin_family = AF_INET; - memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); - sin.sin_port = htons(port); - if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("ii: cannot create socket"); - exit(EXIT_FAILURE); - } - if(connect(fd, (const struct sockaddr *) &sin, sizeof(sin)) < 0) { - perror("ii: cannot connect to host"); +static int tcpopen(const char* port) { + int fd, err; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + .ai_flags = 0, + }, *res, *it; + + err = getaddrinfo(host, port, &hints, &res); + if(err < 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err)); exit(EXIT_FAILURE); } + for (it = res; it; it = it->ai_next) { + if((fd = socket(it->ai_family, it->ai_socktype, it->ai_protocol)) < 0) { + perror("ii: cannot create socket"); + } else if(connect(fd, it->ai_addr, it->ai_addrlen)) { + perror("ii: cannot connect to host"); + close(fd); + fd = -1; + } else break; + + } + freeaddrinfo(res); + if (fd == -1) exit(EXIT_FAILURE); return fd; } @@ -455,7 +461,7 @@ static void run() { int main(int argc, char *argv[]) { int i; - unsigned short port = SERVER_PORT; + const char* port = SERVER_PORT; struct passwd *spw = getpwuid(getuid()); char *key = NULL, *fullname = NULL; char prefix[_POSIX_PATH_MAX]; @@ -472,7 +478,7 @@ int main(int argc, char *argv[]) { switch (argv[i][1]) { case 'i': snprintf(prefix,sizeof(prefix),"%s", argv[++i]); break; case 's': host = argv[++i]; break; - case 'p': port = strtol(argv[++i], NULL, 10); break; + case 'p': port = argv[++i]; break; case 'n': snprintf(nick,sizeof(nick),"%s", argv[++i]); break; case 'k': key = getenv(argv[++i]); break; case 'f': fullname = argv[++i]; break; The advantage of this approach: If hostname resolution returns multiple addresses and the first one doesn't work, all of them will be tried until one works. And IPv6 is handled transparently. (BTW: Shouldn't your code have used the family from the hostent instead of hardcoding AF_INET?) And ports can be named symbolically. In any case, I also wrote a program to do DCC file transfers. It's probably horrible from a technical perspective, since there's next to no error checking, but hey, at least it's free! Or so. Consider it gifted to the public domain, though I don't think that sufficient intellectual work went into it to even merit copyright. #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char* argv[]) { if (argc < 4) return 1; int sock; FILE* out; struct sockaddr_in sin; size_t total = 0; out = fopen(argv[1], "wb"); if (!out) return 2; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return 3; sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(atoi(argv[2])); sin.sin_port = htons(atoi(argv[3])); if (connect(sock, (struct sockaddr*)&sin, sizeof sin) < 0) return 4; while (1) { char buf[1500]; ssize_t rv; rv = recv(sock, buf, sizeof buf, 0); if (rv <= 0) { fclose(out); close(sock); return (rv == 0)?0:5; } fwrite(buf, 1, rv, out); total += rv; *(uint32_t*)buf = htonl(total); send(sock, buf, 4, 0); } } The name of the above program is dcc. Basically, what you do is, when someone offers you a file and you intend to accept, that someone will send you a message of the form DCC SEND <filename> <ip address> <port> <totalsize> You just run this program like dcc outfilename <ip address> <port> with IP address and port copied from the file offer (Both will just be single integers). The file name can be, too, if you want that. In any case, this tool will then run and output all the gathered data to the file name mentioned. As you can see, the DCC file transfer protocol is not particularly hard on the client side, but I couldn't think of a shell script to do the job, so I wrote a tool for that. Basically, I didn't know how to send the current size of the file as a 32-bit big endian binary number. Hope these help someone, Markus