Blame opamgt/src/omgt_oob_net.c

Packit 857059
/* BEGIN_ICS_COPYRIGHT5 ****************************************
Packit 857059
Packit 857059
Copyright (c) 2015-2017, Intel Corporation
Packit 857059
Packit 857059
Redistribution and use in source and binary forms, with or without
Packit 857059
modification, are permitted provided that the following conditions are met:
Packit 857059
Packit 857059
    * Redistributions of source code must retain the above copyright notice,
Packit 857059
      this list of conditions and the following disclaimer.
Packit 857059
    * Redistributions in binary form must reproduce the above copyright
Packit 857059
      notice, this list of conditions and the following disclaimer in the
Packit 857059
      documentation and/or other materials provided with the distribution.
Packit 857059
    * Neither the name of Intel Corporation nor the names of its contributors
Packit 857059
      may be used to endorse or promote products derived from this software
Packit 857059
      without specific prior written permission.
Packit 857059
Packit 857059
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 857059
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 857059
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 857059
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
Packit 857059
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 857059
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit 857059
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit 857059
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit 857059
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 857059
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 857059
Packit 857059
** END_ICS_COPYRIGHT5   ****************************************/
Packit 857059
Packit 857059
/* [ICS VERSION STRING: unknown] */
Packit 857059
Packit 857059
#include <stdio.h>
Packit 857059
#include <stdlib.h>
Packit 857059
#include <string.h>
Packit 857059
#include <arpa/inet.h>
Packit 857059
#include <netinet/in.h>
Packit 857059
#include <netdb.h>
Packit 857059
#include <memory.h>
Packit 857059
#include <unistd.h>
Packit 857059
#include <errno.h>
Packit 857059
#include "imath.h"
Packit 857059
Packit 857059
#define OPAMGT_PRIVATE 1
Packit 857059
Packit 857059
#include "ib_utils_openib.h"
Packit 857059
#include "omgt_oob_net.h"
Packit 857059
#include "omgt_oob_ssl.h"
Packit 857059
#include "opamgt_dump_mad.h"
Packit 857059
Packit 857059
#define CONNECTION_BACKLOG 10
Packit 857059
Packit 857059
#define SET_ERROR(x,y) if (x) { *(x)=(y); }
Packit 857059
#define NET_MAGIC 0x31E0CC01
Packit 857059
Packit 857059
static FSTATUS omgt_oob_read_from_socket(struct omgt_port *port, struct net_connection *conn);
Packit 857059
static FSTATUS omgt_oob_write_to_socket(struct omgt_port *port, struct net_connection *conn);
Packit 857059
static struct net_connection* omgt_oob_new_connection();
Packit 857059
static FSTATUS omgt_oob_print_addrinfo(struct omgt_port *port, char *hostname, uint16_t conn_port);
Packit 857059
Packit 857059
Packit 857059
/**
Packit 857059
 * @brief Establish a connection to the given host.
Packit 857059
 * @param port            port object with connection info
Packit 857059
 * @return FSTATUS
Packit 857059
 */
