Ejemplo n.º 1
0
void
io_frame_leave(struct io *io)
{
	io_debug("io_frame_leave(%" PRIu64 ")\n", frame);

	if (current && current != io)
		errx(1, "io_frame_leave: io mismatch");

	/* io has been cleared */
	if (current == NULL)
		goto done;

	/* TODO: There is a possible optimization there:
	 * In a typical half-duplex request/response scenario,
	 * the io is waiting to read a request, and when done, it queues
	 * the response in the output buffer and goes to write mode.
	 * There, the write event is set and will be triggered in the next
	 * event frame.  In most case, the write call could be done
	 * immediately as part of the last read frame, thus avoiding to go
	 * through the event loop machinery. So, as an optimisation, we
	 * could detect that case here and force an event dispatching.
	 */

	/* Reload the io if it has not been reset already. */
	io_release(io);
	current = NULL;
    done:
	io_debug("=== /%" PRIu64 "\n", frame);

	frame += 1;
}
Ejemplo n.º 2
0
/**
	b64decode
	Decodes a base64-encoded message.  You provide an encoded message,
	and a pointer to somewhere we (the editorial we) can store the length 
	of the decoded message.  A dynamically allocated pointer is returned.
*/
char *b64decode(char *encoded, size_t *newlen)
{
        BIO     *b64, *bmem;
        char    *decoded = NULL;

	if(encoded == NULL) {
		print_loc(); io_debug("NULL data passed!  Bad coder!  Bad!\n");
		return NULL;
	}

	safe_malloc(decoded,*newlen);
        b64 = BIO_new(BIO_f_base64());
        bmem = BIO_new_mem_buf(encoded, -1);
	if(bmem == NULL || b64 == NULL) {
		print_loc(); io_debug("Calls to libssl failed!\n");
		abort();  //I don't think this will ever happen.
	}

        bmem = BIO_push(b64, bmem);
        *newlen = BIO_read(bmem, decoded, *newlen);
	BIO_free_all(bmem);

	decoded[*newlen] = '\0';


	return decoded;
}
Ejemplo n.º 3
0
void
io_set_timeout(struct io *io, int msec)
{
	io_debug("io_set_timeout(%p, %d)\n", io, msec);

	io->timeout = msec;
}
Ejemplo n.º 4
0
/*
 * Setup the necessary events as required by the current io state,
 * honouring duplex mode and i/o pauses.
 */
