Exemple #1
0
void
lsi_b_regsig(int sig, void (*sigfn)(int))
{
#if HAVE_SIGACTION
	struct sigaction act;
	act.sa_handler = sigfn;
	act.sa_flags = 0;
	if (sigemptyset(&act.sa_mask) != 0) {
		WE("sigemptyset");
	} else if (sigaction(sig, &act, NULL) != 0) {
		WE("sigaction");
	}
#else
	W("No signal support; use a real OS for that");
#endif
	return;
}
bool
writeall(int sck, char *buf, size_t len)
{
	size_t c = 0;
	while (c < len) {
		errno = 0;
		ssize_t n = write(sck, buf + c, len - c);
		if (n == -1) {
			WE("failed to write");
			return false;
		}
		c += n;
	}
	return true;
}
Exemple #3
0
/* attempt to read more data from the ircd into our read buffer.
 * returns 1 if something was read; 0 on timeout; -1 on failure */
static int
read_more(sckhld sh, struct readctx *rctx, uint64_t to_us)
{
	/* no sizeof rctx->workbuf here because it's one bigger than WORKBUF_SZ
	 * and we don't want to fill the last byte with data; it's a dummy */
	size_t remain = WORKBUF_SZ - (rctx->eptr - rctx->workbuf);
	if (!remain) { /* no more space left in receive buffer */
		D("Buffer is full");
		if (rctx->wptr == rctx->workbuf) { /* completely full */
			E("input too long");
			return -1;
		}

		/* make additional room by moving data to the beginning */
		size_t datalen = (size_t)(rctx->eptr - rctx->wptr);
		memmove(rctx->workbuf, rctx->wptr, datalen);
		rctx->wptr = rctx->workbuf;
		rctx->eptr = &rctx->workbuf[datalen];

		remain = WORKBUF_SZ - (rctx->eptr - rctx->workbuf);
		D("Moved %zu bytes to the front; space: %zu", datalen, remain);
	}

	V("Reading more data (max. %zu bytes, timeout: %"PRIu64, remain, to_us);
	long n = read_wrap(sh, rctx->eptr, remain, to_us);
	// >0: Amount of bytes read
	// 0: timeout
	// -1: Failure
	// -2: EOF
	if (n <= 0) {
		if (n < 0)
			n == -2 ?  W("read: EOF") : WE("read failed");
		else
			V("Timeout");
		return n;
	}

	V("Got %ld more bytes", n);

	rctx->eptr += n;
	return 1;
}
Exemple #4
0
static void
init(int *argc, char ***argv, struct settings_s *sett)
{
	if (setvbuf(stdin, NULL, _IOLBF, 0) != 0)
		WE("setvbuf stdin");

	if (setvbuf(stdout, NULL, _IOLBF, 0) != 0)
		WE("setvbuf stdout");

	g_irc = irc_init();

	irc_set_track(g_irc, true);

	irc_set_nick(g_irc, "iwat");
	irc_set_uname(g_irc, "iwat");
	irc_set_fname(g_irc, "irc netwat");
	irc_set_conflags(g_irc, 0);
	irc_regcb_conread(g_irc, conread, 0);

	sett->heartbeat_us = DEF_HEARTBEAT_MS * 1000u;
	sett->cfwait_s = DEF_CONFAILWAIT_S;
	sett->verb = DEF_VERB;
	sett->scto_us = DEF_CONTO_SOFT_MS * 1000u;
	sett->hcto_us = DEF_CONTO_HARD_MS * 1000u;

	process_args(argc, argv, sett);

	if (!*argc)
		C("no server given");

	for (int i = 0; i < *argc; i++) {
		char host[256];
		uint16_t port;
		bool ssl = false;
		lsi_ut_parse_hostspec(host, sizeof host, &port, &ssl, (*argv)[i]);

		/* we choke on all other sorts of invalid addrs/hosts later */

		struct srvlist_s *node = MALLOC(sizeof *node);
		if (!node)
			CE("malloc failed");

		node->host = STRDUP(host);
		node->port = port;
		node->ssl = ssl;
		node->next = NULL;

		if (!g_srvlist)
			g_srvlist = node;
		else {
			struct srvlist_s *n = g_srvlist;
			while (n->next)
				n = n->next;
			n->next = node;
		}
	}

	irc_set_connect_timeout(g_irc, g_sett.scto_us, g_sett.hcto_us);

	D("initialized");
	return;
}
Exemple #5
0
int addr_mksocket(const char *host, const char *service,
    int socktype, int aflags, conbind_t func,
    struct sockaddr *sockaddr, size_t *addrlen,
    int64_t softto_us, int64_t hardto_us)
{
	D("invoked: host='%s', serv='%s', scktype: %d, aflags: %d, func: %s, sto=%lu, hto=%lu", host, service, socktype, aflags, !func ? "(none)" : func == connect ? "connect" : func == bind ? "bind" : "(unkonwn)", softto_us, hardto_us);

	struct addrinfo *ai_list = NULL;
	struct addrinfo hints;
	int64_t hardtsend = hardto_us ? tstamp_us() + hardto_us : 0;
	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = socktype;
	hints.ai_protocol = 0;
	hints.ai_flags = aflags;
	if (isdigitstr(service))
		hints.ai_flags |= AI_NUMERICSERV;


	D("calling getaddrinfo on '%s:%s'", host, service);

	int r = getaddrinfo(host, service, &hints, &ai_list);

	if (r != 0) {
		W("getaddrinfo() failed: %s", gai_strerror(r));
		return -1;
	}

	if (!ai_list) {
		W("getaddrinfo() result address list empty");
		return -1;
	}

	bool success = false;
	int sck = -1;

	D("iterating over result list...");
	for (struct addrinfo *ai = ai_list; ai; ai = ai->ai_next) {
		sck = -1;
		if (hardtsend && hardtsend - tstamp_us() <= 0) {
			W("hard timeout");
			return 0;
		}

		D("next result, creating socket (fam=%d, styp=%d, prot=%d)",
		    ai->ai_family, ai->ai_socktype, ai->ai_protocol);

		sck = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (sck < 0) {
			WE("cannot create socket");
			continue;
		}

		char peeraddr[64] = "(non-INET/INET6)";
		unsigned short peerport = 0;

		if (ai->ai_family == AF_INET) {
			struct sockaddr_in *sin =
			    (struct sockaddr_in*)ai->ai_addr;

			inet_ntop(AF_INET, &sin->sin_addr,
			    peeraddr, sizeof peeraddr);

			peerport = ntohs(sin->sin_port);
		} else if (ai->ai_family == AF_INET6) {
			struct sockaddr_in6 *sin =
			    (struct sockaddr_in6*)ai->ai_addr;

			inet_ntop(AF_INET6, &sin->sin6_addr,
			    peeraddr, sizeof peeraddr);

			peerport = ntohs(sin->sin6_port);
		}

		char portstr[7];
		snprintf(portstr, sizeof portstr, ":%hu", peerport);
		strNcat(peeraddr, portstr, sizeof peeraddr);

		int opt = 1;
		socklen_t optlen = sizeof opt;

		D("peer addr is '%s'", peeraddr);

		if (sockaddr)
			*sockaddr = *(ai->ai_addr);
		if (addrlen)
			*addrlen = ai->ai_addrlen;
		
		if (func) {
			D("going non-blocking");
			if (setblocking(sck, false) == -1) {
				WE("failed to enable nonblocking mode");
				close(sck);
				continue;
			}

			D("set to nonblocking mode, calling the backend function...");
			errno = 0;
			bool doselect = false;
			int r = func(sck, ai->ai_addr, ai->ai_addrlen);

			if (r == -1 && (errno != EINPROGRESS)) {
				WE("backend failed");
				close(sck);
				continue;
			} else if (r == -1)
				doselect = true;

			int64_t trem = 0;
			D("backend returned with %d", r);
			if (doselect) {
				if (hardtsend) {
					trem = hardtsend - tstamp_us();
					if (trem <= 0) {
						D("hard timeout detected");
						close(sck);
						continue;
					}
				}

				int64_t softtsend = softto_us ? tstamp_us() + softto_us : 0;

				if (softtsend) {
					int64_t trem_tmp = softtsend - tstamp_us();

					if (trem_tmp <= 0) {
						W("soft timeout");
						close(sck);
						continue;
					}

					if (trem_tmp < trem)
						trem = trem_tmp;
				}

				D("calling io_select1w (timeout: %lld us)", trem);
				r = io_select1w(sck, trem, true);

				if (r < 0) {
					WE("select() failed");
					close(sck);
					continue;
				} else if (!r) {
					W("select() timeout");
					close(sck);
					continue;
				} else
					D("selected!");

				D("calling getsockopt to query error state");
				if (getsockopt(sck, SOL_SOCKET, SO_ERROR, &opt, &optlen) != 0) {
					W("getsockopt failed");
					close(sck);
					continue;
				}

				if (opt == 0) {
					I("socket in good shape! ('%s')", peeraddr);
					if (setblocking(sck, true) == -1) {
						WE("failed to disable nonblocking mode");
						close(sck);
						continue;
					}
					success = true;
					break;
				} else {
					char errstr[256];
					strerror_r(opt, errstr, sizeof errstr);
					W("backend function failed (%d: %s)", opt, errstr);
					close(sck);
					continue;
				}
			} else {
				I("There we go... ('%s')", peeraddr);
				if (setblocking(sck, true) == -1) {
					WE("failed to disable nonblocking mode");
					close(sck);
					continue;
				}
				success = true;
				break;
			}

		} else {
			success = true;
			break;
		}
	}
	
	D("after loop; alling freeaddrinfo then returning %d", sck);

	freeaddrinfo(ai_list);

	return success ? sck : -1;
}
int
connect_socket(const char *host, unsigned short port, unsigned long to_us)
{
	int64_t tsend = to_us ? timestamp_us() + to_us : 0;
	struct addrinfo *ai_list = NULL;
	struct addrinfo hints;
	memset(&hints, 0, sizeof hints);
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;
	hints.ai_flags = AI_NUMERICSERV;
	char portstr[6];
	snprintf(portstr, sizeof portstr, "%hu", port);

	int r = getaddrinfo(host, portstr, &hints, &ai_list);

	if (r != 0) {
		W("%s", gai_strerror(r));
		return -1;
	}

	if (!ai_list) {
		W("result address list empty");
		return -1;
	}

	int sck = -1;
	for (struct addrinfo *ai = ai_list; ai; ai = ai->ai_next)
	{
		errno = 0;
		sck = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (sck < 0) {
			WE("cannot create socket");
			continue;
		}
		
		errno = 0;
		if (fcntl(sck, F_SETFL, O_NONBLOCK) == -1) {
			WE("failed to enable nonblocking mode");
			close(sck);
			sck = -1;
			continue;
		}
		
		D("set to nonblocking mode, calling connect() now");
		errno = 0;
		int r = connect(sck, ai->ai_addr, ai->ai_addrlen);

		if (r == -1 && (errno != EINPROGRESS)) {
			WE("connect() failed");
			close(sck);
			sck = -1;
			continue;
		}

		int opt = 1;
		socklen_t optlen = sizeof opt;
		struct timeval tout;
		tout.tv_sec = 0;
		tout.tv_usec = 0;
		int64_t trem = 0;

		for(;;) {
			if (tsend)
			{
				trem = tsend - timestamp_us();
				if (trem <= 0) {
					W("timeout reached while in 3WHS");
					close(sck);
					sck = -1;
					goto outer_bot;
				}

				tconv(&tout, &trem, false);
			}

			fd_set fds;
			FD_ZERO(&fds);
			FD_SET(sck, &fds);

			errno = 0;
			r = select(sck+1, NULL, &fds, NULL, tsend ? &tout : NULL);
			if (r < 0)
			{
				WE("select() failed");
				close(sck);
				sck = -1;
				goto outer_bot;
			}
			if (r == 1) {
				D("select finished successfully");
				break;
			}
		}

		if (getsockopt(sck, SOL_SOCKET, SO_ERROR, &opt, &optlen) != 0) {
			W("getsockopt failed");
			close(sck);
			sck = -1;
			continue;
		}

		if (opt == 0) {
			D("socket connected, setting to blocking mode");
			errno = 0;
			if (fcntl(sck, F_SETFL, 0) == -1) {
				WE("failed to clear nonblocking mode");
				close(sck);
				sck = -1;
				continue;
			}

			break;
		} else {
			WC(opt, "could not connect socket (%d)", opt);
			close(sck);
			sck = -1;
			continue;
		}
outer_bot:;
	}

	freeaddrinfo(ai_list);

	return sck;
}