Packit 857059
FSTATUS omgt_oob_net_connect(struct omgt_port *port, struct net_connection **cnn)
Packit 857059
{
Packit 857059
	struct net_connection *conn = NULL;
Packit 857059
	struct sockaddr_in v4_addr;
Packit 857059
	struct sockaddr_in6 v6_addr;
Packit 857059
	struct in_addr ipv4addr;
Packit 857059
	struct in6_addr ipv6addr;
Packit 857059
	struct hostent *hp = NULL;
Packit 857059
	int inaddr = 0;
Packit 857059
	int ipv6 = 0;
Packit 857059
Packit 857059
	/* Set Timeout to default value if incorrect value */
Packit 857059
	if (port->ms_timeout <= 0) {
Packit 857059
		port->ms_timeout = OMGT_DEF_TIMEOUT_MS;
Packit 857059
	}
Packit 857059
	if (port->retry_count < 0) {
Packit 857059
		port->retry_count = OMGT_DEF_RETRY_CNT;
Packit 857059
	}
Packit 857059
	/* First resolve the hostname and fill in the sockaddr */
Packit 857059
	inaddr = inet_pton(AF_INET6, port->oob_input.host, &ipv6addr);
Packit 857059
Packit 857059
	if ((ipv6 = (inaddr == 1) ? 1 : 0)) {
Packit 857059
		memset((void *)&v6_addr, 0, sizeof(v6_addr));
Packit 857059
		v6_addr.sin6_family = AF_INET6;
Packit 857059
		v6_addr.sin6_port = htons((short)port->oob_input.port);
Packit 857059
		memcpy((void *)&v6_addr.sin6_addr, (void *)&ipv6addr, sizeof(ipv6addr));
Packit 857059
Packit 857059
		if (port->dbg_file) {
Packit 857059
			(void)omgt_oob_print_addrinfo(port, port->oob_input.host, port->oob_input.port);
Packit 857059
		}
Packit 857059
	} else {
Packit 857059
		memset((void *)&v4_addr, 0, sizeof(v4_addr));
Packit 857059
		v4_addr.sin_family = AF_INET;
Packit 857059
		v4_addr.sin_port = htons((short)port->oob_input.port);
Packit 857059
		inaddr = inet_pton(AF_INET, port->oob_input.host, &ipv4addr);
Packit 857059
Packit 857059
		if (inaddr == 1) {
Packit 857059
			memcpy((void *)&v4_addr.sin_addr, (void *)&ipv4addr, sizeof(ipv4addr));
Packit 857059
		} else {
Packit 857059
			hp = gethostbyname(port->oob_input.host);
Packit 857059
			if (hp == NULL) {
Packit 857059
				OMGT_OUTPUT_ERROR(port, "invalid hostname (%s).\n", port->oob_input.host);
Packit 857059
				return FINVALID_PARAMETER;
Packit 857059
			}
Packit 857059
			memcpy((void *)&v4_addr.sin_addr, hp->h_addr, hp->h_length);
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	/* Next, create a socket and attempt the connection */
Packit 857059
	conn = omgt_oob_new_connection();
Packit 857059
	if (conn == NULL) {
Packit 857059
		OMGT_OUTPUT_ERROR(port, "no memory for connection.\n");
Packit 857059
		return FINSUFFICIENT_MEMORY;
Packit 857059
	}
Packit 857059
	conn->ipv6 = ipv6;
Packit 857059
	conn->sock = socket((conn->ipv6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
Packit 857059
	if (conn->sock == INVALID_SOCKET) {
Packit 857059
		OMGT_OUTPUT_ERROR(port, "invalid socket.\n");
Packit 857059
		free(conn);
Packit 857059
		return FINVALID_STATE;
Packit 857059
	}
Packit 857059
Packit 857059
	if (connect(conn->sock,
Packit 857059
			(conn->ipv6) ? (struct sockaddr *)&v6_addr : (struct sockaddr *)&v4_addr,
Packit 857059
			(conn->ipv6) ? sizeof(v6_addr) : sizeof(v4_addr)) == SOCKET_ERROR) {
Packit 857059
Packit 857059
		OMGT_OUTPUT_ERROR(port, "cannot connect to socket.\n");
Packit 857059
		goto bail;
Packit 857059
	}
Packit 857059
Packit 857059
	if (conn->ipv6) {
Packit 857059
		conn->v6_addr = v6_addr;
Packit 857059
	} else {
Packit 857059
		conn->v4_addr = v4_addr;
Packit 857059
	}
Packit 857059
Packit 857059
	OMGT_DBGPRINT(port, "Out-bound connection to %s port %d (conn #%d) established.\n",
Packit 857059
		port->oob_input.host, port->oob_input.port, conn->sock);
Packit 857059
Packit 857059
	// Should we setup SSL/TLS
Packit 857059
	if (port->oob_input.ssl_params.enable) {
Packit 857059
		port->is_ssl_enabled = TRUE;
Packit 857059
		if (omgt_oob_ssl_init(port)) {
Packit 857059
			OMGT_OUTPUT_ERROR(port, "cannot initialize SSL/TLS\n");
Packit 857059
			goto bail;
Packit 857059
		}
Packit 857059
Packit 857059
		if (port->ssl_context == NULL) {
Packit 857059
			// open SSL/TLS connection
Packit 857059
			if (!(port->ssl_context = omgt_oob_ssl_client_open(port,
Packit 857059
						port->oob_input.ssl_params.directory,
Packit 857059
						port->oob_input.ssl_params.certificate,
Packit 857059
						port->oob_input.ssl_params.private_key,
Packit 857059
						port->oob_input.ssl_params.ca_certificate,
Packit 857059
						port->oob_input.ssl_params.cert_chain_depth,
Packit 857059
						port->oob_input.ssl_params.dh_params,
Packit 857059
						port->oob_input.ssl_params.ca_crl_enable,
Packit 857059
						port->oob_input.ssl_params.ca_crl))) {
Packit 857059
				OMGT_OUTPUT_ERROR(port, "cannot open SSL/TLS connection\n");
Packit 857059
				goto bail;
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		// establish SSL/TLS session
Packit 857059
		conn->ssl_session = omgt_oob_ssl_connect(port, port->ssl_context, conn->sock);
Packit 857059
		if (!conn->ssl_session) {
Packit 857059
			OMGT_OUTPUT_ERROR(port, "cannot establish SSL/TLS session\n");
Packit 857059
			goto bail; 
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	*cnn = conn;
Packit 857059
	return FSUCCESS;
Packit 857059
Packit 857059
bail:
Packit 857059
	close(conn->sock);
Packit 857059
	conn->sock = INVALID_SOCKET;
Packit 857059
	free(conn);
Packit 857059
	return FERROR;
Packit 857059
}
Packit 857059
Packit 857059
FSTATUS omgt_oob_net_disconnect(struct omgt_port *port, struct net_connection *conn)
Packit 857059
{
Packit 857059
	struct net_blob *blob;
Packit 857059
	int nr, ns;
Packit 857059
Packit 857059
	if (!conn || conn->sock == INVALID_SOCKET) {
Packit 857059
		return FINVALID_PARAMETER;
Packit 857059
	}
Packit 857059
Packit 857059
	close(conn->sock);
Packit 857059
	conn->sock = INVALID_SOCKET;
Packit 857059
Packit 857059
	/*
Packit 857059
	 * Delete all enqueued blobs
Packit 857059
	 */
Packit 857059
	ns = 0;
Packit 857059
	while (!omgt_oob_queue_empty(&conn->send_queue)) {
Packit 857059
		blob = omgt_oob_dequeue_net_blob(&conn->send_queue);
Packit 857059
		if (blob) omgt_oob_free_net_blob(blob);
Packit 857059
		++ns;
Packit 857059
	}
Packit 857059
	nr = 0;
Packit 857059
	while (!omgt_oob_queue_empty(&conn->recv_queue)) {
Packit 857059
		blob = omgt_oob_dequeue_net_blob(&conn->recv_queue);
Packit 857059
		if (blob) omgt_oob_free_net_blob(blob);
Packit 857059
		++nr;
Packit 857059
	}
Packit 857059
Packit 857059
	OMGT_DBGPRINT(port, "closed connection %d, deleted %d send %d recv blobs\n",
Packit 857059
		conn->sock, ns, nr);
Packit 857059
Packit 857059
	free(conn);
Packit 857059
Packit 857059
	return FSUCCESS;
Packit 857059
}
Packit 857059
Packit 857059
/*
Packit 857059
 * Pack up the given data into a struct net_blob to be sent over the given
Packit 857059
 * connection. Simply enqueue the blob here. omgt_oob_net_sleep() will take
Packit 857059
 * care of the actual sending.
Packit 857059
 */
Packit 857059
FSTATUS omgt_oob_net_send(struct omgt_port *port, uint8_t *data, int len)
Packit 857059
{
Packit 857059
	int magic;
Packit 857059
	int tot_len;
Packit 857059
	struct net_blob *blob;
Packit 857059
Packit 857059
	if (!port || !port->conn) {
Packit 857059
		return FINVALID_PARAMETER;
Packit 857059
	}
Packit 857059
	if (port->conn->sock == INVALID_SOCKET) {
Packit 857059
		return FINVALID_PARAMETER;
Packit 857059
	}
Packit 857059
Packit 857059
	/*
Packit 857059
	 * Copy the given data, prepended by a magic # and the tot msg len,
Packit 857059
	 * into the blob.
Packit 857059
	 */
Packit 857059
	tot_len = len + 2 * sizeof(int);
Packit 857059
	blob = omgt_oob_new_net_blob(tot_len);
Packit 857059
	if (blob == NULL || blob->data == NULL) {
Packit 857059
		if (blob) omgt_oob_free_net_blob(blob);
Packit 857059
		return FINSUFFICIENT_MEMORY;
Packit 857059
	}
Packit 857059
	magic = htonl(NET_MAGIC);
Packit 857059
	memcpy((void *)blob->data, (void *)&magic, sizeof(int));
Packit 857059
	tot_len = htonl(tot_len);
Packit 857059
	memcpy((void *)(blob->data + sizeof(int)), (void *)&tot_len, sizeof(int));
Packit 857059
	memcpy((void *)(blob->data + 2 * sizeof(int)), (void *)data, len);
Packit 857059
Packit 857059
	if (port->dbg_file) {
Packit 857059
		OMGT_DBGPRINT(port, ">>> sending: len %d pktsz %d\n", len, tot_len);
Packit 857059
		omgt_dump_mad(port->dbg_file, data, len, "send mad\n");
Packit 857059
	}
Packit 857059
Packit 857059
	omgt_oob_enqueue_net_blob(&port->conn->send_queue, blob);
Packit 857059
Packit 857059
	OMGT_DBGPRINT(port, "sent %d bytes at %p over conn %d\n", len, (void *)data, port->conn->sock);
Packit 857059
Packit 857059
	return FSUCCESS;
Packit 857059
}
Packit 857059
Packit 857059
/*
Packit 857059
 * Return the next message in the given connection's receive queue, NULL if none.
Packit 857059
 */
Packit 857059
void omgt_oob_net_get_next_message(struct net_connection *conn, uint8_t **data, int *len)
Packit 857059
{
Packit 857059
	struct net_blob *blob;
Packit 857059
Packit 857059
	if (conn == NULL) {
Packit 857059
		if (data) {
Packit 857059
			*data = NULL;
Packit 857059
		}
Packit 857059
		if (len) {
Packit 857059
			*len = 0;
Packit 857059
		}
Packit 857059
		return;
Packit 857059
	}
Packit 857059
Packit 857059
	blob = omgt_oob_dequeue_net_blob(&conn->recv_queue);
Packit 857059
	if (blob == NULL) {
Packit 857059
		if (data) {
Packit 857059
			*data = NULL;
Packit 857059
		}
Packit 857059
		if (len) {
Packit 857059
			*len = 0;
Packit 857059
		}
Packit 857059
		return;
Packit 857059
	} else {
Packit 857059
		if (data) {
Packit 857059
			*data = blob->data;
Packit 857059
		}
Packit 857059
		if (len) {
Packit 857059
			*len = blob->len;
Packit 857059
		}
Packit 857059
		blob->data = NULL; /* so omgt_oob_free_net_blob() won't free the data */
Packit 857059
		omgt_oob_free_net_blob(blob);
Packit 857059
		return;
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
static FSTATUS omgt_oob_read_from_socket(struct omgt_port *port, struct net_connection *conn)
Packit 857059
{
Packit 857059
	ssize_t bytes_read;
Packit 857059
	struct net_blob *blob;
Packit 857059
Packit 857059
	/*
Packit 857059
	 * If we're in the middle of a message, pick up where we left off.
Packit 857059
	 * Otherwise, start reading a new message.
Packit 857059
	 */
Packit 857059
	if (conn->blob_in_progress == NULL) {
Packit 857059
		blob = omgt_oob_new_net_blob(0);
Packit 857059
		if (blob) {
Packit 857059
			blob->data = NULL; /* this flags that we haven't read the msg size yet */
Packit 857059
			blob->cur_ptr = (uint8_t *)blob->magic;
Packit 857059
			blob->bytes_left = 2 * sizeof(int);
Packit 857059
			conn->blob_in_progress = blob;
Packit 857059
		} else {
Packit 857059
			OMGT_DBGPRINT(port, "Received NULL blob from socket.");
Packit 857059
			return FERROR;
Packit 857059
		}
Packit 857059
	} else {
Packit 857059
		blob = conn->blob_in_progress;
Packit 857059
	}
Packit 857059
Packit 857059
	if (port->is_ssl_enabled && port->is_ssl_initialized) {
Packit 857059
		bytes_read = omgt_oob_ssl_read(port, conn->ssl_session, blob->cur_ptr, blob->bytes_left);
Packit 857059
	} else {
Packit 857059
		bytes_read = recv(conn->sock, blob->cur_ptr, blob->bytes_left, 0);
Packit 857059
	}
Packit 857059
Packit 857059
	if (bytes_read == 0) { /* graceful shutdown */
Packit 857059
		OMGT_DBGPRINT(port, "conn %d shut down gracefully\n", conn->sock);
Packit 857059
		return FERROR;
Packit 857059
	} else if (bytes_read == SOCKET_ERROR) {
Packit 857059
		OMGT_DBGPRINT(port, "err %zd, %d over connection %d\n", bytes_read, errno, conn->sock);
Packit 857059
		return FERROR;
Packit 857059
	} else {
Packit 857059
		if (bytes_read < blob->bytes_left) { /* still more to read */
Packit 857059
			omgt_oob_adjust_blob_cur_ptr(blob, bytes_read);
Packit 857059
			OMGT_DBGPRINT(port, "read %zu bytes over conn %d, %zu bytes to go\n",
Packit 857059
				bytes_read, conn->sock, blob->bytes_left);
Packit 857059
			return FSUCCESS;
Packit 857059
		} else {
Packit 857059
			if (blob->data == NULL) { /* NULL means we just finished reading msg size */
Packit 857059
				/* if we didn't get the magic, DISCONNECT this connection */
Packit 857059
				if (ntohl(blob->magic[0]) != NET_MAGIC) {
Packit 857059
					OMGT_OUTPUT_ERROR(port, "Read/write error over connection %d\n", conn->sock);
Packit 857059
					omgt_oob_free_net_blob(blob);
Packit 857059
					return FERROR;
Packit 857059
				}
Packit 857059
Packit 857059
				blob->len = ntohl(blob->magic[1]) - 2 * sizeof(int);
Packit 857059
				blob->data = malloc(blob->len);
Packit 857059
				if (blob->data == NULL) {
Packit 857059
					/* No memory! Bail out and disconnect, since we have to lose this msg */
Packit 857059
					omgt_oob_free_net_blob(blob);
Packit 857059
					return FERROR;
Packit 857059
				}
Packit 857059
				blob->cur_ptr = blob->data;
Packit 857059
				blob->bytes_left = blob->len;
Packit 857059
				OMGT_DBGPRINT(port, "read %zd bytes over conn %d, start reading size %zu\n",
Packit 857059
					bytes_read, conn->sock, blob->len);
Packit 857059
				return FSUCCESS;
Packit 857059
			} else { /* we just finished reading the user data -- enqueue blob */
Packit 857059
				blob->bytes_left = 0;
Packit 857059
				blob->cur_ptr = NULL;
Packit 857059
				omgt_oob_enqueue_net_blob(&conn->recv_queue, blob);
Packit 857059
				conn->blob_in_progress = NULL;
Packit 857059
				OMGT_DBGPRINT(port, "read %zd bytes over conn %d, finish reading msg of size %zu\n",
Packit 857059
					bytes_read, conn->sock, blob->len);
Packit 857059
				return FSUCCESS;
Packit 857059
			}
Packit 857059
		}
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
static FSTATUS omgt_oob_write_to_socket(struct omgt_port *port, struct net_connection *conn)
Packit 857059
{
Packit 857059
	ssize_t bytes_sent;
Packit 857059
	struct net_blob *blob;
Packit 857059
Packit 857059
	if (omgt_oob_queue_empty(&conn->send_queue)) {
Packit 857059
		return FSUCCESS;
Packit 857059
	}
Packit 857059
Packit 857059
	blob = omgt_oob_peek_net_blob(&conn->send_queue);
Packit 857059
Packit 857059
	/*
Packit 857059
	 * #define TEST if you want to stress test message fragmentation.
Packit 857059
	 * Leave undefined for release build.
Packit 857059
	 */
Packit 857059
#ifdef TEST
Packit 857059
	xxx = blob->bytes_left / 2;
Packit 857059
	if (xxx == 0) {
Packit 857059
		xxx = blob->bytes_left;
Packit 857059
	}
Packit 857059
	if (port->is_ssl_enabled && port->is_ssl_initialized) {
Packit 857059
		bytes_sent = omgt_oob_ssl_write(port, conn->ssl_session, blob->cur_ptr, xxx);
Packit 857059
	} else {
Packit 857059
		bytes_sent = send(conn->sock, blob->cur_ptr, xxx, 0);
Packit 857059
	}
Packit 857059
#else
Packit 857059
	if (port->is_ssl_enabled && port->is_ssl_initialized) {
Packit 857059
		bytes_sent = omgt_oob_ssl_write(port, conn->ssl_session, blob->cur_ptr, blob->bytes_left);
Packit 857059
	} else {
Packit 857059
		bytes_sent = send(conn->sock, blob->cur_ptr, blob->bytes_left, 0);
Packit 857059
	}
Packit 857059
#endif
Packit 857059
Packit 857059
	OMGT_DBGPRINT(port, "wrote %zd bytes over conn %d\n", bytes_sent, conn->sock);
Packit 857059
Packit 857059
	if (bytes_sent == SOCKET_ERROR) {
Packit 857059
		/*
Packit 857059
		 * If we couldn't send because the send() would block, then just
Packit 857059
		 * return.	We'll try again next time.
Packit 857059
		 */
Packit 857059
		if (errno == EWOULDBLOCK) {
Packit 857059
			return FSUCCESS;
Packit 857059
		} else {
Packit 857059
			return FERROR;
Packit 857059
		}
Packit 857059
	} else {
Packit 857059
		/*
Packit 857059
		 * If we sent the entire message, destroy it and go on to the next one
Packit 857059
		 * in the queue. Otherwise, return; we'll continue were we left off
Packit 857059
		 * next time.
Packit 857059
		 */
Packit 857059
		if (bytes_sent == blob->bytes_left) {
Packit 857059
			blob = omgt_oob_dequeue_net_blob(&conn->send_queue);
Packit 857059
			if (blob) omgt_oob_free_net_blob(blob);
Packit 857059
			return FSUCCESS;
Packit 857059
		} else {
Packit 857059
			omgt_oob_adjust_blob_cur_ptr(blob, bytes_sent);
Packit 857059
			return FSUCCESS;
Packit 857059
		}
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
static struct net_connection* omgt_oob_new_connection()
Packit 857059
/*
Packit 857059
 * Return a new struct net_connection object.
Packit 857059
 */
Packit 857059
{
Packit 857059
	struct net_connection *conn = malloc(sizeof(struct net_connection));
Packit 857059
	if (conn == NULL) {
Packit 857059
		return NULL;
Packit 857059
	}
Packit 857059
Packit 857059
	conn->sock = INVALID_SOCKET;
Packit 857059
	omgt_oob_init_queue(&conn->send_queue);
Packit 857059
	omgt_oob_init_queue(&conn->recv_queue);
Packit 857059
	conn->blob_in_progress = NULL;
Packit 857059
	conn->err = 0;
Packit 857059
	return conn;
Packit 857059
}
Packit 857059
Packit 857059
/**
Packit 857059
 * @brief Listen on connection for data
Packit 857059
 *
Packit 857059
 * Put the connection to sleep and wait for the specified time to awake. Listens
Packit 857059
 * for data to be sent and received and calls the appropriate read/write socket
Packit 857059
 * function.
Packit 857059
 *
Packit 857059
 * @param port                port object 
Packit 857059
 * @param conn                connection to listen on 
Packit 857059
 * @param msec_to_wait        number of milliseconds to wait
Packit 857059
 * @param blocking            specifies whether to block while sleeping
Packit 857059
 *
Packit 857059
 * @return None
Packit 857059
 */
Packit 857059
void omgt_oob_net_process(struct omgt_port *port, struct net_connection *conn, int msec_to_wait, int blocking)
Packit 857059
{
Packit 857059
	int n, nfds;
Packit 857059
	fd_set readfds, writefds, errorfds;
Packit 857059
	int queued_data = 0, inprogress_data = 0;
Packit 857059
	struct timeval timeout = {0};
Packit 857059
Packit 857059
	/* Do nothing if no conn */
Packit 857059
	if (!port || !conn)
Packit 857059
		return;
Packit 857059
Packit 857059
	/*
Packit 857059
	 * Do a select on the listen socket (to catch new connections),
Packit 857059
	 * on all in-bound sockets, and on those out-bound sockets for
Packit 857059
	 * which we have traffic enqueued.	If blocking!=0, do the select
Packit 857059
	 * even if there's nothing to listen for (so we will wait msec_to_wait
Packit 857059
	 * always).
Packit 857059
	 */
Packit 857059
	FD_ZERO(&errorfds);
Packit 857059
	FD_ZERO(&readfds);
Packit 857059
	FD_ZERO(&writefds);
Packit 857059
	nfds = 0;
Packit 857059
Packit 857059
	FD_SET(conn->sock, &readfds);
Packit 857059
	nfds = MAX(nfds, (int)conn->sock);
Packit 857059
	if (!omgt_oob_queue_empty(&conn->send_queue)) {
Packit 857059
		queued_data++;
Packit 857059
		nfds = MAX(nfds, (int)conn->sock);
Packit 857059
		FD_SET(conn->sock, &writefds);
Packit 857059
	}
Packit 857059
	if (conn->blob_in_progress) {
Packit 857059
		inprogress_data++;
Packit 857059
	}
Packit 857059
Packit 857059
	if ((nfds == 0) && !blocking) {
Packit 857059
		return;
Packit 857059
	}
Packit 857059
	++nfds;
Packit 857059
Packit 857059
	if (msec_to_wait > 0) {
Packit 857059
		timeout.tv_sec = msec_to_wait / 1000;
Packit 857059
		timeout.tv_usec = (msec_to_wait % 1000) * 1000;
Packit 857059
	}
Packit 857059
	n = select(nfds, &readfds, &writefds, &errorfds, (msec_to_wait < 0 ? NULL : &timeout));
Packit 857059
Packit 857059
	if (n == SOCKET_ERROR) {
Packit 857059
		return;
Packit 857059
	}
Packit 857059
	if (n == 0 && inprogress_data == 0) {
Packit 857059
		return;
Packit 857059
	}
Packit 857059
Packit 857059
	if (FD_ISSET(conn->sock, &writefds) || !omgt_oob_queue_empty(&conn->send_queue)) {
Packit 857059
		conn->err = omgt_oob_write_to_socket(port, conn);
Packit 857059
	}
Packit 857059
	if (conn->err == 0 &&
Packit 857059
		(FD_ISSET(conn->sock, &readfds) || conn->blob_in_progress))
Packit 857059
	{
Packit 857059
		conn->err = omgt_oob_read_from_socket(port, conn);
Packit 857059
	}
Packit 857059
Packit 857059
	if (conn->err) {
Packit 857059
		OMGT_OUTPUT_ERROR(port, "Read/write error over connection %d\n", conn->sock);
Packit 857059
	}
Packit 857059
Packit 857059
	return;
Packit 857059
}
Packit 857059
Packit 857059
static FSTATUS omgt_oob_print_addrinfo(struct omgt_port *port, char *hostname, uint16_t conn_port)
Packit 857059
{
Packit 857059
	int erc;
Packit 857059
	struct addrinfo hints;
Packit 857059
	struct addrinfo *res = NULL;
Packit 857059
	struct addrinfo *ai;
Packit 857059
	char host_bfr[NI_MAXHOST];
Packit 857059
	char serv_bfr[NI_MAXSERV];
Packit 857059
	char port_bfr[NI_MAXSERV];
Packit 857059
Packit 857059
	memset(&hints, 0, sizeof(hints));
Packit 857059
	hints.ai_family = PF_UNSPEC;
Packit 857059
	hints.ai_socktype = SOCK_STREAM;
Packit 857059
	hints.ai_flags |= AI_CANONNAME;
Packit 857059
	snprintf(port_bfr, NI_MAXSERV, "%u", conn_port);
Packit 857059
	erc = getaddrinfo(hostname, port_bfr, &hints, &res;;
Packit 857059
Packit 857059
	if (erc != 0 || !res) {
Packit 857059
		OMGT_DBGPRINT(port, "Unable to get addressing information on IP address\n");
Packit 857059
		return FERROR;
Packit 857059
	}
Packit 857059
Packit 857059
	for (ai = res; ai != NULL; ai = ai->ai_next) {
Packit 857059
		OMGT_DBGPRINT(port,
Packit 857059
			"Setting up a socket connection based on the following address info:\n"
Packit 857059
			" IP Version: %s\n IP Proto:   %s\n",
Packit 857059
			(ai->ai_family == PF_INET ? "IPv4" : "IPv6"),
Packit 857059
			(ai->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP"));
Packit 857059
Packit 857059
		getnameinfo(ai->ai_addr, ai->ai_addrlen, host_bfr, sizeof(host_bfr), serv_bfr,
Packit 857059
			sizeof(serv_bfr), NI_NUMERICHOST | NI_NUMERICSERV);
Packit 857059
Packit 857059
		OMGT_DBGPRINT(port,
Packit 857059
			" IP Address: %s\n Port:       %s\n",
Packit 857059
			host_bfr, serv_bfr);
Packit 857059
	}
Packit 857059
	if (res)
Packit 857059
		freeaddrinfo(res);
Packit 857059
	return FSUCCESS;
Packit 857059
}