void
io_reload(struct io *io)
{
	short	events;

	/* io will be reloaded at release time */
	if (io->flags & IO_HELD)
		return;

#ifdef IO_SSL
	if (io->ssl) {
		io_reload_ssl(io);
		return;
	}
#endif

	io_debug("io_reload(%p)\n", io);

	events = 0;
	if (IO_READING(io) && !(io->flags & IO_PAUSE_IN))
		events = EV_READ;
	if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io))
		events |= EV_WRITE;

	io_reset(io, events, io_dispatch);
}
Ejemplo n.º 5
0
/**
	b64encode
	Encodes raw data in base64.  Pass the data and the length of the data.
	b64encode returns the base64-encoded data as a dynamically allocated 
	char *.
*/
char *b64encode(char *data, size_t datalen)
{
	BIO	*b64, *bmem;
	BUF_MEM	*bptr;
	char	*encoded = NULL;

	
        b64 = BIO_new(BIO_f_base64());
        bmem = BIO_new(BIO_s_mem());
	if(bmem == NULL || b64 == NULL) {
		print_loc(); io_debug("Calls to libssl failed!\n");
		abort();  //I don't think this will ever happen.
	}

        bmem = BIO_push(b64, bmem);
        BIO_write(bmem, data, datalen);
        BIO_flush(bmem);

        BIO_get_mem_ptr(bmem, &bptr);
        BIO_set_close(bmem, BIO_NOCLOSE);

	safe_malloc(encoded, bptr->length);
	memcpy(encoded, bptr->data, bptr->length);

	encoded[bptr->length] = '\0';

	BIO_free_all(bmem);
	BUF_MEM_free(bptr);

	return encoded;
}
Ejemplo n.º 6
0
/* Set the requested event. */
void
io_reset(struct io *io, short events, void (*dispatch)(int, short, void*))
{
	struct timeval	tv, *ptv;

	io_debug("io_reset(%p, %s, %p) -> %s\n",
	    io, io_evstr(events), dispatch, io_strio(io));

	/*
	 * Indicate that the event has already been reset so that reload
	 * is not called on frame_leave.
	 */
	io->flags |= IO_RESET;

	if (event_initialized(&io->ev))
		event_del(&io->ev);

	/*
	 * The io is paused by the user, so we don't want the timeout to be
	 * effective.
	 */
	if (events == 0)
		return;

	event_set(&io->ev, io->sock, events, dispatch, io);
	if (io->timeout >= 0) {
		tv.tv_sec = io->timeout / 1000;
		tv.tv_usec = (io->timeout % 1000) * 1000;
		ptv = &tv;
	} else
		ptv = NULL;

	event_add(&io->ev, ptv);
}
Ejemplo n.º 7
0
void
io_set_lowat(struct io *io, size_t lowat)
{
	io_debug("io_set_lowat(%p, %zu)\n", io, lowat);

	io->lowat = lowat;
}
Ejemplo n.º 8
0
/**
	url2http
	Given a url as a string, it returns a pointer to a dynamically allocated
	http_request struct.

	args:
	url = A string of the following form:  
		<scheme>://<user>:<pass>@<host>:<port>/<url-path>
	where <scheme> is either 'http' or 'https', and all parts are optional
	except the scheme, the host and the path.  So, the minimum is something
	like
		<scheme>://<host>/<url-path>
	Returns a pointer to the http_request struct generated from the string.
*/
http_request *url2http(char *url)
{
	http_request	*nml;
	struct in_addr	addr;
	int		ssl = 0;
	parsed_url	purl;

	if (url == NULL) {
		//print_loc(); io_debug("NULL url passed!\n");
		return NULL;
	}

	if(strncmp(url, "http", 4))  { /* Must start with 'http'. */
		print_loc(); io_debug("Bad URL:  %s\n", url);
		return NULL;
	}
	
	purl = url_parse(url);
	addr = resolve_cached(purl.host, NULL, NULL);
	
	if(!strcmp(purl.scheme, "https"))
		ssl = 1;

	return new_http_req(addr, purl.port, purl.host, purl.path, ssl, 
		purl.passwd, purl.user);
}
Ejemplo n.º 9
0
void
io_pause(struct io *io, int dir)
{
	io_debug("io_pause(%p, %x)\n", io, dir);

	io->flags |= dir & (IO_PAUSE_IN | IO_PAUSE_OUT);
	io_reload(io);
}
Ejemplo n.º 10
0
void
io_resume(struct io *io, int dir)
{
	io_debug("io_resume(%p, %x)\n", io, dir);

	io->flags &= ~(dir & (IO_PAUSE_IN | IO_PAUSE_OUT));
	io_reload(io);
}
Ejemplo n.º 11
0
/**
	valid_dsa_sig
	Given some data, the data length, the public key, the public key 
	length, and the 48-byte signature, we verify it and return 1 for
	true and 0 for false, or -1 for error.
*/
int valid_dsa_sig(const void *data, int dlen, const char sig[48])
{
	int	r;
	char	hash[20];

	SHA1(data, dlen, hash);
	r = DSA_verify(0xdecafbad, hash, 20, sig, 48, dispatch);
	if(!r) {
		print_loc();
		io_err("Couldn't verify signature!  Info follows:\n");
		io_debug("Hexdump of signature:\n");
		io_hexdump(stdout, sig, 48);
		io_debug("\nHexdump of data follows:\n");
		io_hexdump(stdout, data, dlen);
	}
	return r;
}
Ejemplo n.º 12
0
void
io_hold(struct io *io)
{
	io_debug("io_enter(%p)\n", io);

	if (io->flags & IO_HELD)
		errx(1, "io_hold: io is already held");

	io->flags &= ~IO_RESET;
	io->flags |= IO_HELD;
}
Ejemplo n.º 13
0
/*
 * Event framing must not rely on an io pointer to refer to the "same" io
 * throughout the frame, because this is not always the case:
 *
 * 1) enter(addr0) -> free(addr0) -> leave(addr0) = SEGV
 * 2) enter(addr0) -> free(addr0) -> malloc == addr0 -> leave(addr0) = BAD!
 *
 * In both case, the problem is that the io is freed in the callback, so
 * the pointer becomes invalid. If that happens, the user is required to
 * call io_clear, so we can adapt the frame state there.
 */
