Hey all,

I've written a tiny (90 SLOC) tool for connecting to an IRC server and
streaming the connection over stdin/stdout, while responding to (and
filtering out) pings. I just wrote this so I could write simpler IRC
bots without having to worry about TCP, pings, or having to reconnect
every time I want to re-exec when I update the bot. The auto-ping also
works well for logging. I don't know, it might come in handy for
someone.
Thanks,
cls
/* (c) 2012, Connor Lane Smith <c...@lubutu.com> */
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>

#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);
}

Reply via email to