home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume27
/
distributed-c-2.1
/
part17
< prev
next >
Wrap
Text File
|
1993-12-22
|
64KB
|
1,740 lines
Newsgroups: comp.sources.unix
From: pleierc@informatik.tu-muenchen.de (Christoph Pleier)
Subject: v27i191: distributed-c-2.1 - Distributed C Development Environment, V2.1, Part17/18
References: <1.756634932.28500@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: pleierc@informatik.tu-muenchen.de (Christoph Pleier)
Posting-Number: Volume 27, Issue 191
Archive-Name: distributed-c-2.1/part17
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 17 (of 18)."
# Contents: lib/ipc_socket.c
# Wrapped by vixie@gw.home.vix.com on Thu Dec 23 00:12:07 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'lib/ipc_socket.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'lib/ipc_socket.c'\"
else
echo shar: Extracting \"'lib/ipc_socket.c'\" \(60451 characters\)
sed "s/^X//" >'lib/ipc_socket.c' <<'END_OF_FILE'
X/***************************************************************************
X * *
X * @@@@ @@@ @@@@@ @@@@@ @@@@@ @@@ @@@@ @ @ @@@@@ @@@@@ @@@@ @@@ *
X * @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ *
X * @ @ @ @@@@@ @ @@@@@ @ @@@@@ @ @ @ @@@@@ @ @ @ *
X * @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ *
X * @@@@ @@@ @@@@@ @ @ @ @@@ @@@@ @@@@@ @ @@@@@ @@@@ @@@ *
X * *
X * A compiler for distributed programming with C *
X * *
X * i p c _ s o c k e t . c *
X * *
X * Package : Runtime Library *
X * Version : 1.1 *
X * CreationDate : 10.07.90 *
X * LastUpDate : 06.12.93 *
X * *
X * This file contains the hardware dependent routines building the message *
X * passing layer based on stream sockets for use on operating system BSD *
X * Unix Version 4.3 or other compatible operating systems like Sun Os 4.1, *
X * ConvexOs, HP-UX, UNICOS, AIX or Ultrix. *
X * *
X * Copyright (C) 1990-1994 by Christoph Pleier *
X * All rights reserved! *
X ***************************************************************************/
X
X/*
X * This file is part of the Distributed C Development Environment (DCDE).
X * DCDE is free software; you can redistribute it and/or modify
X * it under the terms written in the README-file.
X * DCDE is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
X * See the file README for more details.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#ifdef UNICOS
X# include <sys/param.h>
X#endif
X#include <sys/time.h>
X#include <netinet/in.h>
X#ifdef HPUX
X# include <codelibs/nap.h>
X#endif
X#ifdef AIX
X# include <sys/select.h>
X# include <isode/isoaddrs.h>
X# include <isode/manifest.h>
X#endif
X#include <netdb.h>
X#include <signal.h>
X#include <errno.h>
X#include "ipc_socket.h"
X#include "run_Errno.h"
X
X#define DEBUG_IPC /**/
X
X/* To avoid that processes whose connection attempt is refused several times
X * (e.g. if the called process tries itself to connect to the calling process)
X * let grow the load of the computer nodes because of the busy waiting
X * character, we raise each time a connection attempt is refused the delay
X * until the connecting process is allowed to retry the attempt.
X * The delay starts at MCON_RETRY_DELAY_MIN and is raised in steps of
X * MCON_RETRY_DELAY_STEP until MCON_RETRY_DELAY_MAX. After the connection
X * attempt succeeded or the operation is timed out the delay is reset to the
X * minimal value.
X *
X * Note: the values specify different unities on different machines!
X */
X#ifdef SPARC
X /* the values specify microseconds */
X# define MCON_RETRY_DELAY_MIN 5000
X# define MCON_RETRY_DELAY_MAX 100000
X# define MCON_RETRY_DELAY_STEP 5000
X#else
X# ifdef HPUX
X /* the values specify milliseconds */
X# define MCON_RETRY_DELAY_MIN 10
X# define MCON_RETRY_DELAY_MAX 1000
X# define MCON_RETRY_DELAY_STEP 50
X# else
X /* the values specify seconds */
X# define MCON_RETRY_DELAY_MIN 0
X# define MCON_RETRY_DELAY_MAX 5
X# define MCON_RETRY_DELAY_STEP 1
X# endif /* HPUX /**/
X#endif /* SPARC /**/
X
X#ifdef SYSTEM_V
X# define bzero(s, n) memset((char *)(s), 0, (n))
X# define bcopy(src, dst, num) memcpy((dst), (src), (num))
X#endif /* SYSTEM_V /**/
X
X/* this variable is used to store the actual retry delay */
Xint mcon_retry_delay = MCON_RETRY_DELAY_MIN;
X
X/* the array _con_socks is used to store all established TCP/IP connections. */
Xint _con_num = 0;
Xstruct _con *_con_socks_first = NULL, *_con_socks_last = NULL;
X/* struct _con _con_socks[FD_SETSIZE]; */
X
X/* the used external global variables */
Xextern int errno, /* system error code */
X Errno, /* function error code */
X _debugflush; /* flush debug messages or not */
Xextern char *sys_errlist[], /* system error messages */
X *_programname, /* name of program */
X *_processname, /* name of process */
X _processprefix[]; /* process specifying string */
Xextern FILE *_debugout; /* where to write the debug messages */
Xextern PORTDESCR _own_port; /* own port */
X
X#ifdef DEBUG_IPC
X/* the flag to control the debug messages output */
Xint _debug_ipc = 0;
X#endif /* DEBUG_IPC /**/
X
X/* the timeout flag */
Xstatic int timeout;
X
X/* caught signal SIGPIPE or not */
Xstatic int sigpipe;
X
X/* set timer, if time equals 0 clear timer */
X#ifdef BSD
X# define SETTIMER(time) timeout = FALSE; \
X { \
X struct sigvec vec; \
X \
X vec.sv_handler = timeout_proc; \
X vec.sv_mask = SIGALRM; \
X vec.sv_flags = SV_INTERRUPT; \
X sigvec(SIGALRM,&vec,(struct sigvec *) NULL);\
X } \
X (void) alarm(time);
X# define CATCHSIGPIPE sigpipe = FALSE; \
X { \
X struct sigvec vec; \
X \
X vec.sv_handler = catch_SIGPIPE; \
X vec.sv_mask = SIGPIPE; \
X vec.sv_flags = SV_INTERRUPT; \
X sigvec(SIGPIPE,&vec,(struct sigvec *) NULL);\
X }
X#else /* SYSTEM_V */
X# define SETTIMER(time) timeout = FALSE; \
X signal(SIGALRM, timeout_proc);\
X (void) alarm(time);
X# define CATCHSIGPIPE sigpipe = FALSE; \
X signal(SIGPIPE, catch_SIGPIPE);
X#endif /* BSD /**/
X
X/* if timeout is set, return ERROR */
X#define RETURN_IF_TIMEOUT if (timeout) { \
X Errno = ETIMEOUT; \
X return(ERROR); \
X }
X
X#ifdef DEBUG_IPC
X# define DEBUGPUTS(msg) if (_debug_ipc) { \
X fprintf(_debugout, "[ipc] %s %s\n", \
X _processprefix, msg); \
X if (_debugflush) \
X fflush(_debugout); \
X }
X#else
X# define DEBUGPUTS(msg) { /* nothing */ }
X#endif
X
X/* The parameter types for the select() system call are different
X * on HPUX systems. We handle this problem by a special cast macro.
X */
X#ifdef HPUX
X#define SELECT_CAST (int *)
X#else
X#define SELECT_CAST (fd_set *)
X#endif
X
X/******************************************************************************
X * print_system_error() *
X * *
X * Writes a message of the last error consisting of a the appropriate system *
X * error string and the appropriate error name to the file specified by 'fd'. *
X * *
X * Return values: none! *
X ******************************************************************************/
Xstatic int
Xprint_system_error(fd)
XFILE *fd;
X{
X register char *tmpptr;
X
X switch(errno) {
X case EADDRINUSE:
X tmpptr = "EADDRINUSE";
X break;
X case EADDRNOTAVAIL:
X tmpptr = "EADDRNOTAVAIL";
X break;
X case EAFNOSUPPORT:
X tmpptr = "EAFNOSUPPORT";
X break;
X case EALREADY:
X tmpptr = "EALREADY";
X break;
X case EBADF:
X tmpptr = "EBADF";
X break;
X case ECONNREFUSED:
X tmpptr = "ECONNREFUSED";
X break;
X case EFAULT:
X tmpptr = "EFAULT";
X break;
X case EINPROGRESS:
X tmpptr = "EINPROGRESS";
X break;
X case EINTR:
X tmpptr = "EINTR";
X break;
X case EINVAL:
X tmpptr = "EINVAL";
X break;
X case EISCONN:
X tmpptr = "EISCONN";
X break;
X case EMSGSIZE:
X tmpptr = "EMSGSIZE";
X break;
X case ENETUNREACH:
X tmpptr = "ENETUNREACH";
X break;
X case ENOBUFS:
X tmpptr = "ENOBUFS";
X break;
X case ENOTSOCK:
X tmpptr = "ENOTSOCK";
X break;
X case EOPNOTSUPP:
X tmpptr = "EOPNOTSUPP";
X break;
X case ETIMEDOUT:
X tmpptr = "ETIMEDOUT";
X break;
X case EWOULDBLOCK:
X tmpptr = "EWOULDBLOCK";
X break;
X default:
X tmpptr = NULL;
X } /* switch */
X if (tmpptr)
X fprintf(fd, "Reason: %s (%s)\n", sys_errlist[errno], tmpptr);
X else
X fprintf(fd, "Reason: %s\n", sys_errlist[errno]);
X fflush(fd);
X} /* print_system_error */
X
X/******************************************************************************
X * ipc_error() *
X * *
X * Writes a error message indicating the last error occured in the communica- *
X * tion primitives to stderr. *
X * *
X * Return values: none! *
X ******************************************************************************/
Xstatic int
Xipc_error(msg)
Xchar *msg;
X{
X fprintf(stderr, "***** ERROR IN COMMUNICATION PRIMITIVES *****\n");
X fprintf(stderr, "PROGRAM: %s, PROCESS: %s, HOST: %s, PID: %d\n",
X _programname, _processname, _own_port.hostname, getpid());
X fprintf(stderr, "Error: %s\n", msg);
X if (errno != 0)
X print_system_error(stderr);
X fflush(stderr);
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "***** ERROR IN COMMUNICATION PRIMITIVES *****\n");
X fprintf(_debugout, "PROGRAM: %s, PROCESS: %s, HOST: %s, PID: %d\n",
X _programname, _processname, _own_port.hostname, getpid());
X fprintf(_debugout, "Error: %s\n", msg);
X if (errno != 0)
X print_system_error(_debugout);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X} /* ipc_error */
X
X/******************************************************************************
X * ipc_fatal_error() *
X * *
X * Writes a error message indicating the last error occured in the communica- *
X * tion primitives to stderr and forces the termination of the program with *
X * a core dump. *
X * *
X * Return values: this function returns never! *
X ******************************************************************************/
Xstatic int
Xipc_fatal_error(loc, msg)
Xchar *loc, *msg;
X{
X fprintf(stderr, "***** FATAL ERROR IN COMMUNICATION PRIMITIVES *****\n");
X fprintf(stderr, "PROGRAM: %s, PROCESS: %s, HOST: %s, PID: %d\n",
X _programname, _processname, _own_port.hostname, getpid());
X fprintf(stderr, "Function: %s Error: %s\n", loc, msg);
X if (errno != 0)
X print_system_error(stderr);
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "***** FATAL ERROR IN COMMUNICATION PRIMITIVES *****\n");
X fprintf(_debugout, "PROGRAM: %s, PROCESS: %s, HOST: %s, PID: %d\n",
X _programname, _processname, _own_port.hostname, getpid());
X fprintf(_debugout, "Function: %s Error: %s\n", loc, msg);
X if (errno != 0)
X print_system_error(_debugout);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X signal(SIGIOT, SIG_DFL);
X abort();
X} /* ipc_fatal_error */
X
X/******************************************************************************
X * display_connection_list() *
X * *
X * Displays the list of established TCP/IP connections. **
X * *
X * Return values: none! *
X ******************************************************************************/
Xstatic int
Xdisplay_connection_list()
X{
X int i;
X register struct _con *_con_socks;
X
X#ifdef DEBUG_IPC
X if (!_debug_ipc)
X return;
X fprintf(_debugout, "[ipc] %s connection list:\n", _processprefix);
X for(_con_socks = _con_socks_first, i = 0; _con_socks; _con_socks = _con_socks->next, i++) {
X fprintf(_debugout, "[ipc] %s entry %d:\n", _processprefix, i);
X fprintf(_debugout, "[ipc] %s con_sock = %d\n",
X _processprefix, _con_socks->con_sock);
X fprintf(_debugout, "[ipc] %s port1:\n", _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, _con_socks->own_port.portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, _con_socks->own_port.hostname);
X fprintf(_debugout, "[ipc] %s port2:\n", _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, _con_socks->other_port.portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, _con_socks->other_port.hostname);
X } /* for */
X#endif /* DEBUG_IPC /**/
X} /* display_connection_list */
X
X/******************************************************************************
X * store_connection_in_list() *
X * *
X * Stores the connection specified by the socket 'con_sock' in the list of *
X * established TCP/IP connections. *
X * *
X * Return values: OK upon success / ERROR upon error *
X ******************************************************************************/
Xstatic int
Xstore_connection_in_list(con_sock, own_port, other_port)
Xint con_sock;
XPORTDESCR own_port, other_port;
X{
X register struct _con *ptr;
X#ifdef CONVEX
X int close_connections();
X#else
X static int close_connections();
X#endif
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s storing connection in list:\n", _processprefix);
X fflush(_debugout);
X fprintf(_debugout, "[ipc] %s con_sock = %d\n",
X _processprefix, con_sock);
X fprintf(_debugout, "[ipc] %s port1:\n", _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, own_port.portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, own_port.hostname);
X fprintf(_debugout, "[ipc] %s port2:\n", _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, other_port.portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, other_port.hostname);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X if (!(ptr = (struct _con *) malloc(sizeof(struct _con))))
X ipc_fatal_error("store_connection_in_list", "out of heap space");
X ptr->con_sock = con_sock;
X ptr->own_port = own_port;
X ptr->other_port = other_port;
X ptr->next = NULL;
X if (!_con_socks_first)
X _con_socks_first = _con_socks_last = ptr;
X else {
X _con_socks_last->next = ptr;
X _con_socks_last = ptr;
X }
X /* check if too many connections are open */
X if (++_con_num > MAXOPENCONS)
X close_connections(con_sock);
X return(OK);
X} /* store_connection_in_list */
X
X/******************************************************************************
X * delete_connection_from_list() *
X * *
X * Deletes the connection specified by the socket 'con_sock' from the list of *
X * established TCP/IP connections. *
X * *
X * Return values: OK upon success *
X ******************************************************************************/
Xstatic int
Xdelete_connection_from_list(con_sock)
Xint con_sock;
X{
X register struct _con *_con_socks, *last;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s deleting connection:\n",
X _processprefix);
X fprintf(_debugout, "[ipc] %s con_sock = %d\n",
X _processprefix, _con_socks->con_sock);
X fprintf(_debugout, "[ipc] %s port1:\n", _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, _con_socks->own_port.portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, _con_socks->own_port.hostname);
X fprintf(_debugout, "[ipc] %s port2:\n", _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, _con_socks->other_port.portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, _con_socks->other_port.hostname);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X last = NULL;
X for(_con_socks = _con_socks_first; _con_socks; _con_socks = _con_socks->next) {
X if (_con_socks->con_sock == con_sock) {
X if (!last) {
X _con_socks_first = _con_socks->next;
X free(_con_socks);
X } else {
X last->next = _con_socks->next;
X free(_con_socks);
X }
X _con_num--;
X return(OK);
X }
X last = _con_socks;
X } /* for */
X ipc_fatal_error("delete_connection_from_list", "connection not found in list");
X} /* delete_connection_from_list */
X
X/******************************************************************************
X * close_connections() *
X * *
X * Closes CLOSECONNUM stored connections from the list of established TCP/IP *
X * connections except the connection specified by 'con_sock'. *
X * *
X * Return values: OK upon success *
X ******************************************************************************/
Xstatic int
Xclose_connections(con_sock)
Xint con_sock;
X{
X register struct _con *_con_socks, *next;
X int num, act_con_sock;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s closing %d connections\n",
X _processprefix, CLOSECONNUM);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X num = CLOSECONNUM;
X _con_socks = _con_socks_first;
X while(_con_socks && num) {
X act_con_sock = _con_socks->con_sock;
X next = _con_socks->next;
X if (_con_socks->con_sock != con_sock) {
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s deleting and closing socket %d\n",
X _processprefix, act_con_sock);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X (void) close(act_con_sock);
X delete_connection_from_list(act_con_sock);
X num--;
X }
X _con_socks = next;
X } /* while */
X DEBUGPUTS("connections closed");
X display_connection_list();
X return(OK);
X} /* close_connections */
X
X/******************************************************************************
X * timeout_proc() *
X * *
X * Sets the timeout flag 'timeout' to indicate a timeout error. *
X * *
X * Return values: none! *
X ******************************************************************************/
X#ifdef UNICOS
Xstatic void
Xtimeout_proc(sig)
Xint sig;
X#else
Xstatic void
Xtimeout_proc(sig, code, scp)
Xint sig, code;
Xstruct sigcontext *scp;
X#endif
X{
X DEBUGPUTS("***** timeout_proc():");
X timeout = TRUE;
X#ifdef HPUX
X scp->sc_syscall_action = SIG_RETURN; /* abort interrupted system call! */
X#endif
X} /* timeout_proc */
X
X/******************************************************************************
X * catch_SIGPIPE() *
X * *
X * Catches the signal SIGPIPE and stores TRUE in 'sigpipe'. *
X * *
X * Return values: none! *
X ******************************************************************************/
X#ifdef UNICOS
Xstatic void
Xcatch_SIGPIPE(sig)
Xint sig;
X#else
Xstatic void
Xcatch_SIGPIPE(sig, code, scp)
Xint sig, code;
Xstruct sigcontext *scp;
X#endif
X{
X DEBUGPUTS("***** catch_SIGPIPE():");
Xputs("SIGPIPE"); fflush(stdout);
X sigpipe = TRUE;
X#ifdef HPUX
X scp->sc_syscall_action = SIG_RETURN; /* abort interrupted system call! */
X#endif
X} /* catch_SIGPIPE */
X
X/******************************************************************************
X * _create_port() *
X * *
X * Creates a new communication endpoint. *
X * *
X * Return values: OK = success / ERROR = error *
X ******************************************************************************/
Xint
X_create_port(port)
XPORTDESCR *port;
X{
X int sock,
X res;
X u_short portnum;
X struct sockaddr_in so_addr;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _create_port():\n", _processprefix);
X fprintf(_debugout, "[ipc] %s &port = %d\n", _processprefix, port);
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = ECREATEPORT;
X /* create a TCP socket */
X if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X ipc_error("system call: socket()");
X return(ERROR);
X }
X /* initialize components of internet address */
X bzero(&so_addr, sizeof(so_addr));
X so_addr.sin_family = AF_INET;
X so_addr.sin_addr.s_addr = htonl(INADDR_ANY);
X /* bind socket to an unused address (port number) */
X for (portnum = STARTPORT; portnum <= ENDPORT; portnum++) {
X#ifdef DEBUG_IPC
X if (_debug_ipc)
X fprintf(_debugout,"[ipc] %s trying to bind socket to portnum %d\n",
X _processprefix, htons(portnum));
X#endif /* DEBUG_IPC /**/
X so_addr.sin_port = portnum;
X if (!(res = bind(sock, (struct sockaddr *) &so_addr, sizeof(so_addr)))){
X if (listen(sock, 1)) {
X ipc_error("system call: listen()");
X return(ERROR);
X }
X /*
X * Initialize port and return
X */
X bzero((char *) port, sizeof(PORTDESCR));
X port->state = CONNECTIONLESS;
X port->acc_sock = sock;
X port->portnum = portnum;
X if (gethostname(port->hostname, MAXHOSTNAMELEN)) {
X ipc_error("gethostname()");
X return(ERROR);
X }
X port->con_sock = 0;
X DEBUGPUTS("port successfully created");
X /* clear Errno and return */
X Errno = OK;
X return(OK);
X }
X if ((res < 0) && (errno == EACCES)) {
X ipc_error("can't access socket");
X return (ERROR);
X }
X if (portnum > ENDPORT)
X portnum = STARTPORT;
X } /* for */
X ipc_fatal_error("_create_port()", "no portnum found");
X} /* _create_port */
X
X/******************************************************************************
X * _delete_port() *
X * *
X * Deletes the communication endpoint specified by 'port'. *
X * *
X * Return values: OK = success / ERROR = error *
X ******************************************************************************/
Xint
X_delete_port(port)
XPORTDESCR *port;
X{
X register struct _con *_con_socks;
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _delete_port():\n", _processprefix);
X _display_port_info("[ipc]", "port", *port);
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = EDELETEPORT;
X /* check port state */
X if (port->state != CONNECTIONLESS)
X ipc_fatal_error("_delete_port()", "port state is not CONNECTIONLESS");
X /* close connection if there's any */
X if (port->con_sock)
X (void) close(port->con_sock);
X /* close socket */
X if (close(port->acc_sock)) {
X ipc_error("system call: close()");
X return(ERROR);
X }
X /* shut down all open connections */
X for(_con_socks = _con_socks_first; _con_socks; _con_socks = _con_socks->next) {
X (void) close(_con_socks->con_sock);
X }
X /* clear Errno and return */
X Errno = OK;
X return(OK);
X} /* _delete_port */
X
X/******************************************************************************
X * _accept_connection() *
X * *
X * Communication endpoint 'port' waits 'time' real time seconds for a *
X * connection request (if 'time' equals 0 then the operation is unlimited). *
X * *
X * Return values: OK = success / ERROR = error *
X ******************************************************************************/
Xint
X_accept_connection(con_port, port, time)
XCONNECTIONDESCR *con_port;
XPORTDESCR *port;
Xunsigned time;
X{
X static int i,
X num,
X con_sock,
X con_addr_len,
X connector_portnum,
X newconnection,
X setsoptarg;
X char connector_hostname[MAXHOSTNAMELEN],
X address[MAXHOSTNAMELEN+20],
X buffer[CON_MSGLEN+5];
X PORTDESCR other_port;
X register struct _con *_con_socks;
X struct timeval timevalarg;
X static fd_set readfds;
X static struct sockaddr_in con_addr;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _accept_connection():\n",
X _processprefix);
X fprintf(_debugout, "[ipc] %s &con_port = %d\n", _processprefix,
X con_port);
X _display_port_info("[ipc]", "port", *port);
X fprintf(_debugout, "[ipc] %s time = %d\n", _processprefix, time);
Xdisplay_connection_list();
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = EACPTCON;
X /* set timer, if time equals 0 clear timer */
X SETTIMER(time);
X while(!timeout) {
X /* check port state */
X if (port->state != CONNECTIONLESS)
X ipc_fatal_error("_accept_connection()", "port state is not CONNECTIONLESS");
X DEBUGPUTS("state: CONNECTIONLESS");
Xdisplay_connection_list();
X /* initialize readfds */
X FD_ZERO(&readfds);
X FD_SET(port->acc_sock, &readfds);
X for(_con_socks = _con_socks_first; _con_socks; _con_socks = _con_socks->next) {
X FD_SET(_con_socks->con_sock, &readfds);
X }
X /* First we wait until one or more process(es) want(s) to connect to us
X * (connect() to port->acc_sock) or one or more process(es) want(s) to
X * send some data to us using an existing connection.
X */
X port->state = SELECTING;
X DEBUGPUTS("state: SELECTING");
X if (select(FD_SETSIZE, SELECT_CAST &readfds, SELECT_CAST NULL, SELECT_CAST NULL,
X (struct timeval *) NULL) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X switch(errno) {
X case EBADF:
X case EFAULT:
X /* remove connections that have been closed */
X timevalarg.tv_sec = 0;
X timevalarg.tv_usec = 1;
X for(_con_socks = _con_socks_first; _con_socks; _con_socks = _con_socks->next) {
X FD_ZERO(&readfds);
X FD_SET(_con_socks->con_sock, &readfds);
X if (select(FD_SETSIZE, SELECT_CAST &readfds, SELECT_CAST NULL, SELECT_CAST NULL,
X &timevalarg) < 0) {
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s closed connection found! socket is %d\n",
X _processprefix, _con_socks->con_sock);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X delete_connection_from_list(_con_socks->con_sock);
X }
X } /* for */
X break;
X default:
X ipc_error("system call: select()");
X return(ERROR);
X } /* switch */
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X (void) close(con_sock);
X continue;
X }
X /* Upon completion of select(), we look first if one or more process
X * want(s) to establish a new connection (CASE 1) (Note: new connections
X * are prefered!) Otherwise we choose one of the process(es) that
X * want(s) to send data to us (CASE 2)!
X */
X /* clear connection descriptor */
X con_sock = 0;
X /* clear new connection flag */
X newconnection = 0;
X /* set connection descriptor */
X if (FD_ISSET(port->acc_sock, &readfds)) {
X /* CASE 1: accept a new connection */
X port->state = ACCEPTING;
X DEBUGPUTS("state: ACCEPTING");
X con_addr_len = sizeof(con_addr);
X if ((con_sock = accept(port->acc_sock, (struct sockaddr *) &con_addr,
X &con_addr_len)) < 0) {
X switch(errno) {
X case EMFILE:
X /* ipc_fatal_error("accept()", "too many open connections or files"); */
X fprintf(stderr, "%s too many connections open\n", _processprefix);
X fprintf(stderr, "%s closing %d connections\n", _processprefix, CLOSECONNUM);
X fflush(stderr);
X close_connections(0);
X fprintf(stderr, "%s sleeping 15 seconds to get connections closed\n", _processprefix);
X fflush(stderr);
X sleep(15);
X fprintf(stderr, "%s ok - trying again\n", _processprefix);
X fflush(stderr);
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer");
X break;
X default:
X ipc_error("system call: accept()");
X return(ERROR);
X } /* switch */
X DEBUGPUTS("trying again");
X (void) close(con_sock);
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X newconnection = 1;
X } else {
X /* CASE 2: reuse old, already existing connection */
X for(_con_socks = _con_socks_first; _con_socks; _con_socks = _con_socks->next) {
X if (FD_ISSET(_con_socks->con_sock, &readfds)) {
X DEBUGPUTS("reusing old connection");
X con_sock = _con_socks->con_sock;
X break;
X }
X }
X }
X /* If con_port equals zero at this point, select() returned indicating
X * an ending connection. Unfortunately we don't know which connection
X * it was! So we can't delete it from the list at this point.
X */
X if (!con_sock) {
X DEBUGPUTS("a connection was closed (1)");
X DEBUGPUTS("trying again");
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X /* Well! We have a correct connection, specified by con_sock.
X * A request message of length zero indicates again the ending of
X * a connection. We consider this aspect.
X * Now let's look for a correct request message.
X */
X port->state = RECV_REQ;
X DEBUGPUTS("state: RECV_REQ");
X if ((num = read(con_sock, buffer, CON_MSGLEN + 5)) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X switch(errno) {
X case EBADF:
X DEBUGPUTS("bad file number, trying again");
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer, trying again");
X break;
X default:
X ipc_error("system call: read() - 1");
X return(ERROR);
X } /* switch */
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X (void) close(con_sock);
X continue;
X }
X if (num == 0) {
X DEBUGPUTS("a connection was closed (2)");
X DEBUGPUTS("trying again");
X (void) close(con_sock);
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num != CON_MSGLEN || strcmp(buffer, CON_REQUEST)) {
X DEBUGPUTS("bad request message received");
X DEBUGPUTS("trying again");
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X /* The request message was o.k. as well. Therefore we send back
X * the reply message.
X */
X port->state = SEND_REP;
X DEBUGPUTS("state: SEND_REP");
X CATCHSIGPIPE;
X if ((num = write(con_sock, CON_ACCEPTED, CON_MSGLEN)) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X if (sigpipe) {
X /* connection was closed by foreign host */
X errno = EPIPE;
X sigpipe = FALSE;
X }
X switch(errno) {
X case EBADF:
X DEBUGPUTS("bad file number, trying again");
X break;
X case EPIPE:
X DEBUGPUTS("broken pipe, trying again");
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer, trying again");
X break;
X default:
X ipc_error("system call: write() - 1");
X return(ERROR);
X } /* switch */
X (void) close(con_sock);
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num != CON_MSGLEN) {
X errno = 0;
X ipc_error("sending reply message");
X return(ERROR);
X }
X /* After correct handshaking of request and reply, we receive
X * the address of the process connecting to us.
X * We also check if the TCP/IP connection was ending!
X */
X port->state = RECV_ADDR;
X DEBUGPUTS("state: RECV_ADDR");
X if ((num = read(con_sock, address, sizeof(address))) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X switch(errno) {
X case EBADF:
X DEBUGPUTS("bad file number, trying again");
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer, trying again");
X break;
X default:
X ipc_error("system call: read() - 2");
X return(ERROR);
X } /* switch */
X (void) close(con_sock);
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num == 0) {
X DEBUGPUTS("connection was closed");
X if (!newconnection)
X delete_connection_from_list(con_sock);
X DEBUGPUTS("trying again");
X (void) close(con_sock);
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num != sizeof(address)) {
X DEBUGPUTS("bad address received");
X DEBUGPUTS("trying again");
X (void) close(con_sock);
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X sscanf(address, "%d|%s", &connector_portnum, connector_hostname);
X /* Connection establishment completed!
X * Initialize variables and return to calling program.
X */
X port->state = CONNECTED;
X DEBUGPUTS("state: CONNECTED");
X /* Initialize connection port */
X con_port->state = CONNECTED;
X con_port->con_sock = con_sock;
X con_port->own_port = port;
X con_port->other_port = NULL;
X /* If we have accepted a new TCP/IP connection, we store it
X * in the connection list.
X */
X if (newconnection) {
X other_port.state = -1;
X other_port.acc_sock = -1;;
X other_port.con_sock = -1;;
X other_port.portnum = connector_portnum;
X strcpy(other_port.hostname, connector_hostname);
X store_connection_in_list(con_sock, *port, other_port);
X }
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s address of connector:\n",
X _processprefix);
X fprintf(_debugout, "[ipc] %s portnum = %d\n",
X _processprefix, connector_portnum);
X fprintf(_debugout, "[ipc] %s hostname = %s\n",
X _processprefix, connector_hostname);
X display_connection_list();
X }
X#endif /* DEBUG_IPC /**/
X /* check periodically if connection is still alive */
X setsoptarg = 1;
X if (setsockopt(con_sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &setsoptarg, sizeof(int)) < 0) {
X ipc_error("system_call: setsockopt(SO_KEEPALIVE)");
X return(ERROR);
X }
X /* clear timer and return */
X (void) alarm(0);
X DEBUGPUTS("connection accepted");
X Errno = OK;
X return(OK);
X } /* while */
X DEBUGPUTS("TIMEOUT");
X port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X Errno = ETIMEOUT;
X return(ERROR);
X} /* _accept_connection */
X
X/******************************************************************************
X * _make_connection() *
X * *
X * Communication enpoint 'port1' tries 'time' real time seconds to connect *
X * to 'port2' (if 'time' equals 0 then the operation is unlimited). *
X * *
X * Return values: OK = success / ERROR = error *
X ******************************************************************************/
Xint
X_make_connection(con_port, port1, port2, time)
XCONNECTIONDESCR *con_port;
XPORTDESCR *port1;
XPORTDESCR *port2;
Xunsigned time;
X{
X int i,
X num,
X con_sock,
X con_addr_len,
X setsoptarg;
X char buffer[CON_MSGLEN+5],
X address[MAXHOSTNAMELEN+20];
X static struct sockaddr_in con_addr;
X static struct hostent *hostinfo;
X register struct _con *_con_socks;
X struct timeval timevalarg;
X static fd_set writefds;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _make_connection():\n",
X _processprefix);
X fprintf(_debugout, "[ipc] %s &con_port = %d\n", _processprefix,
X con_port);
X _display_port_info("[ipc]", "port1", *port1);
X _display_port_info("[ipc]", "port2", *port2);
X fprintf(_debugout, "[ipc] %s time = %d\n", _processprefix, time);
Xdisplay_connection_list();
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = EMAKECON;
X /* set timer, if time equals 0 clear timer */
X SETTIMER(time);
X while(!timeout) {
X /* check port state */
X if (port1->state != CONNECTIONLESS)
X ipc_fatal_error("_make_connection()", "port state is not CONNECTIONLESS");
X /* clear connection descriptor */
X con_sock = 0;
X /* If there's already an existing TCP/IP connection we use it (CASE 1).
X * Otherwise we try to connect to the other port (CASE 2).
X */
X if (port2->con_sock) {
X /* CASE 1a: connection exists! */
X con_sock = port2->con_sock;
X } else {
X /* look if connection was already accepted! */
X DEBUGPUTS("searching in connection list");
X for(_con_socks = _con_socks_first; _con_socks; _con_socks = _con_socks->next) {
X if (port2->portnum == _con_socks->other_port.portnum
X && !strcmp(port2->hostname, _con_socks->other_port.hostname)) {
X /* CASE 1b: connection exists! */
X DEBUGPUTS("using old connection");
X con_sock = _con_socks->con_sock;
X /* check if connection is still alive! */
X FD_ZERO(&writefds);
X FD_SET(con_sock, &writefds);
X if (select(FD_SETSIZE, SELECT_CAST NULL, SELECT_CAST &writefds,
X SELECT_CAST NULL, &timevalarg) < 0) {
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s closed connection found! socket is %d\n",
X _processprefix, _con_socks->con_sock);
X if (_debugflush)
X fflush(_debugout);
X#endif /* DEBUG_IPC /**/
X delete_connection_from_list(_con_socks->con_sock);
X con_sock = 0;
X }
X }
X break;
X }
X } /* for */
X /* If con_sock equals zero, there was no connection found in
X * the array storing established TCP/IP connections.
X * Because of that, we establish a new connection
X */
X if (con_sock == 0) {
X /* CASE 2: establish a new TCP/IP connection! */
X port1->state = CONNECTING;
X DEBUGPUTS("state: CONNECTING");
X /* create a new TCP socket
X * NOTE: a new socket is used instead of port1
X */
X if ((con_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X ipc_error("system call: socket()");
X return(ERROR);
X }
X /* clear calling address */
X bzero(&con_addr, sizeof(con_addr));
X /* set address family of called host */
X con_addr.sin_family = AF_INET;
X /* get host information of called host */
X hostinfo = NULL;
X while(!timeout && !hostinfo)
X hostinfo = gethostbyname(port2->hostname);
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X fputs("timeout caused by gethostbyname()!\n", stderr);
X Errno = ETIMEOUT;
X return(ERROR);
X }
X /* set address of called host */
X bcopy(hostinfo->h_addr, &con_addr.sin_addr, hostinfo->h_length);
X /* set portnum of called host */
X con_addr.sin_port = port2->portnum;
X /* try to connect */
X if (connect(con_sock, (struct sockaddr *) &con_addr, sizeof(con_addr)) < 0){
X switch(errno) {
X case ETIMEDOUT:
X DEBUGPUTS("attempt timed out by system, trying again");
X break;
X case EISCONN:
X DEBUGPUTS("port is connected, trying again");
X break;
X case ECONNREFUSED:
X DEBUGPUTS("connection refused, trying again");
X break;
X default:
X ipc_error("system call: connect()");
X } /* switch */
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X (void) close(con_sock);
X continue;
X }
X /* TCP/IP connection established! Store connection information
X * in connection list.
X */
X store_connection_in_list(con_sock, *port1, *port2);
X#ifdef DEBUG_IPC
X if (_debug_ipc)
X display_connection_list();
X#endif /* DEBUG_IPC /**/
X }
X }
X /* At this point, con_sock specifies a network connection to the called
X * port. If the stored connection was closed at the other side we will
X * get an EBADF, EPIPE or ECONNRESET error or receive signal SIGPIPE.
X * In this case we delete the stored connection and try it again.
X * Now we send a request message.
X */
X port1->state = SEND_REQ;
X DEBUGPUTS("state: SEND_REQ");
X CATCHSIGPIPE;
X if ((num = write(con_sock, CON_REQUEST, CON_MSGLEN)) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X if (sigpipe) {
X /* connection was closed by foreign host */
X errno = EPIPE;
X sigpipe = FALSE;
X }
X switch(errno) {
X case EBADF:
X DEBUGPUTS("bad file number, trying again");
X break;
X case EPIPE:
X DEBUGPUTS("broken pipe, trying again");
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer, trying again");
X break;
X default:
X ipc_error("system call: write() - 2");
X return(ERROR);
X } /* switch */
X DEBUGPUTS("stored connection not longer valid");
X delete_connection_from_list(con_sock);
X (void) close(con_sock);
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num != CON_MSGLEN) {
X errno = 0;
X ipc_error("sending request");
X return(ERROR);
X }
X /* Well! The request message was successfully sent to the called
X * process. Now receive the reply message. We must also take care
X * if the connection is ending during our handshaking!
X */
X port1->state = RECV_REP;
X DEBUGPUTS("state: RECV_REP");
X if ((num = read(con_sock, buffer, CON_MSGLEN + 5)) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X switch(errno) {
X case EBADF:
X DEBUGPUTS("bad file number, trying again");
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer, trying again");
X break;
X default:
X ipc_error("system call: read() - 3");
X return(ERROR);
X } /* switch */
X DEBUGPUTS("stored connection not longer valid");
X delete_connection_from_list(con_sock);
X (void) close(con_sock);
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num == 0) {
X DEBUGPUTS("connection was closed");
X delete_connection_from_list(con_sock);
X DEBUGPUTS("trying again");
X (void) close(con_sock);
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X if (num != CON_MSGLEN) {
X DEBUGPUTS("bad reply message received");
X DEBUGPUTS("trying again");
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X /* After correct handshaking of request and reply, send the own
X * address to the called process, initialize the variables and
X * return to the calling program.
X */
X if (!strcmp(buffer, CON_ACCEPTED)) {
X port1->state = SEND_ADDR;
X DEBUGPUTS("state: SEND_ADDR");
X /* send address */
X sprintf(address, "%d|%s", port1->portnum, port1->hostname);
X CATCHSIGPIPE;
X if ((num = write(con_sock, address, sizeof(address))) < 0) {
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X continue;
X }
X if (sigpipe) {
X /* connection was closed by foreign host */
X errno = EPIPE;
X sigpipe = FALSE;
X }
X switch(errno) {
X case EBADF:
X DEBUGPUTS("bad file number, trying again");
X break;
X case EPIPE:
X DEBUGPUTS("broken pipe, trying again");
X break;
X case ECONNRESET:
X DEBUGPUTS("connection reset by peer, trying again");
X break;
X default:
X ipc_error("system call: write() - 3");
X return(ERROR);
X } /* switch */
X DEBUGPUTS("stored connection not longer valid");
X delete_connection_from_list(con_sock);
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X (void) close(con_sock);
X continue;
X }
X if (num != sizeof(address)) {
X errno = 0;
X ipc_error("sending adress");
X return(ERROR);
X }
X port1->state = CONNECTED;
X DEBUGPUTS("state: CONNECTED");
X /* Initialize connection port */
X con_port->state = CONNECTED;
X con_port->con_sock = con_sock;
X con_port->own_port = port1;
X con_port->other_port = port2;
X /* clear timer and return */
X (void) alarm(0);
X DEBUGPUTS("connection established!");
X mcon_retry_delay = MCON_RETRY_DELAY_MIN;
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s retry delay now %d\n",
X _processprefix, mcon_retry_delay);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X /* check periodically if connection is still alive */
X setsoptarg = 1;
X if (setsockopt(con_sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &setsoptarg,
X sizeof(int)) < 0) {
X ipc_error("system_call: setsockopt(SO_KEEPALIVE)");
X return(ERROR);
X }
X return(OK);
X } else {
X /* If two processes have already an established TCP/IP connection
X * and try to make a connection using _make_connection() at the
X * same time, each process receives as reply message the request
X * message of the other process! In this case we try it again!
X */
X DEBUGPUTS("wrong reply message");
X#ifdef SPARC
X usleep(mcon_retry_delay);
X#else
X# ifdef HPUX
X nap(mcon_retry_delay);
X# else
X sleep(mcon_retry_delay);
X# endif /* HPUX /**/
X#endif /* SPARC /**/
X if (mcon_retry_delay < MCON_RETRY_DELAY_MAX)
X mcon_retry_delay += MCON_RETRY_DELAY_STEP;
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s retry delay now %d\n",
X _processprefix, mcon_retry_delay);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X DEBUGPUTS("trying again");
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X continue;
X }
X } /* while */
X DEBUGPUTS("TIMEOUT");
X port1->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s retry delay now %d\n",
X _processprefix, mcon_retry_delay);
X if (_debugflush)
X fflush(_debugout);
X }
X#endif /* DEBUG_IPC /**/
X Errno = ETIMEOUT;
X return(ERROR);
X} /* _make_connection */
X
X/******************************************************************************
X * _close_connection() *
X * *
X * The connection associated to connection port 'con_port' is closed. *
X * *
X * Return values: OK = success / ERROR = error *
X ******************************************************************************/
Xint
X_close_connection(con_port)
XCONNECTIONDESCR *con_port;
X{
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _close_connection():\n",
X _processprefix);
X _display_connection_port_info("[ipc]", "con_port", *con_port);
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = ECLOSECON;
X /* check port state */
X if (con_port->state != CONNECTED)
X ipc_fatal_error("_close_connection()", "con_port state is not CONNECTED");
X con_port->own_port->state = CLOSING;
X DEBUGPUTS("state: CLOSING");
X con_port->own_port->state = CONNECTIONLESS;
X con_port->state = CONNECTIONLESS;
X DEBUGPUTS("state: CONNECTIONLESS");
X return(OK);
X} /* _close_connection */
X
X
X/******************************************************************************
X * *
X * 'number' bytes are received from connection port 'con_port' and stored *
X * into 'buffer'. 'time' is the maximum real time in seconds to wait for a *
X * message to arrive (if 'time' equals 0 the waiting is unlimited). *
X * *
X * Return values: number of received bytes upon success / ERROR = error *
X ******************************************************************************/
Xint
X_recv_data(con_port, buffer, number, time)
XCONNECTIONDESCR *con_port;
Xchar *buffer;
Xint number;
Xunsigned time;
X{
X int num, nleft, nread;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _recv_data():\n", _processprefix);
X _display_connection_port_info("[ipc]", "con_port", *con_port);
X fprintf(_debugout, "[ipc] %s buffer = %d, number = %d\n",
X _processprefix, buffer, number);
X fprintf(_debugout, "[ipc] %s time = %d\n", _processprefix, time);
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = ERECVDATA;
X /* check connection port state */
X if (con_port->state != CONNECTED)
X ipc_fatal_error("_recv_data()", "con_port state is not CONNECTED");
X /* check port state */
X if (con_port->own_port->state != CONNECTED)
X ipc_fatal_error("_recv_data()", "port state is not CONNECTED");
X /* set timer, if time equals 0 clear timer */
X SETTIMER(time);
X con_port->state = con_port->own_port->state = RECEIVING;
X DEBUGPUTS("state: RECEIVING");
X nleft = number;
X while(nleft > 0) {
X nread = read(con_port->con_sock, buffer, nleft);
X if (nread < 0) {
X /* ERROR! */
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X Errno = ETIMEOUT;
X } else
X ipc_error("system call: read() - 4");
X con_port->state = con_port->own_port->state = CONNECTED;
X DEBUGPUTS("state: CONNECTED");
X return(ERROR);
X } else if (nread == 0) {
X /* EOF! */
X break;
X }
X nleft -= nread;
X buffer += nread;
X } /* while */
X con_port->state = con_port->own_port->state = CONNECTED;
X DEBUGPUTS("state: CONNECTED");
X /* clear timer and return */
X (void) alarm(0);
X return(number - nleft);
X} /* _recv_data */
X
X/******************************************************************************
X * _send_data() *
X * *
X * 'number' bytes, stored in 'buffer', are send to connection port 'con_port'.*
X * 'time' is the maximum real time in seconds to retry sending upon error (if *
X * 'time' equals 0 the waiting is unlimited). *
X * *
X * Return values: number of sent bytes upon success / ERROR = error *
X ******************************************************************************/
Xint
X_send_data(con_port, buffer, number, time)
XCONNECTIONDESCR *con_port;
Xchar *buffer;
Xint number;
Xunsigned time;
X{
X int num, nleft, nwritten;
X
X#ifdef DEBUG_IPC
X if (_debug_ipc) {
X fprintf(_debugout, "[ipc] %s ***** _send_data():\n", _processprefix);
X _display_connection_port_info("[ipc]", "con_port", *con_port);
X fprintf(_debugout, "[ipc] %s buffer = %d, number = %d\n",
X _processprefix, buffer, number);
X fprintf(_debugout, "[ipc] %s time = %d\n", _processprefix, time);
X }
X#endif /* DEBUG_IPC /**/
X /* set Errno */
X Errno = ESENDDATA;
X /* check connection port state */
X if (con_port->state != CONNECTED)
X ipc_fatal_error("_send_data()", "con_port state is not CONNECTED");
X /* check port state */
X if (con_port->own_port->state != CONNECTED)
X ipc_fatal_error("_send_data()", "port state is not CONNECTED");
X /* set timer, if time equals 0 clear timer */
X SETTIMER(time);
X con_port->state = con_port->own_port->state = SENDING;
X DEBUGPUTS("state: SENDING");
X nleft = number;
X while(nleft > 0) {
X nwritten = write(con_port->con_sock, buffer, nleft);
X if (nwritten <= 0) {
X /* ERROR! */
X if (errno == EINTR && timeout) {
X /* return TIMEOUT error to caller */
X Errno = ETIMEOUT;
X } else
X ipc_error("system call: write() - 4");
X con_port->state = con_port->own_port->state = CONNECTED;
X DEBUGPUTS("state: CONNECTED");
X return(ERROR);
X }
X nleft -= nwritten;
X buffer += nwritten;
X } /* while */
X con_port->state = con_port->own_port->state = CONNECTED;
X DEBUGPUTS("state: CONNECTED");
X /* clear timer and return */
X (void) alarm(0);
X return(number - nleft);
X} /* _send_data */
X
X/* ============================ DEBUG Routines ============================== */
X
X/******************************************************************************
X * _display_port_info() *
X * *
X * Displays the components of the structure PORTDESCR specified by 'port'. *
X * *
X * Return values: always OK for success *
X ******************************************************************************/
Xint
X_display_port_info(prefix, msg, port)
Xchar *prefix, *msg;
XPORTDESCR port;
X{
X char *tmpptr;
X
X switch(port.state) {
X case CONNECTIONLESS:
X tmpptr = "CONNECTIONLESS";
X break;
X case CONNECTED:
X tmpptr = "CONNECTED";
X break;
X case SELECTING:
X tmpptr = "SELECTING";
X break;
X case ACCEPTING:
X tmpptr = "ACCEPTING";
X break;
X case CONNECTING:
X tmpptr = "CONNECTING";
X break;
X case SEND_REQ:
X tmpptr = "SEND_REQ";
X break;
X case RECV_REQ:
X tmpptr = "RECV_REQ";
X break;
X case SEND_REP:
X tmpptr = "SEND_REP";
X break;
X case RECV_REP:
X tmpptr = "RECV_REP";
X break;
X case SEND_ADDR:
X tmpptr = "SEND_ADDR";
X break;
X case RECV_ADDR:
X tmpptr = "RECV_ADDR";
X break;
X case SENDING:
X tmpptr = "SENDING";
X break;
X case RECEIVING:
X tmpptr = "RECEIVING";
X break;
X default:
X tmpptr = "UNKNOWN";
X } /* switch */
X fprintf(_debugout, "%s %s %s: port information:\n", prefix,
X _processprefix, msg);
X fprintf(_debugout, "%s %s state: %s\n", prefix, _processprefix,
X tmpptr);
X fprintf(_debugout, "%s %s acc_sock = %d\n", prefix, _processprefix,
X port.acc_sock);
X fprintf(_debugout, "%s %s portnum = %d\n", prefix, _processprefix,
X ntohs(port.portnum));
X fprintf(_debugout, "%s %s hostname = %s\n", prefix, _processprefix,
X port.hostname);
X fprintf(_debugout, "%s %s con_sock = %d\n", prefix, _processprefix,
X port.con_sock);
X if (_debugflush)
X fflush(_debugout);
X return(OK);
X} /* _display_port_info */
X
X/******************************************************************************
X * _display_connection_port_info() *
X * *
X * Displays the components of the structure CONNECTIONDESCR specified by *
X * 'con_port'. *
X * *
X * Return values: always OK for success *
X ******************************************************************************/
Xint
X_display_connection_port_info(prefix, msg, con_port)
Xchar *prefix, *msg;
XCONNECTIONDESCR con_port;
X{
X char *tmpptr;
X
X switch(con_port.state) {
X case CONNECTIONLESS:
X tmpptr = "CONNECTIONLESS";
X break;
X case CONNECTED:
X tmpptr = "CONNECTED";
X break;
X case SENDING:
X tmpptr = "SENDING";
X break;
X case RECEIVING:
X tmpptr = "RECEIVING";
X break;
X default:
X tmpptr = "UNKNOWN";
X } /* switch */
X fprintf(_debugout, "%s %s %s: connection port info:\n", prefix,
X _processprefix, msg);
X fprintf(_debugout, "%s %s state: %s\n", prefix, _processprefix,
X tmpptr);
X fprintf(_debugout, "%s %s con_sock = %d\n", prefix, _processprefix,
X con_port.con_sock);
X if (_debugflush)
X fflush(_debugout);
X return(OK);
X} /* _display_connection_port_info */
X
X/******************************************************************************
X * _input_port_info() *
X * *
X * Input the port information for 'port'. *
X * *
X * Return values: none *
X ******************************************************************************/
Xint
X_input_port_info(port)
XPORTDESCR *port;
X{
X int dummy;
X u_short dummy2;
X
X bzero((char *) port, sizeof(PORTDESCR));
X printf("socket = ");
X scanf("%d", &(port->acc_sock));
X printf("portnum = ");
X scanf("%d", &dummy);
X dummy2 = (u_short) dummy;
X port->portnum = htons(dummy2);
X printf("hostname = ");
X scanf("%s", port->hostname);
X} /* _input_port_info */
END_OF_FILE
if test 60451 -ne `wc -c <'lib/ipc_socket.c'`; then
echo shar: \"'lib/ipc_socket.c'\" unpacked with wrong size!
fi
# end of 'lib/ipc_socket.c'
fi
echo shar: End of archive 17 \(of 18\).
cp /dev/null ark17isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 18 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0