--- l2_ch_socket.c 2001/08/26 13:07:27 1.5
+++ l2_ch_socket.c 2001/09/02 14:38:51 1.6
@@ -27,37 +27,86 @@
** l2_ch_socket.c: socket channel implementation
*/
-#include "l2.h"
-#include "l2_p.h"
-
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include "l2.h"
+#include "l2_p.h"
+
+#define HAVE_INET_ATON
+#ifndef HAVE_INET_PTON
+#ifdef HAVE_INET_ATON
+/* !!! TODO change pton1 to pton !!! */
+static int inet_pton1(int iFamily, const char *pszAddress, void *pvMemref)
+{
+ int i = 0;
+ struct in_addr IP4Addr;
+ struct in6_addr IP6Addr;
+ char *pszNextfield = NULL; /* For IPv6 address trans */
+ char **ppszVerify = &pszNextfield; /* To check IPv6 validity */
+
+ if (iFamily == AF_INET)
+ {
+ if (inet_aton(pszAddress, &IP4Addr))
+ {
+ memcpy(pvMemref, &IP4Addr, sizeof(struct in_addr));
+ return 1;
+ }
+ return 0;
+ }
+
+ else if (iFamily == AF_INET6)
+ {
+ for (i = 0; i < 16; i++) /* Iterate through the IPv6 address fields */
+ {
+ ppszVerify = &pszNextfield; /* Reset and compare later to verify */
+ IP6Addr.__u6_addr.__u6_addr8[i] = (u_int8_t)strtol(pszAddress,\
+ &pszNextfield, 16);
+ *pszNextfield++; /* !!! TODO Problema !!! */
+
+ if ((&pszNextfield - ppszVerify) != 2)
+ return 0; /* User is supplying a IPv6 format we don't support */
+ }
+ memcpy(pvMemref, &IP6Addr, sizeof(struct in6_addr));
+ return 1;
+ }
+
+ else /* User converting from an address family that we don't support */
+ {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
+#else
+#error "neither inet_pton nor inet_aton available"
+#endif
+#endif
/* declare private channel configuration */
-typedef struct {
- int iSocket; /* Socket descriptor */
- int iDomain; /* Hardcoded to support only IPv4 and IPv6 */
- int iProtocol; /* Hardcoded to support only IPv4 and IPv6 */
- int iType; /* Hardcoded for writing streams to iSocket */
- struct sockaddr *pAddr; /* Where do we open a socket? */
+typedef struct
+{
+ char *pszHost; /* IP Address or name of host to connect to */
+ int iPort; /* TCP Port to connect to */
+ int iSocket; /* Socket descriptor used during writing */
} l2_ch_socket_t;
/* create channel */
static int hook_create(l2_context_t *ctx)
{
- l2_ch_socket_t *cfg;
+ l2_ch_socket_t *cfg = NULL;
/* allocate private channel configuration */
if ((cfg = (l2_ch_socket_t *)malloc(sizeof(l2_ch_socket_t))) == NULL)
return L2_ERROR;
/* initialize configuration with reasonable defaults */
- cfg->iSocket = 0;
- cfg->iDomain = PF_INET; /* Internet family */
- cfg->iType = SOCK_STREAM; /* We write streams reliably */
- cfg->iProtocol = IPPROTO_TCP; /* TCP socket */
- cfg->pAddr = NULL;
+ cfg->pszHost = NULL;
+ cfg->iPort = 0;
+ cfg->iSocket = -1;
/* link private channel configuration into channel context */
ctx->vp = cfg;
@@ -69,21 +118,16 @@
static int hook_configure(l2_context_t *ctx, const char *fmt, va_list ap)
{
l2_ch_socket_t *cfg;
- char pszAddress[L2_MAX_STRING];
- unsigned short unInport;
l2_param_t pa[3];
l2_result_t rv;
- unInport = 0;
-
/* parameter checks */
if ((cfg = (l2_ch_socket_t *)ctx->vp) == NULL)
return L2_ERROR;
/* feed and call generic parameter parsing engine */
- L2_PARAM_SET(pa[0], address, CHARPTR, pszAddress);
- L2_PARAM_SET(pa[1], port, USHORT, &unInport);
-/* TODO: Fill in the cfg-> structure after building the socket */
+ L2_PARAM_SET(pa[0], host, CHARPTR, &cfg->pszHost);
+ L2_PARAM_SET(pa[1], port, INT, &cfg->iPort);
L2_PARAM_END(pa[2]);
rv = l2_channel_setparams(pa, fmt, ap);
@@ -93,13 +137,55 @@
/* open channel */
static int hook_open(l2_context_t *ctx, l2_channel_t *downstream)
{
- l2_ch_socket_t *cfg;
+ l2_ch_socket_t *cfg;
+ struct hostent *pHostentry;
+ struct sockaddr_in IP4Sockaddr;
+ struct sockaddr_in6 IP6Sockaddr;
/* parameter checks */
if ((cfg = (l2_ch_socket_t *)ctx->vp) == NULL)
return L2_ERROR;
+ if (cfg->pszHost == NULL)
+ return L2_ERROR;
+
+ /* open channel socket */
+ /* resolve host numerically */
+ if (inet_pton1(AF_INET, cfg->pszHost, &IP4Sockaddr.sin_addr.s_addr) == 1)
+ {
+ IP4Sockaddr.sin_family = AF_INET;
+ IP4Sockaddr.sin_port = htons(cfg->iPort);
+ }
+
+ /* resolve host nominally */
+ else if ((pHostentry = gethostbyname(cfg->pszHost)) != NULL)
+ {
+ if (pHostentry->h_addrtype == AF_INET)
+ {
+ IP4Sockaddr.sin_family = AF_INET;
+ IP4Sockaddr.sin_port = htons(cfg->iPort);
+ memcpy(&IP4Sockaddr.sin_addr.s_addr, pHostentry->h_addr_list[0],\
+ sizeof(IP4Sockaddr.sin_addr.s_addr));
+ }
+
+ else if (pHostentry->h_addrtype == AF_INET6)
+ {
+ IP6Sockaddr.sin6_family = AF_INET6;
+ IP6Sockaddr.sin6_port = htons(cfg->iPort);
+ memcpy(&IP6Sockaddr.sin6_addr.__u6_addr, pHostentry->h_addr_list[0],\
+ sizeof(IP6Sockaddr.sin6_addr.__u6_addr));
+ }
+ }
+
+ else
+ return L2_ERROR;
- /* open channel socket */
+ if ((cfg->iSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+ return L2_ERROR;
+ if (connect(cfg->iSocket, (struct sockaddr *)&IP4Sockaddr, sizeof(IP4Sockaddr)))
+ {
+ close(cfg->iSocket);
+ return L2_ERROR;
+ }
/* optionally open downstream channel, too */
if (downstream != NULL)
@@ -118,8 +204,12 @@
/* parameter checks */
if ((cfg = (l2_ch_socket_t *)ctx->vp) == NULL)
return L2_ERROR;
+ if (cfg->iSocket == -1)
+ return L2_ERROR;
/* write message to channel socket */
+ if (send(cfg->iSocket, buf, buf_size, 0) == -1)
+ return L2_ERROR;
/* optionally write to downstream channel, too */
if (downstream != NULL)
@@ -132,6 +222,8 @@
/* flush channel */
static int hook_flush(l2_context_t *ctx, l2_channel_t *downstream)
{
+ /* NOP for this channel, because Unix I/O sockets are unbuffered! */
+
/* optionally flush downstream channel, too */
if (downstream != NULL)
if (l2_channel_flush(downstream) == L2_ERROR)
@@ -153,8 +245,12 @@
/* parameter checks */
if ((cfg = (l2_ch_socket_t *)ctx->vp) == NULL)
return L2_ERROR;
+ if (cfg->iSocket == -1)
+ return L2_ERROR;
/* close channel socket */
+ if ((shutdown(cfg->iSocket, SHUT_RDWR)) || (close(cfg->iSocket)))
+ return L2_ERROR;
return L2_OK;
}
|