summaryrefslogtreecommitdiffstats
path: root/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c')
-rw-r--r--debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c595
1 files changed, 595 insertions, 0 deletions
diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c
new file mode 100644
index 00000000..9906bdde
--- /dev/null
+++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c
@@ -0,0 +1,595 @@
+/*
+ * $Id: inet.c,v 1.61 2006/10/12 14:21:22 desrod Exp $
+ *
+ * inet.c: Interface layer to TCP/IP NetSync connections
+ *
+ * Copyright (c) 1997, Kenneth Albanowski
+ * Copyright (c) 1999, Tilo Christ
+ * Copyright (c) 1999, John Franks
+ * Copyright (c) 2004, 2005 Florent Pillet
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+
+#include "pi-debug.h"
+#include "pi-source.h"
+#include "pi-inet.h"
+#include "pi-cmp.h"
+#include "pi-net.h"
+
+/* Declare prototypes */
+static void pi_inet_device_free (pi_device_t *dev);
+static pi_protocol_t* pi_inet_protocol (pi_device_t *dev);
+static pi_protocol_t* pi_inet_protocol_dup (pi_protocol_t *prot);
+static void pi_inet_protocol_free (pi_protocol_t *prot);
+static int pi_inet_close(pi_socket_t *ps);
+static int pi_inet_connect(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen);
+static int pi_inet_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen);
+static int pi_inet_listen(pi_socket_t *ps, int backlog);
+static int pi_inet_accept(pi_socket_t *ps, struct sockaddr *addr, size_t *addrlen);
+static ssize_t pi_inet_read(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags);
+static ssize_t pi_inet_write(pi_socket_t *ps, const unsigned char *msg, size_t len, int flags);
+static int pi_inet_getsockopt(pi_socket_t *ps, int level, int option_name, void *option_value, size_t *option_len);
+static int pi_inet_setsockopt(pi_socket_t *ps, int level, int option_name, const void *option_value, size_t *option_len);
+static int pi_inet_flush(pi_socket_t *ps, int flags);
+
+extern int pi_socket_init(pi_socket_t *ps);
+
+pi_device_t*
+pi_inet_device (int type)
+{
+ pi_device_t *dev = NULL;
+ pi_inet_data_t *data = NULL;
+
+ dev = (pi_device_t *)malloc (sizeof (pi_device_t));
+ if (dev != NULL) {
+ data = (pi_inet_data_t *)malloc (sizeof (pi_inet_data_t));
+ if (data == NULL) {
+ free(dev);
+ dev = NULL;
+ }
+ }
+
+ if (dev != NULL && data != NULL) {
+ dev->free = pi_inet_device_free;
+ dev->protocol = pi_inet_protocol;
+ dev->bind = pi_inet_bind;
+ dev->listen = pi_inet_listen;
+ dev->accept = pi_inet_accept;
+ dev->connect = pi_inet_connect;
+ dev->close = pi_inet_close;
+
+ data->timeout = 0;
+ data->rx_bytes = 0;
+ data->rx_errors = 0;
+ data->tx_bytes = 0;
+ data->tx_errors = 0;
+ dev->data = data;
+ }
+
+ return dev;
+}
+
+static void
+pi_inet_device_free (pi_device_t *dev)
+{
+ ASSERT (dev != NULL);
+ if (dev != NULL) {
+ if (dev->data != NULL)
+ free(dev->data);
+ free(dev);
+ }
+}
+
+static pi_protocol_t*
+pi_inet_protocol (pi_device_t *dev)
+{
+ pi_protocol_t *prot;
+ pi_inet_data_t *data;
+
+ ASSERT (dev != NULL);
+
+ data = dev->data;
+
+ prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t));
+
+ if (prot != NULL) {
+ prot->level = PI_LEVEL_DEV;
+ prot->dup = pi_inet_protocol_dup;
+ prot->free = pi_inet_protocol_free;
+ prot->read = pi_inet_read;
+ prot->write = pi_inet_write;
+ prot->flush = pi_inet_flush;
+ prot->getsockopt = pi_inet_getsockopt;
+ prot->setsockopt = pi_inet_setsockopt;
+ prot->data = NULL;
+ }
+
+ return prot;
+}
+
+static pi_protocol_t*
+pi_inet_protocol_dup (pi_protocol_t *prot)
+{
+ pi_protocol_t *new_prot;
+
+ ASSERT (prot != NULL);
+
+ new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t));
+
+ if (new_prot != NULL) {
+ new_prot->level = prot->level;
+ new_prot->dup = prot->dup;
+ new_prot->free = prot->free;
+ new_prot->read = prot->read;
+ new_prot->write = prot->write;
+ new_prot->flush = prot->flush;
+ new_prot->getsockopt = prot->getsockopt;
+ new_prot->setsockopt = prot->setsockopt;
+ new_prot->data = NULL;
+ }
+
+ return new_prot;
+}
+
+static void
+pi_inet_protocol_free (pi_protocol_t *prot)
+{
+ ASSERT (prot != NULL);
+ if (prot != NULL)
+ free(prot);
+}
+
+static int
+pi_inet_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen)
+{
+ int opt,
+ sd,
+ err;
+ size_t optlen;
+ struct pi_sockaddr *paddr = (struct pi_sockaddr *) addr;
+ struct sockaddr_in serv_addr;
+ char *device = paddr->pi_device,
+ *port = NULL;
+
+ /* Figure out the addresses to allow */
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ if (strlen(device) > 1 && strncmp(device, "any", 3)) {
+ serv_addr.sin_addr.s_addr = inet_addr(device);
+ if (serv_addr.sin_addr.s_addr == (in_addr_t)-1) {
+ struct hostent *hostent = gethostbyname(device);
+
+ if (!hostent)
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+
+ memcpy((char *) &serv_addr.sin_addr.s_addr,
+ hostent->h_addr, (size_t)hostent->h_length);
+ }
+ } else {
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ if ((port = strchr(device, ':')) != NULL) {
+ serv_addr.sin_port = htons(atoi(++port));
+ } else {
+ serv_addr.sin_port = htons(14238);
+ }
+
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sd < 0) {
+ LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
+ "DEV BIND Inet: Unable to create socket\n"));
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+ }
+ if ((err = pi_socket_setsd (ps, sd)) < 0)
+ return err;
+
+ opt = 1;
+ optlen = sizeof(opt);
+
+ if (setsockopt(ps->sd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt,
+ (int)optlen) < 0) {
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+ }
+
+ if (bind(ps->sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+
+ LOG((PI_DBG_DEV, PI_DBG_LVL_INFO,
+ "DEV BIND Inet Bound to %s\n", device));
+
+ ps->raddr = malloc(addrlen);
+ memcpy(ps->raddr, addr, addrlen);
+ ps->raddrlen = addrlen;
+ ps->laddr = malloc(addrlen);
+ memcpy(ps->laddr, addr, addrlen);
+ ps->laddrlen = addrlen;
+
+ return 0;
+}
+
+static int
+pi_inet_connect(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen)
+{
+ int sd,
+ err;
+
+ struct pi_sockaddr *paddr = (struct pi_sockaddr *) addr;
+ struct sockaddr_in serv_addr;
+ char *device = paddr->pi_device;
+
+ /* Figure out the addresses to allow */
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ if (strlen(device) > 1) {
+ serv_addr.sin_addr.s_addr = inet_addr(device);
+ if (serv_addr.sin_addr.s_addr == (in_addr_t)-1) {
+ struct hostent *hostent = gethostbyname(device);
+
+ if (!hostent) {
+ LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
+ "DEV CONNECT Inet: Unable"
+ " to determine host\n"));
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+ }
+
+ memcpy((char *) &serv_addr.sin_addr.s_addr,
+ hostent->h_addr, (size_t)hostent->h_length);
+ }
+ } else {
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ serv_addr.sin_port = htons(14238);
+
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sd < 0) {
+ LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
+ "DEV CONNECT Inet: Unable to create socket\n"));
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+ }
+
+ if ((err = pi_socket_setsd (ps, sd)) < 0)
+ return err;
+
+ if (connect (ps->sd, (struct sockaddr *) &serv_addr,
+ sizeof(serv_addr)) < 0) {
+ LOG((PI_DBG_DEV, PI_DBG_LVL_ERR,
+ "DEV CONNECT Inet: Unable to connect\n"));
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM);
+ }
+
+ ps->raddr = malloc(addrlen);
+ memcpy(ps->raddr, addr, addrlen);
+ ps->raddrlen = addrlen;
+ ps->laddr = malloc(addrlen);
+ memcpy(ps->laddr, addr, addrlen);
+ ps->laddrlen = addrlen;
+
+ switch (ps->cmd) {
+ case PI_CMD_CMP:
+ if ((err = cmp_tx_handshake(ps)) < 0)
+ goto fail;
+ break;
+ case PI_CMD_NET:
+ if ((err = net_tx_handshake(ps)) < 0)
+ goto fail;
+ break;
+ }
+ ps->state = PI_SOCK_CONN_INIT;
+ ps->command = 0;
+
+ LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV CONNECT Inet: Connected\n"));
+ return 0;
+
+fail:
+ return err;
+}
+
+static int
+pi_inet_listen(pi_socket_t *ps, int backlog)
+{
+ int result;
+
+ result = listen(ps->sd, backlog);
+ if (result == 0)
+ ps->state = PI_SOCK_LISTEN;
+
+ return result;
+}
+
+static int
+pi_inet_accept(pi_socket_t *ps, struct sockaddr *addr, size_t *addrlen)
+{
+ int sd,
+ err,
+ split = 0,
+ chunksize = 0;
+ size_t len,
+ size;
+ pl_socklen_t l = 0;
+ unsigned char cmp_flags;
+
+ if (addrlen)
+ l = *addrlen;
+ sd = accept(ps->sd, addr, &l);
+ if (addrlen)
+ *addrlen = l;
+ if (sd < 0) {
+ pi_set_error(ps->sd, sd);
+ err = PI_ERR_GENERIC_SYSTEM;
+ goto fail;
+ }
+
+ pi_socket_setsd(ps, sd);
+ pi_socket_init(ps);
+
+ switch (ps->cmd) {
+ case PI_CMD_CMP:
+ if ((err = cmp_rx_handshake(ps, 57600, 0)) < 0)
+ goto fail;
+
+ /* propagate the long packet format flag to both command and non-command stacks */
+ size = sizeof(cmp_flags);
+ pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_FLAGS, &cmp_flags, &size);
+ if (cmp_flags & CMP_FL_LONG_PACKET_SUPPORT) {
+ int use_long_format = 1;
+ size = sizeof(int);
+ pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT,
+ &use_long_format, &size);
+ ps->command ^= 1;
+ pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT,
+ &use_long_format, &size);
+ ps->command ^= 1;
+ }
+
+ break;
+ case PI_CMD_NET:
+ /* network: make sure we don't split writes. set socket option
+ * on both the command and non-command instances of the protocol
+ */
+ len = sizeof (split);
+ pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES,
+ &split, &len);
+ len = sizeof (chunksize);
+ pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE,
+ &chunksize, &len);
+
+ ps->command ^= 1;
+ len = sizeof (split);
+ pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES,
+ &split, &len);
+ len = sizeof (chunksize);
+ pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE,
+ &chunksize, &len);
+ ps->command ^= 1;
+
+ if ((err = net_rx_handshake(ps)) < 0)
+ goto fail;
+ break;
+ }
+
+ ps->state = PI_SOCK_CONN_ACCEPT;
+ ps->command = 0;
+ ps->dlprecord = 0;
+
+ LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV INET ACCEPT accepted\n"));
+
+ return ps->sd;
+
+ fail:
+ return err;
+}
+
+static int
+pi_inet_close(pi_socket_t *ps)
+{
+ if (ps->sd) {
+ close(ps->sd);
+ ps->sd = 0;
+ }
+ if (ps->laddr) {
+ free(ps->laddr);
+ ps->laddr = NULL;
+ }
+ if (ps->raddr) {
+ free(ps->raddr);
+ ps->raddr = NULL;
+ }
+ return 0;
+}
+
+static int
+pi_inet_flush(pi_socket_t *ps, int flags)
+{
+ char buf[256];
+ int fl;
+
+ if (flags & PI_FLUSH_INPUT) {
+ if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) {
+ fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK);
+ while (recv(ps->sd, buf, sizeof(buf), 0) > 0)
+ ;
+ fcntl(ps->sd, F_SETFL, fl);
+ }
+ }
+ return 0;
+}
+
+static ssize_t
+pi_inet_write(pi_socket_t *ps, const unsigned char *msg, size_t len, int flags)
+{
+ int total,
+ nwrote;
+ pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data;
+ struct timeval t;
+ fd_set ready;
+
+ FD_ZERO(&ready);
+ FD_SET(ps->sd, &ready);
+
+ total = len;
+ while (total > 0) {
+ if (data->timeout == 0) {
+ if (select(ps->sd + 1, 0, &ready, 0, 0) < 0
+ && errno == EINTR)
+ continue;
+ } else {
+ t.tv_sec = data->timeout / 1000;
+ t.tv_usec = (data->timeout % 1000) * 1000;
+ if (select(ps->sd + 1, 0, &ready, 0, &t) == 0)
+ return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT);
+ }
+ if (!FD_ISSET(ps->sd, &ready)) {
+ ps->state = PI_SOCK_CONN_BREAK;
+ return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED);
+ }
+
+ nwrote = write(ps->sd, msg, len);
+ if (nwrote < 0) {
+ /* test errno to properly set the socket error */
+ if (errno == EPIPE || errno == EBADF) {
+ ps->state = PI_SOCK_CONN_BREAK;
+ return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED);
+ }
+ return pi_set_error(ps->sd, PI_ERR_SOCK_IO);
+ }
+
+ total -= nwrote;
+ }
+ data->tx_bytes += len;
+
+ LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV TX Inet Bytes: %d\n", len));
+
+ return len;
+}
+
+static ssize_t
+pi_inet_read(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags)
+{
+ int r,
+ fl = 0;
+ pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data;
+ fd_set ready;
+ struct timeval t;
+
+ if (pi_buffer_expect (msg, len) == NULL) {
+ errno = ENOMEM;
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY);
+ }
+
+ if (flags == PI_MSG_PEEK)
+ fl = MSG_PEEK;
+
+ FD_ZERO(&ready);
+ FD_SET(ps->sd, &ready);
+
+ /* If timeout == 0, wait forever for packet, otherwise wait till
+ timeout milliseconds */
+ if (data->timeout == 0)
+ select(ps->sd + 1, &ready, 0, 0, 0);
+ else {
+ t.tv_sec = data->timeout / 1000;
+ t.tv_usec = (data->timeout % 1000) * 1000;
+ if (select(ps->sd + 1, &ready, 0, 0, &t) == 0)
+ return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT);
+ }
+
+ /* If data is available in time, read it */
+ if (FD_ISSET(ps->sd, &ready)) {
+ r = recv(ps->sd, msg->data + msg->used, len, fl);
+ if (r < 0) {
+ if (errno == EPIPE || errno == EBADF) {
+ ps->state = PI_SOCK_CONN_BREAK;
+ return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED);
+ }
+ return pi_set_error(ps->sd, PI_ERR_SOCK_IO);
+ }
+
+ data->rx_bytes += r;
+ msg->used += r;
+
+ LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV RX Inet Bytes: %d\n", r));
+ return r;
+ }
+
+ /* otherwise throw out any current packet and return */
+ LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, "DEV RX Inet timeout\n"));
+ data->rx_errors++;
+ return 0;
+}
+
+static int
+pi_inet_getsockopt(pi_socket_t *ps, int level, int option_name,
+ void *option_value, size_t *option_len)
+{
+ pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data;
+
+ switch (option_name) {
+ case PI_DEV_TIMEOUT:
+ if (*option_len != sizeof (data->timeout)) {
+ errno = EINVAL;
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
+ }
+ memcpy (option_value, &data->timeout,
+ sizeof (data->timeout));
+ *option_len = sizeof (data->timeout);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+pi_inet_setsockopt(pi_socket_t *ps, int level, int option_name,
+ const void *option_value, size_t *option_len)
+{
+ pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data;
+
+ switch (option_name) {
+ case PI_DEV_TIMEOUT:
+ if (*option_len != sizeof (data->timeout)) {
+ errno = EINVAL;
+ return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
+ }
+ memcpy (&data->timeout, option_value,
+ sizeof (data->timeout));
+ break;
+ }
+
+ return 0;
+}
+
+/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
+/* ex: set tabstop=4 expandtab: */
+/* Local Variables: */
+/* indent-tabs-mode: t */
+/* c-basic-offset: 8 */
+/* End: */