/* (c) 2012, Connor Lane Smith */ #include #include #include #include #include #include #include #include #define MAX(x,y) ((x) > (y) ? (x) : (y)) static void stream(int, int, int); static int dial(const char *, const char *); static void eprintf(const char *, ...); int main(int argc, char *argv[]) { const char *host, *port; fd_set rfds; int srv; if(argc != 2 && argc != 3) eprintf("usage: %s host [port]\n", argv[0]); host = argv[1]; port = (argc == 3) ? argv[2] : "6667"; srv = dial(host, port); for(;;) { FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); FD_SET(srv, &rfds); if(select(MAX(STDIN_FILENO, srv) + 1, &rfds, NULL, NULL, NULL) == -1) break; if(FD_ISSET(srv, &rfds)) stream(srv, STDOUT_FILENO, 1); if(FD_ISSET(STDIN_FILENO, &rfds)) stream(STDIN_FILENO, srv, 0); } return EXIT_SUCCESS; } void stream(int in, int out, int pings) { char buf[BUFSIZ]; int n = 0, t = 0; /* DIY line buffering */ while(n < sizeof buf - 1 && (t = read(in, &buf[n], 1)) == 1) if(buf[n++] == '\n') break; if(t == -1) eprintf("read error:"); /* check for ping commands */ if(pings && n >= 5 && !strncmp(buf, "PING ", 5)) { buf[1] = 'O'; /* ping becomes pong */ out = in; } if(write(out, buf, n) != n) eprintf("write error:"); } int dial(const char *host, const char *port) { struct addrinfo hints, *res, *r; int fd; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if(getaddrinfo(host, port, &hints, &res) != 0) eprintf("cannot resolve hostname '%s':", host); for(r = res; r; r = r->ai_next) { if((fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) continue; if(connect(fd, r->ai_addr, r->ai_addrlen) == 0) break; close(fd); } freeaddrinfo(res); if(!r) eprintf("cannot connect to host '%s'\n", host); return fd; } void eprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if(fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') { fputc(' ', stderr); perror(NULL); } exit(EXIT_FAILURE); }