Example #1
0
/**
 * @brief	Requeue an imap connection for processing, or log it out if there was an error or excess of protocol violations.
 * @param	con		a pointer to the connection object of the imap session.
 * @return	This function returns no value.
 */
void imap_requeue(connection_t *con) {

	if (!status() || con_status(con) < 0 || con_status(con) == 2 || con->protocol.violations > con->server->violations.cutoff) {
		enqueue(&imap_logout, con);
	}
	else {
		enqueue(&imap_process, con);
	}

	return;
}
Example #2
0
/**
 * @brief	Gracefully destroy a POP3 session, whether because of an error or in response to a user QUIT command.
 * @param	con		the POP3 client connection to be shut down.
 * @brief	This function returns no value.
 */
void pop_quit(connection_t *con) {

	if (con_status(con) == 2) {
		con_write_bl(con, "-ERR Unexpected connection shutdown detected. Goodbye.\r\n", 56);
	}
	else if (con_status(con) >= 0) {
		con_write_bl(con, "+OK Goodbye.\r\n", 14);
	}
	else {
		con_write_bl(con, "-ERR Network connection failure.\r\n", 34);
	}

	con_destroy(con);

	return;
}
Example #3
0
File: read.c Project: lavabit/magma
/**
 * @brief	Read a line of input from a network connection.
 * @note	This function handles reading data from both regular and ssl connections.
 * 			This function continually attempts to read incoming data from the specified connection until a \n terminated line of input is received.
 * 			If a new line is read, the length of that line is returned to the caller, including the trailing \n.
 * 			If the read returns -1 and wasn't caused by a syscall interruption or blocking error, -1 is returned, and the connection status is set to -1.
 * 			If the read returns 0 and wasn't caused by a syscall interruption or blocking error, -2 is returned, and the connection status is set to 2.
 * 			Once a \n character is reached, the length of the current line of input is returned to the user, and the connection status is set to 1.
 * @param	con		the network connection across which the line of data will be read.
 * @return	-1 on general failure, -2 if the connection was reset, or the length of the current line of input, including the trailing new line character.
 */
int64_t con_read_line(connection_t *con, bool_t block) {

	ssize_t bytes = 0;
	int_t counter = 0;
	bool_t line = false;

	if (!con || con->network.sockd == -1 || con_status(con) < 0) {
		if (con) con->network.status = -1;
		return -1;
	}

	// Check for an existing network buffer. If there isn't one, try creating it.
	else if (!con->network.buffer && !con_init_network_buffer(con)) {
		con->network.status = -1;
		return -1;
	}

	// Check if we have received more data than just what is in the current line of input.
	else if (pl_length_get(con->network.line) && st_length_get(con->network.buffer) > pl_length_get(con->network.line)) {

		// If so, move the unused "new" data after the current line marker to the front of the buffer.
		mm_move(st_data_get(con->network.buffer), st_data_get(con->network.buffer) + pl_length_get(con->network.line),
			st_length_get(con->network.buffer) - pl_length_get(con->network.line));

		// Update the buffer length.
		st_length_set(con->network.buffer, st_length_get(con->network.buffer) - pl_length_get(con->network.line));

		// Check whether the data we just moved contains a complete line.
		if (!pl_empty((con->network.line = line_pl_st(con->network.buffer, 0)))) {
			con->network.status = 1;
			return pl_length_get(con->network.line);
		}

	}
	// Otherwise reset the buffer and line lengths to zero.
	else {
		st_length_set(con->network.buffer, 0);
		con->network.line = pl_null();
	}

	// Loop until we get a complete line, an error, or the buffer is filled.
	do {
//		blocking = st_length_get(con->network.buffer) ? false : true;
		block = true;

		if (con->network.tls) {
			bytes = tls_read(con->network.tls, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
				st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), block);
		}
		else {
			bytes = tcp_read(con->network.sockd, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
				st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), block);
		}

		// We actually read in data, so we need to update the buffer to reflect the amount of unprocessed data it currently holds.
		if (bytes > 0) {
			st_length_set(con->network.buffer, st_length_get(con->network.buffer) + bytes);
		}
		else if (bytes == 0) {
			usleep(1000);
		}
		else {
			con->network.status = -1;
			return -1;
		}

		// Check whether we have a complete line before checking whether the connection was closed.
		if (!st_empty(con->network.buffer) && !pl_empty((con->network.line = line_pl_st(con->network.buffer, 0)))) {
			line = true;
		}

	} while (!line && block && counter++ < 128 && st_length_get(con->network.buffer) != st_avail_get(con->network.buffer) && status());

	if (st_length_get(con->network.buffer) > 0) {
		con->network.status = 1;
	}

	return pl_length_get(con->network.line);
}
Example #4
0
File: read.c Project: lavabit/magma
/**
 * @brief	Read data from a network connection, and store the data in the connection context buffer.
 * @note	This function handles reading data from both regular and SSL connections.
 * 			If the connection's network buffer hasn't been allocated, it will be initialized.
 * @param	con		a pointer to the connection object from which the data will be read.
 * @return	-1 on general failure, -2 if the connection was reset, or the amount of data that was read.
 */
int64_t con_read(connection_t *con) {

	ssize_t bytes = 0;
	int_t counter = 0;
	bool_t blocking = true;

	if (!con || con->network.sockd == -1 || con_status(con) < 0) {
		if (con) con->network.status = -1;
		return -1;
	}

	// Check for an existing network buffer. If there isn't one, try creating it.
	else if (!con->network.buffer && !con_init_network_buffer(con)) {
		con->network.status = -1;
		return -1;
	}

	// Check for data past the current line buffer.
	else if (pl_length_get(con->network.line) && st_length_get(con->network.buffer) > pl_length_get(con->network.line)) {

		// Move the unused data to the front of the buffer.
		mm_move(st_data_get(con->network.buffer), st_data_get(con->network.buffer) + pl_length_get(con->network.line),
			st_length_get(con->network.buffer) - pl_length_get(con->network.line));

		// Update the length.
		st_length_set(con->network.buffer, st_length_get(con->network.buffer) - pl_length_get(con->network.line));

		// Clear the line buffer.
		con->network.line = pl_null();

		if (st_length_get(con->network.buffer)) {
			return st_length_get(con->network.buffer);
		}

	}
	// Otherwise reset the buffer and line lengths to zero.
	else {
		st_length_set(con->network.buffer, 0);
		con->network.line = pl_null();
	}

	// Loop until the buffer has data or we get an error.
	do {
//		blocking = st_length_get(con->network.buffer) ? false : true;
		blocking = true;

		if (con->network.tls) {
			bytes = tls_read(con->network.tls, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
				st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), blocking);
		}
		else {
			bytes = tcp_read(con->network.sockd, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
				st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), blocking);
		}

		// We actually read in data, so we need to update the buffer to reflect the amount of unprocessed data it currently holds.
		if (bytes > 0) {
			st_length_set(con->network.buffer, st_length_get(con->network.buffer) + bytes);
		}
		else if (bytes == 0) {
			usleep(1000);
		}
		else {
			con->network.status = -1;
			return -1;
		}


	} while (blocking && counter++ < 128 && !st_length_get(con->network.buffer) && status());

	// If there is data in the buffer process it. Otherwise if the buffer is empty and the connection appears to be closed
	// (as indicated by a return value of 0), then return -1 to let the caller know the connection is dead.
	if (st_length_get(con->network.buffer)) {
		con->network.status = 1;
	}

	return st_length_get(con->network.buffer);
}