# define INCLUDE_FILE_IO # include "dgd.h" # include <sys/time.h> # include <sys/socket.h> # include <netinet/in.h> # include <arpa/inet.h> # include <netdb.h> # include <errno.h> # include "str.h" # include "array.h" # include "object.h" # include "comm.h" struct _connection_ { int fd; /* file descriptor */ struct sockaddr_in addr; /* internet address of connection */ struct _connection_ *next; /* next in list */ }; static int nusers; /* # of users */ static connection *connections; /* connections array */ static connection *flist; /* list of free connections */ static int telnet; /* telnet port socket descriptor */ static int binary; /* binary port socket descriptor */ static fd_set fds; /* file descriptor bitmap */ static fd_set readfds; /* file descriptor read bitmap */ static int maxfd; /* largest fd opened yet */ /* * NAME: conn->init() * DESCRIPTION: initialize connections */ void conn_init(maxusers, telnet_port, binary_port) int maxusers; unsigned short telnet_port, binary_port; { struct sockaddr_in sin; struct hostent *host; register int n; register connection *conn; char buffer[256]; int on; gethostname(buffer, sizeof(buffer)); host = gethostbyname(buffer); if (host == (struct hostent *) NULL) { perror("gethostbyname"); exit(2); } telnet = socket(host->h_addrtype, SOCK_STREAM, 0); binary = socket(host->h_addrtype, SOCK_STREAM, 0); if (telnet < 0 || binary < 0) { perror("socket"); exit(2); } on = 1; if (setsockopt(telnet, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("setsockopt"); exit(2); } on = 1; if (setsockopt(binary, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("setsockopt"); exit(2); } memset(&sin, '\0', sizeof(sin)); memcpy(&sin.sin_addr, host->h_addr, host->h_length); sin.sin_port = htons(telnet_port); sin.sin_family = host->h_addrtype; sin.sin_addr.s_addr = INADDR_ANY; if (bind(telnet, (struct sockaddr *) &sin, sizeof(sin)) < 0) { perror("bind"); exit(2); } sin.sin_port = htons(binary_port); if (bind(binary, (struct sockaddr *) &sin, sizeof(sin)) < 0) { perror("bind"); exit(2); } if (listen(telnet, 5) < 0 || listen(binary, 5) < 0) { perror("listen"); exit(2); } if (fcntl(telnet, F_SETFL, FNDELAY) < 0 || fcntl(binary, F_SETFL, FNDELAY) < 0) { perror("fcntl"); exit(2); } connections = ALLOC(connection, nusers = maxusers); for (n = nusers, conn = connections; n > 0; --n, conn++) { conn->fd = -1; conn->next = flist; flist = conn; } FD_ZERO(&fds); } /* * NAME: conn->finish() * DESCRIPTION: terminate connections */ void conn_finish() { close(telnet); close(binary); } /* * NAME: conn->tnew() * DESCRIPTION: accept a new telnet connection */ connection *conn_tnew() { int fd, len; struct sockaddr_in sin; register connection *conn; len = sizeof(sin); fd = accept(telnet, (struct sockaddr *) &sin, &len); if (fd < 0) { return (connection *) NULL; } conn = flist; flist = conn->next; conn->fd = fd; memcpy(&conn->addr, (char *) &sin, len); FD_SET(fd, &fds); if (fd > maxfd) { maxfd = fd; } return conn; } /* * NAME: conn->bnew() * DESCRIPTION: accept a new binary connection */ connection *conn_bnew() { int fd, len; struct sockaddr_in sin; register connection *conn; len = sizeof(sin); fd = accept(binary, (struct sockaddr *) &sin, &len); if (fd < 0) { return (connection *) NULL; } conn = flist; flist = conn->next; conn->fd = fd; memcpy(&conn->addr, (char *) &sin, len); FD_SET(fd, &fds); if (fd > maxfd) { maxfd = fd; } return conn; } /* * NAME: conn->del() * DESCRIPTION: delete a connection */ void conn_del(conn) register connection *conn; { if (conn->fd >= 0) { close(conn->fd); FD_CLR(conn->fd, &fds); conn->fd = -1; } conn->next = flist; flist = conn; } /* * NAME: conn->select() * DESCRIPTION: wait for input from connections */ int conn_select(wait) bool wait; { struct timeval timeout; memcpy(&readfds, &fds, sizeof(fd_set)); timeout.tv_sec = (int) wait; timeout.tv_usec = 0; return select(maxfd + 1, &readfds, (fd_set *) NULL, (fd_set *) NULL, &timeout); } /* * NAME: conn->read() * DESCRIPTION: read from a connection */ int conn_read(conn, buf, size) connection *conn; char *buf; int size; { if (conn->fd < 0) { return -1; } if (!FD_ISSET(conn->fd, &readfds)) { return 0; } size = read(conn->fd, buf, size); return (size == 0) ? -1 : size; } /* * NAME: conn->write() * DESCRIPTION: write to a connection */ void conn_write(conn, buf, size) connection *conn; char *buf; register int size; { if (conn->fd >= 0) { if (write(conn->fd, buf, size) < 0 && errno != EWOULDBLOCK) { close(conn->fd); FD_CLR(conn->fd, &fds); conn->fd = -1; } } } /* * NAME: conn->ipnum() * DESCRIPTION: return the ip number of a connection */ char *conn_ipnum(conn) connection *conn; { return inet_ntoa(conn->addr.sin_addr); }