#include <X11/Xpoll.h>
#include "scope.h"
#include <unistd.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if !defined(FIOCLEX) && defined(HAVE_SYS_FILIO_H)
#include <sys/filio.h>
#endif
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <errno.h>
void
InitializeFD(void)
{
register short i;
enterprocedure("InitializeFD");
#ifdef _SC_OPEN_MAX
MaxFD = sysconf(_SC_OPEN_MAX);
#elif defined(HAVE_GETDTABLESIZE)
MaxFD = getdtablesize();
#else
MaxFD = _NFILE - 1;
#endif
if (MaxFD > FD_SETSIZE) {
MaxFD = FD_SETSIZE;
}
if (MaxFD > StaticMaxFD)
{
fprintf(stderr, "Recompile with larger StaticMaxFD value %d\n", MaxFD);
MaxFD = StaticMaxFD;
}
FDD = (struct FDDescriptor *)
Malloc ((long)(MaxFD * sizeof (struct FDDescriptor)));
if (FDD == NULL) {
panic("Can't allocate memory!");
}
bzero(FDD, (MaxFD * sizeof (struct FDDescriptor)));
for (i = 0; i < MaxFD; i++)
{
if (i > 2)
close(i);
}
MaxFD -= 4;
nFDsInUse = 0 ;
FD_ZERO(&ReadDescriptors);
HighestFD = 0;
UsingFD(fileno(stdin), NULL, NULL, NULL);
UsingFD(fileno(stdout), NULL, NULL, NULL);
UsingFD(fileno(stderr), NULL, NULL, NULL);
}
void
UsingFD(
FD fd,
void (*Handler)(int),
void (*FlushHandler)(int),
XtransConnInfo trans_conn)
{
if (FDD[fd].Busy)
NotUsingFD(fd);
nFDsInUse += 1;
FDD[fd].Busy = true;
FDD[fd].InputHandler = Handler;
FDD[fd].FlushHandler = FlushHandler;
#ifdef USE_XTRANS
FDD[fd].trans_conn = trans_conn;
#endif
if (Handler == NULL)
FD_CLR(fd,&ReadDescriptors) ;
else
FD_SET(fd,&ReadDescriptors) ;
if (fd > HighestFD)
HighestFD = fd;
if (nFDsInUse >= MaxFD)
panic("no more FDs");
debug(128,(stderr, "Using FD %d, %d of %d in use\n", fd, nFDsInUse, MaxFD));
}
void
NotUsingFD(
FD fd)
{
debug(128,(stderr, "Not Using FD %d\n", fd));
if (FDD[fd].Busy)
nFDsInUse -= 1;
FDD[fd].Busy = false;
FD_CLR(fd,&ReadDescriptors) ;
while (!FDD[HighestFD].Busy && HighestFD > 0)
HighestFD -= 1;
debug(128,(stderr, "Highest FD %d, in use %d\n", HighestFD, nFDsInUse));
}
#ifdef USE_XTRANS
XtransConnInfo GetXTransConnInfo(FD fd)
{
return FDD[fd].trans_conn;
}
#endif
static void
EOFonFD (
FD fd)
{
enterprocedure("EOFonFD");
debug(128,(stderr, "EOF on %d\n", fd));
#ifdef USE_XTRANS
if (FDD[fd].trans_conn)
_X11TransClose(FDD[fd].trans_conn);
else
#endif
close(fd);
NotUsingFD(fd);
}
FD
AcceptConnection (
FD ConnectionSocket)
{
FD ClientFD;
struct sockaddr_in from;
socklen_t len = sizeof (from);
int tmp = 1;
enterprocedure("ConnectToClient");
ClientFD = accept(ConnectionSocket, (struct sockaddr *)&from, &len);
debug(4,(stderr, "Connect To Client: FD %d\n", ClientFD));
if (ClientFD < 0 && errno == EWOULDBLOCK)
{
debug(4,(stderr, "Almost blocked accepting FD %d\n", ClientFD));
panic("Can't connect to Client");
}
if (ClientFD < 0)
{
debug(4,(stderr, "NewConnection: error %d\n", errno));
panic("Can't connect to Client");
}
#ifdef FD_CLOEXEC
(void)fcntl(ClientFD, F_SETFD, FD_CLOEXEC);
#else
(void)ioctl(ClientFD, FIOCLEX, 0);
#endif
#if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux))
(void) fcntl (ClientFD, F_SETFL, O_NONBLOCK);
#else
#ifdef FIOSNBIO
ioctl (ClientFD, FIOSNBIO, &ON);
#else
(void) fcntl (ClientFD, F_SETFL, FNDELAY);
#endif
#endif
(void) setsockopt(ClientFD, IPPROTO_TCP, TCP_NODELAY, (char *) &tmp, sizeof (int));
return(ClientFD);
}
FD
MakeConnection(
const char *server,
short port,
int report,
XtransConnInfo *trans_conn
)
{
FD ServerFD;
#ifdef USE_XTRANS
char address[256];
int connect_stat;
const char *protocols[] = {"local", "unix", "tcp", "inet6", "inet", NULL};
const char **s;
for(*trans_conn = NULL, s = protocols; *trans_conn == NULL && *s; s++) {
snprintf (address, sizeof(address), "%s/%s:%ld", *s, server, port - ServerBasePort);
*trans_conn = _X11TransOpenCOTSClient(address);
}
if(*trans_conn == NULL) {
debug(1,(stderr, "OpenCOTSClient failed\n"));
panic("Can't open connection to Server");
}
if ((connect_stat = _X11TransConnect(*trans_conn,address)) < 0 ) {
_X11TransClose(*trans_conn);
*trans_conn = NULL;
debug(1,(stderr, "TransConnect failed\n"));
panic("Can't open connection to Server");
}
ServerFD = _X11TransGetConnectionNumber(*trans_conn);
#else
char HostName[512];
struct sockaddr_in sin;
struct sockaddr_un sun;
struct sockaddr *saddr;
int salen;
struct hostent *hp;
int tmp = 1;
#ifndef SO_DONTLINGER
struct linger linger;
#endif
enterprocedure("ConnectToServer");
if (*server == '\0')
{
sun.sun_family = AF_UNIX;
sprintf (sun.sun_path, "/tmp/.X11-unix/X%d", port - 6000);
salen = sizeof (sun.sun_family) + strlen (sun.sun_path) + 1;
saddr = (struct sockaddr *) &sun;
}
else
{
debug(4,(stderr, "try to connect on %s\n", server));
bzero((char *)&sin, sizeof(sin));
sin.sin_addr.s_addr = inet_addr (server);
if ((long) sin.sin_addr.s_addr == -1)
{
hp = gethostbyname(server);
if (hp == 0)
{
perror("gethostbyname failed");
debug(1,(stderr, "gethostbyname failed for %s\n", server));
panic("Can't open connection to Server");
}
bcopy((char *)hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
}
sin.sin_family = AF_INET;
if (port == ScopePort
&& strcmp(server, ScopeHost) == 0)
{
char error_message[100];
(void)sprintf(error_message, "Trying to attach to myself: %s,%d\n",
server, sin.sin_port);
panic(error_message);
}
sin.sin_port = htons (port);
salen = sizeof (sin);
saddr = (struct sockaddr *) &sin;
}
ServerFD = socket(saddr->sa_family, SOCK_STREAM, 0);
if (ServerFD < 0)
{
perror("socket() to Server failed");
debug(1,(stderr, "socket failed\n"));
panic("Can't open connection to Server");
}
(void) setsockopt(ServerFD, SOL_SOCKET, SO_REUSEADDR, (char *) NULL, 0);
#ifdef SO_USELOOPBACK
(void) setsockopt(ServerFD, SOL_SOCKET, SO_USELOOPBACK,(char *) NULL, 0);
#endif
(void) setsockopt(ServerFD, IPPROTO_TCP, TCP_NODELAY, (char *) &tmp, sizeof (int));
#ifdef SO_DONTLINGER
(void) setsockopt(ServerFD, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
#else
linger.l_onoff = 0;
linger.l_linger = 0;
(void) setsockopt(ServerFD, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof linger);
#endif
if (connect(ServerFD, saddr, salen) < 0)
{
debug(4,(stderr, "connect returns errno of %d\n", errno));
if (errno != 0)
if (report)
perror("connect");
switch (errno)
{
case ECONNREFUSED:
(void)close(ServerFD);
debug(1,(stderr, "No Server\n"));
if (report)
warn("Can't open connection to Server");
return(-1);
default:
(void)close(ServerFD);
panic("Can't open connection to Server");
}
}
#endif
debug(4,(stderr, "Connect To Server: FD %d\n", ServerFD));
return(ServerFD);
}
int
MainLoop(void)
{
enterprocedure("MainLoop");
while (true)
{
fd_set rfds, wfds, xfds;
short nfds;
short fd;
rfds = ReadDescriptors;
XFD_UNSET(&rfds, &BlockedReadDescriptors);
xfds = rfds;
XFD_ANDSET(&wfds, &ReadDescriptors, &WriteDescriptors);
debug(128,(stderr, "select %d, rfds = 0%o\n", HighestFD + 1, rfds));
if (Interrupt || (!XFD_ANYSET(&rfds) && !XFD_ANYSET(&wfds)))
{
ReadCommands ();
Interrupt = 0;
continue;
}
nfds = select(HighestFD + 1, &rfds, &wfds, &xfds, (struct timeval *)NULL);
debug(128,(stderr,
"select nfds = 0%o, rfds = 0%o, wfds = 0%o, xfds = 0%o\n",
nfds, rfds, wfds, xfds));
if (nfds < 0)
{
if (errno == EINTR)
continue ;
debug(1,(stderr, "Bad select - errno = %d\n", errno));
if (errno == EBADF)
{
EOFonFD(HighestFD);
continue;
}
if (Interrupt)
{
ReadCommands ();
Interrupt = 0;
}
else
{
panic("Select returns error");
}
continue ;
}
if (nfds == 0)
{
TimerExpired();
continue;
}
for (fd = 0; fd <= HighestFD; fd++)
{
if (FD_ISSET(fd,&rfds))
{
if (FDD[fd].InputHandler == NULL)
{
panic("FD selected with no handler");
debug(1,(stderr, "FD %d has NULL handler\n", fd));
}
else
(FDD[fd].InputHandler)(fd);
}
if (FD_ISSET(fd,&wfds))
{
if (FDD[fd].FlushHandler == NULL)
{
panic("FD selected with no flush handler");
}
else
(FDD[fd].FlushHandler)(fd);
}
}
}
return 0;
}