void
io_frame_enter(const char *where, struct io *io, int ev)
{
	io_debug("\n=== %" PRIu64 " ===\n"
	    "io_frame_enter(%s, %s, %s)\n",
	    frame, where, io_evstr(ev), io_strio(io));

	if (current)
		errx(1, "io_frame_enter: interleaved frames");

	current = io;

	io_hold(io);
}
Ejemplo n.º 14
0
void
io_set_write(struct io *io)
{
	int	mode;

	io_debug("io_set_write(%p)\n", io);

	mode = io->flags & IO_RW;
	if (!(mode == 0 || mode == IO_READ))
		errx(1, "io_set_write(): full-duplex or writing");

	io->flags &= ~IO_RW;
	io->flags |= IO_WRITE;
	io_reload(io);
}
Ejemplo n.º 15
0
void
io_dispatch_write_ssl(int fd, short event, void *humppa)
{
	struct io	*io = humppa;
	int		 n, saved_errno;
	size_t		 w2, w;

	io_frame_enter("io_dispatch_write_ssl", io, event);

	if (event == EV_TIMEOUT) {
		io_callback(io, IO_TIMEOUT);
		goto leave;
	}

	w = io_queued(io);
	switch ((n = iobuf_write_ssl(io->iobuf, (SSL*)io->ssl))) {
	case IOBUF_WANT_READ:
		io_reset(io, EV_READ, io_dispatch_write_ssl);
		break;
	case IOBUF_WANT_WRITE:
		io_reset(io, EV_WRITE, io_dispatch_write_ssl);
		break;
	case IOBUF_CLOSED:
		io_callback(io, IO_DISCONNECTED);
		break;
	case IOBUF_ERROR:
		saved_errno = errno;
		io->error = strerror(errno);
		errno = saved_errno;
		io_callback(io, IO_ERROR);
		break;
	case IOBUF_SSLERROR:
		io->error = io_ssl_error();
		ssl_error("io_dispatch_write_ssl:SSL_write");
		io_callback(io, IO_ERROR);
		break;
	default:
		io_debug("io_dispatch_write_ssl(...) -> w=%d\n", n);
		w2 = io_queued(io);
		if (w > io->lowat && w2 <= io->lowat)
			io_callback(io, IO_LOWAT);
		break;
	}

    leave:
	io_frame_leave(io);
}
Ejemplo n.º 16
0
void
io_dispatch_read_ssl(int fd, short event, void *humppa)
{
	struct io	*io = humppa;
	int		 n, saved_errno;

	io_frame_enter("io_dispatch_read_ssl", io, event);

	if (event == EV_TIMEOUT) {
		io_callback(io, IO_TIMEOUT);
		goto leave;
	}

again:
	iobuf_normalize(&io->iobuf);
	switch ((n = iobuf_read_ssl(&io->iobuf, (SSL*)io->ssl))) {
	case IOBUF_WANT_READ:
		io_reset(io, EV_READ, io_dispatch_read_ssl);
		break;
	case IOBUF_WANT_WRITE:
		io_reset(io, EV_WRITE, io_dispatch_read_ssl);
		break;
	case IOBUF_CLOSED:
		io_callback(io, IO_DISCONNECTED);
		break;
	case IOBUF_ERROR:
		saved_errno = errno;
		io->error = strerror(errno);
		errno = saved_errno;
		io_callback(io, IO_ERROR);
		break;
	case IOBUF_SSLERROR:
		io->error = io_ssl_error();
		ssl_error("io_dispatch_read_ssl:SSL_read");
		io_callback(io, IO_ERROR);
		break;
	default:
		io_debug("io_dispatch_read_ssl(...) -> r=%d\n", n);
		io_callback(io, IO_DATAIN);
		if (current == io && IO_READING(io) && SSL_pending(io->ssl))
			goto again;
	}

    leave:
	io_frame_leave(io);
}
Ejemplo n.º 17
0
/**
	read_config
	Reads and parses the specified config file, and sets the appropriate 
	options.
	Returns -1 on error, 0 on success.
*/
int read_config(const char *filename)
{
	FILE *cf;
	int r;

	cf = fopen(filename, "r");
	if(cf == NULL) {
		io_debug("Error opening config file '%s':  %s\n"
			"Skipping config.\n", filename, strerror(errno));
		return 0;
	}

	r = parse_config(cf);
	fclose(cf);
	parsed_yet = 1;

	if(r == -1)
		io_err("Trouble parsing %s.\n", filename);

	return r;
}
Ejemplo n.º 18
0
void
io_clear(struct io *io)
{
	io_debug("io_clear(%p)\n", io);

	/* the current io is virtually dead */
	if (io == current)
		current = NULL;

#ifdef IO_SSL
	if (io->ssl) {
		SSL_free(io->ssl);
		io->ssl = NULL;
	}
#endif

	if (event_initialized(&io->ev))
		event_del(&io->ev);
	if (io->sock != -1) {
		close(io->sock);
		io->sock = -1;
	}
}
Ejemplo n.º 19
0
/**
	save_dispatch_key
	Saves a base64 encoded key, as well as keeping it for future use.  Pass
	it a key in the form of a null-terminated string.
	Returns -1 for error, 0 for success.
*/
int save_dispatch_key(const char *key)
{
	int r;
	char *pub;

	if(dispatch != NULL)
		return 0;	/* We have ignored you! */

	dispatch = DSA_generate_parameters(DSA_KEYLEN, NULL, 0, NULL, NULL, 
		NULL, NULL);
	if(dispatch == NULL) {
		io_debug("%s:%s():%d  ", __FILE__, __func__, __LINE__);
		io_err("Not enough free memory!  The walls are closing in!\n");
		return -1;
	}

	pub = fm_abs(FM_KEY_DISPATCH_PUBLIC);

	r = !fm_write(FM_KEY_DISPATCH_PUBLIC, key, strlen(key));
	r |= load_keys(pub, NULL, &dispatch);
	free(pub);

	return r;
}