/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include #include #if DXD_HAS_WINSOCKETS /* here's where to put NT windows socket specific includes */ /* will need to fix other code as necessary */ #define EADDRINUSE WSAEADDRINUSE #include #else #include #include #include #if DXD_SOCKET_UNIXDOMAIN_OK #include #endif #ifndef DXD_HAS_WINSOCKETS #include #endif #if DXD_NEEDS_SYS_SELECT_H #include #endif #endif #ifdef DXD_WIN #include #else #include #endif #include #include #define SOCK_QUEUE_LENGTH 1 #define SOCK_ACCEPT_TIMEOUT 60 /* Seconds */ /* * Parse the DXHOST environment variable and determine the host name and * socket port number to use for remote connections. The format of the * varible is 'hostname[,portnumber]'. The default port number (if one * is not given) is 1900. This number is arbitrary, but should not collide * with anything in /etc/services. In general, I believe that most numbers * over 1024 will work. */ _dxf_ExGetSocket(char *name, int *port) { char *getenv(); char *env; char *p; if (name) *name = '\0'; *port = 1900; env = getenv("DXHOST"); if (env == NULL) return(0); p = env; while (*p && *p != ',') p++; if (*p == ',') { if (name) { p = env; while (*p && *p != ',') *name++ = *p++; *name = '\0'; } p++; *port = atoi(p); } return(1); } /* * Open a socket port and wait for a client to connect. * This opens 2 sockets (except on the server), one internet domain, and * one unix domain. It then selects on both sockets to see to which one the * ui connects, and returns the new connection, closing the one not * selected. */ _dxf_ExInitServer(int pport) { int sock = -1; struct sockaddr_in server; #if DXD_SOCKET_UNIXDOMAIN_OK int usock = -1; struct sockaddr_un userver; int oldUmask; #endif struct linger sl; int length; ushort port; int fd; int sts; int oldPort; extern int errno; int tries; fd_set fds; #if DXD_HAS_GETDTABLESIZE int width = getdtablesize(); #else #ifdef DXD_HAS_WINSOCKETS int width = FD_SETSIZE; #else int width = MAXFUPLIM; #endif #endif struct timeval to; port = pport; retry: sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); fd = -1; goto error; } sl.l_onoff = 1; sl.l_linger = 0; setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&sl, sizeof(sl)); #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(sock); #endif #if DXD_SOCKET_UNIXDOMAIN_OK usock = socket(AF_UNIX, SOCK_STREAM, 0); if (usock < 0) { perror ("socket"); fd = -1; goto error; } setsockopt(usock, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)); #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(sock); #endif #endif server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(port); length = sizeof(struct sockaddr_in); /* Try to find a working port, and keep trying if you get EADDRINUSE. * If we get some other error, try a few times because we sometimes * get bad error numbers on the server. */ tries = 0; while ((sts = bind(sock, (struct sockaddr *)&server, length)) < 0 && (errno == EADDRINUSE || tries++ < 5)) { oldPort = port; server.sin_port = htons(++port); if (ntohs(server.sin_port) < oldPort) break; } if (sts < 0) { perror ("bind"); fd = -1; goto error; } if (getsockname(sock, (struct sockaddr *)&server, &length) < 0) { perror ("getsockname"); fd = -1; goto error; } #if DXD_SOCKET_UNIXDOMAIN_OK userver.sun_family = AF_UNIX; sprintf(userver.sun_path, "/tmp/.DX-unix/DX%d", port); length = sizeof (userver) - sizeof(userver.sun_path) + strlen (userver.sun_path); oldUmask = umask(0); mkdir("/tmp/.DX-unix", 0777); chmod("/tmp/.DX-unix", 0777); umask(oldUmask); unlink(userver.sun_path); /* Try to find a working port, and keep trying if you get EADDRINUSE. * If we get some other error, try a few times because we sometimes * get bad error numbers on the server. */ if ((sts = bind(usock, (struct sockaddr *)&userver, length)) < 0 && errno == EADDRINUSE) { oldPort = port; server.sin_port = htons(++port); close (sock); close (usock); sock = -1; usock = -1; if (ntohs(server.sin_port) > oldPort) goto retry; } if (sts < 0) { perror ("bind"); fd = -1; goto error; } #endif if (listen(sock, SOCK_QUEUE_LENGTH) < 0) { perror ("listen"); fd = -1; goto error; } #if DXD_SOCKET_UNIXDOMAIN_OK if (listen(usock, SOCK_QUEUE_LENGTH) < 0) { perror ("listen"); fd = -1; goto error; } #endif printf ("port = %d\n", ntohs(server.sin_port)); fflush(stdout); /* Wait (in select) for someone to connect. * if we get through the error checks, someone must want to connect to * our port, accept him/her. Otherwize, block in accept until someone * connects. If stdin is not a terminal, timeout after SOCK_ACCEPT_TIMEOUT * seconds. */ #ifndef DXD_HAS_LIBIOP FD_ZERO(&fds); FD_SET(sock, &fds); #if DXD_SOCKET_UNIXDOMAIN_OK FD_SET(usock, &fds); #endif if (!isatty(0)) { to.tv_sec = SOCK_ACCEPT_TIMEOUT; to.tv_usec = 0; sts = select(width, (SelectPtr) &fds, NULL, NULL, &to); } else { sts = select(width, (SelectPtr) &fds, NULL, NULL, NULL); } if (sts < 0) { perror("select"); fd = -1; goto error; } else if (sts == 0) { fprintf (stderr, "connection timed out\n"); fd = -1; goto error; } #else { double beforeSelect; double SVS_double_time(); int tty = isatty(0); beforeSelect = SVS_double_time(); do { FD_ZERO(&fds); FD_SET(sock, &fds); to.tv_sec = 0; to.tv_usec = 0; sts = select(width, (SelectPtr) &fds, NULL, NULL, &to); if (sts < 0) { perror("select"); fd = -1; goto error; } } while (sts == 0 && (tty || SVS_double_time() - beforeSelect < SOCK_ACCEPT_TIMEOUT)); if (sts == 0) { fprintf (stderr, "connection timed out\n"); fd = -1; goto error; } } #endif #if DXD_SOCKET_UNIXDOMAIN_OK if (FD_ISSET(sock, &fds)) { #endif if ((fd = accept(sock, (struct sockaddr *)&server, &length)) < 0) { perror ("accept"); fd = -1; goto error; } #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(fd); #endif #if DXD_SOCKET_UNIXDOMAIN_OK } else { if ((fd = accept(usock, (struct sockaddr *)&userver, &length)) < 0) { perror ("accept"); fd = -1; goto error; } #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(fd); #endif } #endif printf ("server: accepted connection from client\n"); error: #if DXD_SOCKET_UNIXDOMAIN_OK if (userver.sun_path[0] != '\0') unlink (userver.sun_path); if (usock >= 0) close (usock); #endif if (sock >= 0) close (sock); return (fd); } /* * Initiate a connection to a server. */ static init_client(char *host, int pport) { int sock; struct sockaddr_in server; #if DXD_SOCKET_UNIXDOMAIN_OK struct sockaddr_un userver; #endif struct hostent *hp; int length; #if DXD_HAS_GETHOSTBYNAME struct hostent *gethostbyname(); #endif u_short port = pport; #if DXD_SOCKET_UNIXDOMAIN_OK if (strcmp(host, "unix") == 0) { memset((char *)&userver, 0, sizeof(userver)); userver.sun_family = AF_INET; sprintf(userver.sun_path, "/tmp/.DX-unix/DX%d", port); length = sizeof (userver) - sizeof(userver.sun_path) + strlen (userver.sun_path); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) return(-1); if (connect(sock, (struct sockaddr *) &userver, length) < 0) { perror("connect"); close(sock); return(-1); } #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(sock); #endif } else #endif { memset((char *)&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(port); /* get host address */ if (isdigit(host[0])) server.sin_addr.s_addr = inet_addr(host); else { hp = gethostbyname(host); if (hp == NULL) return(-1); memcpy(&server.sin_addr, hp->h_addr, hp->h_length); } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return(-1); if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) { close(sock); return(-1); } #if defined(DXD_HAS_IBM_OS2_SOCKETS) || defined(DXD_HAS_WINSOCKETS) SOCK_SETSOCKET(sock); #endif } printf ("client: connected to server\n"); return(sock); } #ifdef TEST main(int argc, char *argv[]) { int fd; char buffer[1000]; if (argc < 3) { fd = _dxf_ExInitServer(1959); write(fd, "good bye\n", 9); buffer[read(fd, buffer, 1000)] = '\0'; fprintf(stdout, buffer); close (fd); } else { fd = init_client(argv[1], atol(argv[2])); buffer[read(fd, buffer, 1000)] = '\0'; fprintf(stdout, buffer); printf("> "); gets(buffer); write(fd, "hello\n", 6); close (fd); } } #endif