|
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 |
}
|