aboutsummaryrefslogtreecommitdiff
path: root/src/Sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Sockets.c')
-rw-r--r--src/Sockets.c812
1 files changed, 812 insertions, 0 deletions
diff --git a/src/Sockets.c b/src/Sockets.c
new file mode 100644
index 0000000..88c67d7
--- /dev/null
+++ b/src/Sockets.c
@@ -0,0 +1,812 @@
+ /*@@
+ @file Sockets.c
+ @date Wed Sep 13 20:39:15 2000
+ @author Tom Goodale
+ @desc
+ Routines which deal with sockets.
+ These should probably move into thorn Socket at some point if
+ they aren't already there.
+ @enddesc
+ @version $Header$
+ @@*/
+
+#include "cctk.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif /* HAVE_SYS_SOCKET_H */
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif /* ARPA_INET_H */
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif /* HAVE_WINSOCK2_H */
+#include <errno.h>
+
+#include "IsoSurfacerInit.h"
+#include "IsoSurfacerGH.h"
+
+static char *rcsid = "$Header$";
+
+CCTK_FILEVERSION(DevThorns_isosurfacer_Socket_c)
+
+/********************************************************************
+ ********************* Local Data Types ***********************
+ ********************************************************************/
+
+#ifndef SOCKET
+#define SOCKET int
+#endif
+
+#ifdef SOCKET_ERROR
+#define ERROR_CHECK(a) ((a) == SOCKET_ERROR)
+#else
+#define ERROR_CHECK(a) ((a) < 0)
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#define CLOSESOCKET(a) closesocket(a)
+#else
+#define CLOSESOCKET(a) close(a)
+#endif
+
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+typedef enum {closed, open} isoSocketState;
+
+typedef struct ISOSocket
+{
+ struct ISOSocket *prev;
+ struct ISOSocket *next;
+ unsigned long filedes;
+ isoSocketState state;
+} isoSocket;
+
+/********************************************************************
+ ********************* Local Routine Prototypes *********************
+ ********************************************************************/
+
+int Iso_Write(isoSocket *connection, const char *buffer, size_t count);
+
+static SOCKET Iso_MakeSocket (unsigned long port, int *hunt);
+
+static isoSocket *SocketCreate(unsigned long int filedes, isoSocket **list);
+static void SocketDestroy(isoSocket *this, isoSocket **list);
+static void SocketClose(isoSocket *this);
+
+static int InitialiseTCP(void);
+
+static int Iso_ReadFromClient(cGH *cctkGH, isoSocket *this);
+
+/********************************************************************
+ ********************* Other Routine Prototypes *********************
+ ********************************************************************/
+
+/********************************************************************
+ ********************* Local Data *****************************
+ ********************************************************************/
+
+/* Active file descriptors */
+static fd_set active_fd_set;
+
+/* Main server socket */
+static SOCKET datasock;
+static SOCKET controlsock;
+
+static SOCKET minsock;
+static SOCKET maxsock;
+
+static isoSocket *controlsocklist = NULL;
+static isoSocket *datasocklist = NULL;
+
+/********************************************************************
+ ********************* External Routines **********************
+ ********************************************************************/
+
+
+ /*@@
+ @routine Iso_SetupServer
+ @date Wed Sep 13 20:39:15 2000
+ @author Tom Goodale
+ @desc
+ Creates a socket to listen on.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int Iso_SetupServer(int dataport, int controlport, int queue_size, int hunt)
+{
+ char hostname[1025];
+ int realdport;
+ int realcport;
+
+ /* Some systems need special logic for starting up TCP. */
+ InitialiseTCP();
+
+ /* Create the data socket and set it up to accept connections. */
+ datasock = Iso_MakeSocket (dataport, hunt ? &realdport : NULL);
+
+ if (ERROR_CHECK(listen (datasock, queue_size)))
+ {
+ perror ("listen");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Create the control socket and set it up to accept connections. */
+ controlsock = Iso_MakeSocket (controlport, hunt ? &realcport : NULL);
+
+ if (ERROR_CHECK(listen (controlsock, queue_size)))
+ {
+ perror ("listen");
+ exit (EXIT_FAILURE);
+ }
+
+ gethostname(hostname, 1024);
+
+ printf("Isosurfacer listening for control connetcions on %s port %d/\n", hostname, hunt ? realcport : controlport);
+ printf("Isosurfacer listening for data connections on %s port %d/\n", hostname, hunt ? realdport : dataport);
+
+ minsock = datasock > controlsock ? controlsock : datasock;
+ maxsock = datasock > controlsock ? datasock : controlsock;
+
+
+ /* Initialize the set of active sockets. */
+ FD_ZERO (&active_fd_set);
+ FD_SET (controlsock, &active_fd_set);
+ FD_SET (datasock, &active_fd_set);
+
+ return 0;
+}
+
+ /*@@
+ @routine Iso_ShutdownServer
+ @date Wed Sep 13 20:39:15 2000
+ @author Tom Goodale
+ @desc
+ Closes all sockets we are interested in.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int Iso_ShutdownServer(void)
+{
+ SOCKET i;
+
+ /* Close all sockets in our active set */
+ for(i = maxsock; i >= minsock; i--)
+ {
+ if(FD_ISSET(i, &active_fd_set))
+ {
+ CLOSESOCKET(i);
+ }
+ }
+
+ return 0;
+}
+
+ /*@@
+ @routine Iso_Poll
+ @date Wed Sep 13 20:39:15 2000
+ @author Tom Goodale
+ @desc
+ Main workhorse routine.
+ Looks for activity on any of the sockets which are open
+ and dispatches work.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int Iso_Poll(cGH *cctkGH, long sec, long usec)
+{
+#ifdef HAVE_SOCKLEN_T
+ socklen_t size;
+#else
+ int size;
+#endif
+
+ fd_set read_fd_set;
+
+ struct sockaddr_in clientname;
+ struct timeval timeout;
+ struct timeval *real_timeout;
+
+ isoSocket *this;
+ isoSocket *next;
+
+ if(sec >=0)
+ {
+ timeout.tv_sec = sec;
+ timeout.tv_usec = usec;
+
+ real_timeout = &timeout;
+ }
+ else
+ {
+ real_timeout = NULL;
+ }
+
+ /* Check if any input is available on one or more active sockets. */
+ read_fd_set = active_fd_set;
+
+ if (ERROR_CHECK(select (FD_SETSIZE, &read_fd_set, NULL, NULL, real_timeout)))
+ {
+ perror ("select");
+ CCTK_Abort(cctkGH, EXIT_FAILURE);
+ }
+
+ /* Service all the sockets with input pending. */
+ if (FD_ISSET (datasock, &read_fd_set))
+ {
+ /* Connection request on data socket. */
+ SOCKET new;
+ size = sizeof (clientname);
+ new = accept (datasock,
+ (struct sockaddr *) &clientname,
+ &size);
+ if (ERROR_CHECK(new))
+ {
+ perror ("accept");
+ CCTK_Abort(cctkGH, EXIT_FAILURE);
+ }
+ fprintf (stderr,
+ "Isosurfacer: data connect from host %s, port %hd.\n",
+ inet_ntoa (clientname.sin_addr),
+ ntohs (clientname.sin_port));
+
+ SocketCreate(new, &datasocklist);
+ }
+
+ if (FD_ISSET (controlsock, &read_fd_set))
+ {
+ /* Connection request on data socket. */
+ SOCKET new;
+ size = sizeof (clientname);
+ new = accept (controlsock,
+ (struct sockaddr *) &clientname,
+ &size);
+ if (ERROR_CHECK(new))
+ {
+ perror ("accept");
+ CCTK_Abort(cctkGH, EXIT_FAILURE);
+ }
+ fprintf (stderr,
+ "Isosurfacer: control connect from host %s, port %hd.\n",
+ inet_ntoa (clientname.sin_addr),
+ ntohs (clientname.sin_port));
+
+ SocketCreate(new, &controlsocklist);
+ }
+
+ for(this = controlsocklist; this; this = next)
+ {
+ next = this->next;
+ if(FD_ISSET (this->filedes, &read_fd_set))
+ {
+ /* Data arriving on an already-connected socket. */
+ if (Iso_ReadFromClient (cctkGH, this) < 0)
+ {
+ SocketDestroy(this, &controlsocklist);
+ }
+ }
+ }
+
+
+ return 0;
+}
+
+int IsoWriteDataToClients(const char *metadata,
+ CCTK_INT8 size,
+ IsoType type,
+ CCTK_INT4 *data)
+{
+ int retval;
+ CCTK_INT8 i;
+ CCTK_INT4 datatype;
+ CCTK_INT8 datasize;
+ isoSocket *this;
+ isoSocket *next;
+
+ CCTK_INT4 tmppolys[3] = {0,0,0};
+ CCTK_REAL4 tmpverts[3] = {0.0,0.0,0.0};
+
+ /* Convert the data to network byte order */
+ for(i = 0; i < size; i++)
+ {
+ data[i] = htons(data[i]);
+ }
+
+ datatype = type;
+
+ datatype = htons(datatype);
+
+ datasize = htonl(datasize);
+
+ /* Send data down all connected sockets. */
+ for(this = datasocklist; this; this = next)
+ {
+ next = this->next;
+
+ Iso_Write(this, (void *)&datasize, 8);
+ Iso_Write(this, (void *)&datatype, 4);
+ Iso_Write(this, metadata, 64);
+ retval = Iso_Write(this, (void *)data, size);
+
+ if(retval < 0)
+ {
+ SocketDestroy(this, &datasocklist);
+ }
+ }
+
+ /* Convert the data back */
+ for(i = 0; i < size; i++)
+ {
+ data[i] = htons(data[i]);
+ }
+
+
+}
+
+
+ /*@@
+ @routine Iso_Write
+ @date Fri Sep 15 18:47:41 2000
+ @author Tom Goodale
+ @desc
+ Writes part or all of an Iso data connection.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int Iso_Write(isoSocket *connection, const char *buffer, size_t count)
+{
+ int retval;
+ size_t bytes_sent;
+ size_t halfcount;
+ int done;
+ int tmp;
+ fd_set this_set;
+
+ if(connection->state == open)
+ {
+ FD_ZERO (&this_set);
+ done = 0;
+ bytes_sent = 0;
+ while(!done)
+ {
+ /* Try and send the data. Make sure we don't get a SIGPIPE if the
+ * other end is closed.
+ */
+ retval = send(connection->filedes,
+ buffer+bytes_sent,
+ count-bytes_sent,
+ MSG_NOSIGNAL);
+
+ /* Check for errors */
+ if(ERROR_CHECK(retval))
+ {
+ switch(errno)
+ {
+#ifdef EMSGSIZE
+ case EMSGSIZE : /* The socket requires that message be sent atomically,
+ * and the size of the message to be sent made this
+ * impossible.
+ */
+ /* Split message in two and try again. */
+ halfcount = count/2;
+ retval = Iso_Write(connection, buffer, halfcount);
+ if(retval > -1)
+ {
+ tmp = Iso_Write(connection, buffer+halfcount, count-halfcount);
+ if(tmp > -1)
+ {
+ retval += tmp;
+ }
+ else
+ {
+ retval = tmp;
+ }
+ }
+ break;
+#endif
+
+#ifdef ENOBUFS
+ case ENOBUFS :
+ /* The output queue for a network interface was full. This generally indicates that the interface has
+ * stopped sending, but may be caused by transient congestion. (This cannot occur in Linux, packets are
+ * just silently dropped when a device queue overflows.)
+ */
+ retval = 0;
+ break;
+#endif
+ case EBADF : /* An invalid descriptor was specified. */
+#ifdef ENOTSOCK
+ case ENOTSOCK : /* The filedescriptor is not a socket. */
+#endif
+ case EPIPE : /* The local end has been shut down on a connection oriented socket. In this case the process will also
+ * receive a SIGPIPE unless MSG_NOSIGNAL is set.
+ */
+ SocketClose(connection);
+ break;
+
+ case EINTR : /* A signal occurred.*/
+
+ case ENOMEM : /* No memory available. */
+
+ case EINVAL : /* Invalid argument passed. */
+
+ case EFAULT : /* An invalid user space address was specified for a parameter. */
+ break;
+
+#if 0
+ case EAGAIN :
+ case EWOULDBLOCK :
+ /* The socket is marked non-blocking and the requested operation would block. */
+#endif
+ default :
+ fprintf(stderr, "Error: this should never happen - %s %d", __FILE__, __LINE__);
+ }
+ }
+ else
+ {
+ bytes_sent += retval;
+ }
+
+ if(!(ERROR_CHECK(retval)) && bytes_sent < count)
+ {
+ /* Wait until can write */
+ FD_SET (connection->filedes, &this_set);
+ if (ERROR_CHECK(select (FD_SETSIZE, NULL, &this_set, NULL, NULL)))
+ {
+ perror ("select");
+ CCTK_Abort(NULL, EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ done = 1;
+ }
+ };
+ }
+ else
+ {
+ retval = -1;
+ }
+
+#ifdef Iso_DEBUG
+ if(retval != -1)
+ {
+ fprintf (stderr, "Wrote: `%s'\n", buffer);
+ }
+ else
+ {
+ fprintf(stderr, "Couldn't write to the socket 8-(\n");
+ }
+#endif
+
+ return retval;
+}
+
+ /*@@
+ @routine Iso_Read
+ @date Mon Sep 18 10:14:03 2000
+ @author Tom Goodale
+ @desc
+ Reads part or all of an Iso request.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int Iso_Read(isoSocket *connection, char *buffer, size_t count)
+{
+ int retval;
+
+ if(connection->state == open)
+ {
+ /* Currently don't do anything fancy. */
+ retval = recv(connection->filedes, buffer, count,MSG_NOSIGNAL);
+
+#ifdef Iso_DEBUG
+ fprintf (stderr, "Read: `%s'\n", buffer);
+#endif
+ }
+ else
+ {
+ retval = -1;
+ }
+
+ return retval;
+}
+
+/********************************************************************
+ ********************* Local Routines *************************
+ ********************************************************************/
+
+ /*@@
+ @routine Iso_MakeSocket
+ @date Wed Sep 13 20:39:15 2000
+ @author Tom Goodale
+ @desc
+ Creates a socket.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int Iso_MakeSocket (unsigned long port, int *hunt)
+{
+ int this_sock;
+ struct sockaddr_in name;
+ int opt;
+ int done;
+ int realport;
+ int error;
+
+ /* Create the socket. */
+ this_sock = socket (PF_INET, SOCK_STREAM, 0);
+ if (ERROR_CHECK(this_sock))
+ {
+ perror ("socket");
+ CCTK_Abort(NULL, EXIT_FAILURE);
+ }
+
+ /* Try to reuse the port if possible */
+#ifdef SO_REUSEADDR
+ opt = 1;
+ setsockopt(this_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+#endif
+
+ done = 0;
+ realport = port;
+
+ while(!done)
+ {
+ /* Give the socket a name. */
+ name.sin_family = AF_INET;
+ name.sin_port = htons (realport);
+ name.sin_addr.s_addr = htonl (INADDR_ANY);
+ if (ERROR_CHECK(error = bind (this_sock, (struct sockaddr *) &name, sizeof (name))))
+ {
+ if(hunt)
+ {
+ /* Hunt for a new port */
+ fprintf(stderr, "Port %u taken, trying %u\n", realport, realport+1);
+ realport++;
+ }
+ else
+ {
+ done = 1;
+ }
+ }
+ else
+ {
+ done = 1;
+ }
+ }
+
+ if(ERROR_CHECK(error))
+ {
+ perror ("bind");
+ CCTK_Abort(NULL,EXIT_FAILURE);
+ }
+ else if(hunt)
+ {
+ *hunt = realport;
+ }
+
+ return this_sock;
+}
+
+ /*@@
+ @routine SocketCreate
+ @date Thu Sep 21 15:03:32 2000
+ @author Tom Goodale
+ @desc
+ Creates an isoSocket structure and links it to the list.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static isoSocket *SocketCreate(unsigned long int filedes, isoSocket **list)
+{
+ isoSocket *this;
+
+ this = (isoSocket *)malloc(sizeof (isoSocket));
+
+ if(this)
+ {
+ this->filedes = filedes;
+ this->state = open;
+ this->prev = NULL;
+ this->next = *list;
+
+ if(*list)
+ {
+ (*list)->prev = this;
+ }
+
+ *list = this;
+
+ FD_SET (this->filedes, &active_fd_set);
+ }
+
+ return this;
+}
+
+ /*@@
+ @routine SocketDestroy
+ @date Thu Sep 21 15:04:03 2000
+ @author Tom Goodale
+ @desc
+ Destroys an isoSocket structure and removes it from the list.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static void SocketDestroy(isoSocket *this, isoSocket **list)
+{
+ if(this)
+ {
+ if(this->state == open)
+ {
+ SocketClose(this);
+ }
+
+ if(this->next)
+ {
+ this->next->prev = this->prev;
+ }
+
+ if(this->prev)
+ {
+ this->prev->next=this->next;
+ }
+ else
+ {
+ *list = this->next;
+ }
+
+ free(this);
+ }
+}
+
+ /*@@
+ @routine SocketClose
+ @date Thu Sep 21 15:04:27 2000
+ @author Tom Goodale
+ @desc
+ Closes the socket associated with an isoSocket structure.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static void SocketClose(isoSocket *this)
+{
+ if(this)
+ {
+ if(this->state == open)
+ {
+ CLOSESOCKET(this->filedes);
+ this->state=closed;
+ FD_CLR (this->filedes, &active_fd_set);
+ }
+ }
+}
+
+ /*@@
+ @routine Iso_ReadFromClient
+ @date Wed Oct 4 11:27:32 2000
+ @author Tom Goodale
+ @desc
+ Reads a client command.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static int Iso_ReadFromClient(cGH *cctkGH, isoSocket *this)
+{
+ return -1;
+}
+
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
+
+/* Special code for starting up the socket layer. */
+
+#ifdef HAVE_WINSOCK2_H
+#ifndef _M_IX86
+#define _M_IX86 400
+#endif
+
+#include <sys/types.h>
+#include <windows.h>
+#include <stdio.h>
+
+static int InitialiseTCP(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int errnumber;
+
+ wVersionRequested = MAKEWORD( 2, 0 );
+
+ errnumber = WSAStartup( wVersionRequested, &wsaData );
+
+ if (errnumber)
+ {
+ fprintf(stderr, "Couldn't start Windows socket layer\n");
+ }
+ else
+ {
+ printf("Windows socket layer initialized.\n");
+ }
+
+ return errnumber;
+}
+
+#else
+
+static int InitialiseTCP(void)
+{
+ return 0;
+}
+
+#endif /* defined HAVE_WINSOCK2_H */