fis-gtm/sr_port/iotcp_list.c

189 lines
4.7 KiB
C

/****************************************************************
* *
* Copyright 2001, 2009 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
/* iotcp_list.c - routines to maintain a list of TCP/IP listening sockets */
#include "mdef.h"
#include "gtm_stdio.h"
#include "gtm_string.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
#include <errno.h>
#include "io_params.h"
#include "io.h"
#include "iotcproutine.h"
#include "iotcpdef.h"
/* list of listening sockets */
typedef struct lsock_rec_s
{
int socket;
struct sockaddr_in sin;
struct lsock_rec_s *next;
io_log_name *ldev; /* listening device record */
} lsock_rec;
static lsock_rec *lsock_list = NULL;
GBLREF tcp_library_struct tcp_routines;
int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr);
/* find the listening socket associated with the address of this
* new socket, creating a listening socket if there is none.
*/
int iotcp_getlsock(io_log_name *dev)
{
d_tcp_struct *tcpptr;
lsock_rec *ls;
#ifdef DEBUG_TCP
PRINTF("iotcp_getlsock ---\n");
#endif
tcpptr = (d_tcp_struct *)dev->iod->dev_sp;
for (ls = lsock_list; ls != NULL; ls = ls->next)
if (tcpptr->sin.sin_addr.s_addr == ls->sin.sin_addr.s_addr && tcpptr->sin.sin_port == ls->sin.sin_port)
return ls->socket;
return iotcp_newlsock(dev, tcpptr);
}
int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr)
{
lsock_rec *new_lsock;
io_log_name *ldev; /* listening device */
d_tcp_struct *lsock_tcp;
int lsock;
char buf[MAX_TRANS_NAME_LEN];
static char ones[] = {1, 1, 1};
mstr ldev_name;
int on = 1;
char *errptr;
int4 errlen;
error_def(ERR_SOCKINIT);
error_def(ERR_TEXT);
#ifdef DEBUG_TCP
PRINTF("iotcp_newlsock ---\n");
#endif
lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
if (lsock == -1)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
/* allow multiple connections to the same IP address */
if (tcp_routines.aa_setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on)) == -1)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
(void)tcp_routines.aa_close(lsock);
rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
if (tcp_routines.aa_bind(lsock, (struct sockaddr *)&tcpptr->sin, SIZEOF(struct sockaddr)) == -1)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
(void)tcp_routines.aa_close(lsock);
rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
/* establish a queue of length 5 for incoming connections */
if (tcp_routines.aa_listen(lsock, 5) == -1)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
(void)tcp_routines.aa_close(lsock);
rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
/* create an extra device for the listening socket (device
* name is the user-specified device name with three ^A's
* appended). We need this device to be on the io_log_name
* list so that it gets closed automatically when the user's
* program exits.
*/
ldev_name.addr=buf;
memcpy(ldev_name.addr, dev->dollar_io, dev->len);
memcpy(ldev_name.addr+dev->len, ones, 3);
ldev_name.len = dev->len + 2;
ldev = get_log_name(&ldev_name, INSERT);
/* copy all state information from the current device */
/* io descriptor */
ldev->iod = (io_desc *)malloc(SIZEOF(io_desc));
memcpy(ldev->iod, dev->iod, SIZEOF(io_desc));
ldev->iod->state = dev_open;
ldev->iod->pair.in = ldev->iod;
ldev->iod->pair.out = ldev->iod;
/* tcp-specific information */
ldev->iod->dev_sp = (void *)malloc(SIZEOF(d_tcp_struct));
lsock_tcp=(d_tcp_struct *)ldev->iod->dev_sp;
memcpy(lsock_tcp, tcpptr, SIZEOF(d_tcp_struct));
lsock_tcp->socket = lsock;
ldev->iod->state = dev_open;
/* add to our list of tcp listening sockets */
new_lsock = (lsock_rec *)malloc(SIZEOF(lsock_rec));
new_lsock->socket = lsock;
new_lsock->sin = tcpptr->sin;
new_lsock->next = lsock_list;
new_lsock->ldev = ldev;
lsock_list = new_lsock;
return lsock;
}
void iotcp_rmlsock(io_desc *iod)
{
lsock_rec *ls, *prev, *next;
d_tcp_struct *tcpptr = (d_tcp_struct *)iod->dev_sp;
for (prev = NULL, ls = lsock_list; ls != NULL;)
{
next = ls->next;
if (tcpptr->sin.sin_port == ls->sin.sin_port)
{
if (prev)
prev->next = ls->next;
else
lsock_list = ls->next;
tcp_routines.aa_close(ls->socket);
ls->ldev->iod->state = dev_closed;
free(ls);
}
else
prev = ls;
ls = next;
}
}