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
#include
#include
+#include
#include
#include
#include
@@ -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
#include
#include
#include
#include
#include
#include
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
You just run this program like
dcc outfilename
with IP address and