/* TCP/IP based Transport Service for RPC ts_tcp.c ** ====================================== ** ** This module provides a transport service for the RPC system developed ** by CERN/DD Online group in 1986-90. ** ** This particular module uses the existing TCP/IP protocol. ** See the RPC User Manual for details of address syntax. ** ** See also the RPC internals manual, which describes how modules ** similar to this one work, also giving flow charts and message formats. ** ** Authors: ** Tim Berners-Lee CERN/DD ** ** History: ** 30 Apr 90 Code extracted from general ts.c module. TBL ** 18 Jun 90 Modified to work on the cray, too. ** 5 Mar 91 Transient connection code put in and tested on VAX/ultrix ** 24 May 91 Moved tcp_connect() before tcp_write() (fwd referece) ** ** Compilation switches: ** ** vms For VMS/Wollongong TCP. Works with VMS/SRI Multinet too. ** ** SELECT The select() call is supported by the socket library. ** If not, can't have multiple clients. */ /* Module parameters: ** ----------------- ** ** These may be undefined and redefined by syspec.h */ #define LISTEN_BACKLOG 2 /* Number of pending connect requests (TCP)*/ #define INET_VMS_ERROR 0x08558002 /* Add to (errno<<3) to make VMS error */ #define WILDCARD '*' /* Wildcard used in addressing */ #define NETCLOSE close /* Routine to close a TCP-IP socket */ #define NETREAD read /* Routine to read from a TCP-IP socket */ #define NETWRITE write /* Routine to write to a TCP-IP socket */ # define FIRST_TCP_PORT 5000 /* First port number to try to bind to */ # define LAST_TCP_PORT 5999 /* Last one to try before giving up */ #include #include "syspec.h" #define TS /* Require visibility of TS interface */ #define TS_INTERNALS /* Require visibility of TS internals */ #include "rpcrts.h" /* Define all general RPC data structures */ #include "rpc_code.h" /* Coding convention macros */ /* ** Definitions for pointers */ #define NIL_MESSAGE (rpc_message *)0 extern char *malloc(); extern void free(); extern char *strncpy(); /* External Routines ** ----------------- */ extern void rpc_new(); /* Allocate rpc_message */ extern void rpc_dispose(); /* Deallocate rpc_message */ extern void rpc_get_string(); /* Get Pascal or C string parameter */ #ifdef AST /* Always used by CATS !!!!!! */ extern void sys_setast(); /* En/Disable ASTs */ rpc_status ts_when_receive(); /* forward (ASTs only) */ #endif /* Forward Declarations ** -------------------- */ #ifdef __STDC__ PRIVATE rpc_status tcp_close(socket_type soc); #else PRIVATE rpc_status tcp_close(); #endif /* Encode INET status (as in sys/errno.h) inet_status() ** ------------------ ** ** The error number is put into the "message number" field, ** and given a facility number 57 hex, with bits "Non-VMS" and ** "Local error message" set, and severity "ERROR". */ #ifdef vms extern int uerrno; /* Deposit of error info (as perr errno.h) */ extern int vmserrno; /* Deposit of VMS error info */ extern volatile noshare int errno; /* noshare to avoid PSECT conflict */ #else #ifndef VM extern int errno; #endif #endif rpc_status inet_status(where) char *where; { CTRACE(tfp, "RPC/TCP: Error %d in `errno' after call to %s() failed.\n", errno, where); #ifdef vms CTRACE(tfp, " Unix error number (uerrno) = %ld dec\n", uerrno); CTRACE(tfp, " VMS error (vmserrno) = %lx hex\n", vmserrno); if (vmserrno) { if (vmserrno & 0x8000) return (vmserrno | INET_VMS_ERROR); /* Add facility & severity */ else return vmserrno; } #else return ((unsigned long)errno<<3) | INET_VMS_ERROR; #endif } /* Return RPC address of this socket tcp_my_address() ** --------------------------------- ** ** This routine returns a string indicating the RPC address of the socket. ** ** On entry, ** soc should be a valid socket pointer ** addrstr points to a buffer to contain a string. ** addrlen indicates the length of the string buffer ** ** On exit, ** *addrstr has the contact address for an external node wishing to contact ** this socket written into it, zero terminated, without the ** protocol on the end. */ #ifdef __STDC__ PRIVATE rpc_status tcp_my_address( socket_type soc, char * addrstr, int addrlen) #else PRIVATE rpc_status tcp_my_address(soc, addrstr, addrlen) socket_type soc; char * addrstr; int addrlen; #endif { rpc_name local_string; rpc_name node_name; gethostname(node_name, RPC_NAME_LENGTH); sprintf(local_string, "%s:%d", node_name, ntohs(soc->mdp.soc_tcp.soc_address.sin_port)); if (strlen(local_string)+1 > addrlen) return RPC_S_BUFFER_OVERFLOW; strcpy(addrstr, local_string); return RPC_S_NORMAL; } /* tcp_my_address */ /* Return RPC address of peer tcp_peer_address() ** -------------------------- ** ** On entry, ** soc should be a valid socket pointer ** address points to a buffer to contain an rpc_name. ** ** On exit, ** *address has the contact address for the peer node. ** blank filled. ** 26 useful characters in the address. ** ** Bug: Peer node name not extracted: Number only given. */ #ifdef __STDC__ PRIVATE rpc_status tcp_peer_address( socket_type soc, char * addrstr, int addrlen) #else PRIVATE rpc_status tcp_peer_address(soc, addrstr, addrlen) socket_type soc; char * addrstr; int addrlen; #endif { int i; rpc_name local_string; unsigned char * p = (unsigned char *)&soc->mdp.soc_tcp.soc_address.sin_addr; sprintf(local_string, "%d.%d.%d.%d:%d", (int)p[0], (int)p[1], (int)p[2], (int)p[3], ntohs(soc->mdp.soc_tcp.soc_address.sin_port)); if (strlen(local_string)+1 > addrlen) return RPC_S_BUFFER_OVERFLOW; strcpy(addrstr, local_string); return RPC_S_NORMAL; } /* Connect a parsed socket ** ----------------------- */ #ifdef __STDC__ PRIVATE rpc_status tcp_connect(socket_type soc) #else PRIVATE rpc_status tcp_connect(soc) socket_type soc; #endif { if (soc->soc_protocol->reliable) soc->mdp.soc_tcp.soc_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); else soc->mdp.soc_tcp.soc_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (soc->mdp.soc_tcp.soc_s<0) return inet_status("socket"); CTRACE(tfp, "RPC/IP: Opened socket number %d\n", soc->mdp.soc_tcp.soc_s); if (connect(soc->mdp.soc_tcp.soc_s, &soc->mdp.soc_tcp.soc_address, sizeof(soc->mdp.soc_tcp.soc_address))<0) return inet_status("connect"); soc->mdp.soc_tcp.soc_connected = TRUE; CTRACE(tfp, "RPC/TCP: Socket connected OK.\n"); return RPC_S_NORMAL; } /* Send a message over the given socket tcp_write() ** ------------------------------------ ** ** On entry, ** pmessage points to a pointer to the message, with fields: ** m_next (undefined) ** m_socket valid ** m_index Length of message to be sent in bytes, ** exclusing any bytes needed for the protocol. ** m_status (undefined) ** ** On exit, ** ** The pointer to the message may have been changed. In this case, ** it will point to a message with the m_socket and m_status fields ** set, but without the data. This routine may therefore be DESTRUCTIVE. ** In fact, this implementation is not. ** ** returns: Status of operation. ** ** A failure to transmit is returned as a bad status except when it is ** received on a slave socket which returns zero bytes sent, in which ** case it is assumed that the write was ok but that the peer exited with ** the data before the acknowledgement could get back. */ #ifdef __STDC__ PRIVATE rpc_status tcp_write(rpc_message_pointer *ppmessage) #else PRIVATE rpc_status tcp_write(ppmessage) rpc_message_pointer *ppmessage; #endif { rpc_status status; int tcp_status; /* Number of bytes in a slice, or <0 => error. */ int done; /* Number of bytes transferred so far */ register rpc_message *mes = *ppmessage; register struct socket_struct *soc = mes->m_socket; unsigned int bufsize = mes->m_index; rpc_byte *p = mes->body.rpc_b; mes->m_status = check_socket(soc); if (BAD(mes->m_status)) return status; if (!soc->mdp.soc_tcp.soc_connected){ status = tcp_connect(soc); /* Reconnect disconnected socket */ if (!soc->mdp.soc_tcp.soc_connected) /* If still disconnected, forget it */ return status; } if (rpc_trace) { UTRACE(tfp, "RPC/TCP: Sending message, "); hex_message(mes, mes->m_index); } /* Store the length of the message just before it: */ *--p = (rpc_byte)(bufsize & 0xff); *--p = (rpc_byte)((bufsize >> 8) & 0xff); *--p = (rpc_byte)((bufsize >> 16) & 0xff); *--p = (rpc_byte)((bufsize >> 24) & 0xff); /* The following didn't work on the Cray : mes->header.ip.length = htonl((long)bufsize); Store size just before msg */ mes->m_status = RPC_S_NORMAL; /* So far. */ for(done=0; done<4+bufsize;) { tcp_status = NETWRITE(soc->mdp.soc_tcp.soc_s, p+done, bufsize+4); if (tcp_status<=0) { mes->m_status = inet_status("netwrite"); break; } done = done+tcp_status; CTRACE(tfp, "RPC/TCP: netwrite() wrote %d bytes out of %d\n", tcp_status, bufsize+4); } return mes->m_status; } /* tcp_write */ /* Receive message tcp_read() ** --------------- ** ** This procedure waits for a message to arrive on a socket and returns the ** message. A suitable message buffer is passed to the routine, but a ** different one may be returned. If the socket passed is the master socket ** for mutiple connections, then the message recieved will carry the socket ** number of the slave socket on which the message actually arrived. ** ** On entry: ** ppmessage is pointer to pointer to buffer, fields: ** m_socket The socket to be used - possibly a master socket ** m_index don't care ** m_status don't care ** m_next don't care ** ** timeout -1 for infinite, 0 for poll, else in units of 10ms ** ** On exit, ** returns The status of the operation. ** *pmessage may have been modified to point to another message ** from the pool. Fields: ** m_socket The (possible slave) socket the msg came on. ** m_status The status of the operation (= return value). ** m_index The number of bytes recieved if good status ** m_next junk. ** */ #ifdef __STDC__ PRIVATE rpc_status tcp_read( rpc_message_pointer *ppmessage, int timeout) #else PRIVATE rpc_status tcp_read(ppmessage, timeout) rpc_message_pointer *ppmessage; int timeout; #endif { int tcp_status; /* Number of bytes in a slice, or <0 => error */ rpc_long length; /* length of the message received */ rpc_long done; /* Number of bytes transferred so far */ register socket_type rsoc; /* Socket to actually receive on */ rpc_message * mes = *ppmessage; /* Buffer provided for data */ socket_type soc = mes->m_socket; /* Socket read requested on */ rpc_byte * p; /* Pointer to message including length*/ for(;;) { /* If it's a master socket, then find a slave: */ if (soc->mdp.soc_tcp.soc_role == master) { #ifdef SELECT fd_set read_chans; fd_set write_chans; fd_set except_chans; int nchans; /* Number of channels for SELECT */ int nfound; /* Number of ready channels */ socket_type scan; struct timeval max_wait; /* timeout in form for select() */ FD_ZERO(&write_chans); /* Clear the write mask */ FD_ZERO(&except_chans); /* Clear the exception mask */ /* If timeout is required, the timeout structure is set up. Otherwise ** (timeout<0) a zero is passed instead of a pointer to the struct timeval. */ if (timeout>=0) { max_wait.tv_sec = timeout/100; max_wait.tv_usec = (timeout%100)*10000; } for (;;) { /* Loop while connections keep coming */ /* The read mask expresses interest in the master channel for incomming ** connections) or any slave channel (for incomming messages). */ FD_ZERO(&read_chans); /* Set upthe read mask */ FD_SET(nchans=soc->mdp.soc_tcp.soc_s, &read_chans); for(scan=soc->mdp.soc_tcp.soc_slaves; scan; scan=scan->soc_next) { int chan=scan->mdp.soc_tcp.soc_s; FD_SET(chan, &read_chans); if (nchans= 0 ? &max_wait : 0); if (nfound<0) return inet_status("accept"); if (nfound==0) return RPC_S_TIMEOUT; /* If an incomming connection has arrived, accept the new socket: */ if (FD_ISSET(soc->mdp.soc_tcp.soc_s, &read_chans)) { rsoc = (socket_type)malloc(sizeof(socket_descriptor)); /* Make new slave */ rsoc->soc_next = soc->mdp.soc_tcp.soc_slaves; /* list */ soc->mdp.soc_tcp.soc_slaves = rsoc; rsoc->mdp.soc_tcp.soc_master = soc; rsoc->soc_protocol = soc->soc_protocol; rsoc->mdp.soc_tcp.soc_role = slave; rsoc->mdp.soc_tcp.soc_slaves = NULL; rsoc->mdp.soc_tcp.soc_connected = TRUE; rsoc->mdp.soc_tcp.soc_addrlen= sizeof(rsoc->mdp.soc_tcp.soc_address); CTRACE(tfp, "RPC/TCP: New incomming connection:\n"); FLUSH_TRACE tcp_status = accept(soc->mdp.soc_tcp.soc_s, &rsoc->mdp.soc_tcp.soc_address, &rsoc->mdp.soc_tcp.soc_addrlen); if (tcp_status<0) return inet_status("accept"); rsoc->mdp.soc_tcp.soc_s = tcp_status; /* socket number */ CTRACE(tfp, "RPC/TCP: Accepted new socket %d\n", tcp_status); nfound--; } /* If new connection */ /* If a message has arrived on one of the channels, take that channel: */ if(nfound) { for(rsoc=soc->mdp.soc_tcp.soc_slaves; rsoc; rsoc=rsoc->soc_next) if(FD_ISSET(rsoc->mdp.soc_tcp.soc_s, &read_chans)) break; break; /* Found input socket */ } /* if message waiting */ } /* loop on event */ #else /* SELECT not supported */ if (!(soc->mdp.soc_tcp.soc_slaves)) { /* No slaves: must accept */ rsoc = (socket_type)malloc(sizeof(socket_descriptor)); /* Make new slave */ rsoc->soc_next = soc->mdp.soc_tcp.soc_slaves; /* put on list */ soc->mdp.soc_tcp.soc_slaves = rsoc; rsoc->mdp.soc_tcp.soc_master = soc; rsoc->soc_protocol = soc->soc_protocol; rsoc->mdp.soc_tcp.soc_role = slave; /* Set fields up */ rsoc->mdp.soc_tcp.soc_slaves = NULL; rsoc->mdp.soc_tcp.soc_connected = TRUE; rsoc->mdp.soc_tcp.soc_addrlen= sizeof(rsoc->mdp.soc_tcp.soc_address); CTRACE(tfp, "RPC/TCP: Waiting for incomming connection...\n"); FLUSH_TRACE tcp_status = accept(soc->mdp.soc_tcp.soc_s, &rsoc->mdp.soc_tcp.soc_address, &rsoc->mdp.soc_tcp.soc_addrlen); if (tcp_status<0) return inet_status("accept"); rsoc->mdp.soc_tcp.soc_s = tcp_status; /* socket number */ CTRACE(tfp, "RPC/TCP: Accepted socket %d\n", tcp_status); } /* end if no slaves */ rsoc = soc->mdp.soc_tcp.soc_slaves; /* Take the only slave */ #endif } else /* Not master */ rsoc = soc; /* Read the message now on whatever channel there is: */ CTRACE(tfp,"RPC/TCP: Reading socket %d\n", rsoc->mdp.soc_tcp.soc_s); FLUSH_TRACE p = mes->body.rpc_b-4; for(done=0; done<4;) { tcp_status = NETREAD(rsoc->mdp.soc_tcp.soc_s, /* Get length */ p+done, 4); if (tcp_status <=0) goto connection_fail; done = done+tcp_status; CTRACE(tfp, "RPC/TCP: netread() read %d bytes of header\n", tcp_status); } /* Won't work on Cray: length = ntohl(mes->header.ip.length); total size of message */ length = *p++; /* Unpack length of the front */ length = (length<<8)+(*p++); length = (length<<8)+(*p++); length = (length<<8)+(*p++); if (length<2 || length>RPC_BUFFER_SIZE) { CTRACE(tfp, "RPC/TCP: Message length received was %x hex! ***\n", length); (*ppmessage)->m_status = RPC_S_BAD_MESSAGE_HEADER; return RPC_S_BAD_MESSAGE_HEADER; /* framing else overflow */ } done = 0; while (done < length) { tcp_status = NETREAD(rsoc->mdp.soc_tcp.soc_s, /* Get a slice */ &mes->body.rpc_b[done], length-done); if (tcp_status <=0) goto connection_fail; done = done+tcp_status; CTRACE(tfp, "RPC/TCP: netread() read %d bytes out of %d\n", tcp_status, length); } mes->m_index = length; /* Return actual length received */ mes->m_socket = rsoc; /* Fill in back pointer to socket */ mes->m_status = RPC_S_NORMAL; if (rpc_trace) { UTRACE(tfp, "RPC/TCP: Received message, "); hex_message(mes, mes->m_index); } if (soc->mdp.soc_tcp.soc_role == transient) { CTRACE(tfp, "RPC/TCP: Closing transient socket %d\n", soc->mdp.soc_tcp.soc_s); soc->mdp.soc_tcp.soc_connected = FALSE; if (NETCLOSE(soc->mdp.soc_tcp.soc_s) < 0) return inet_status("netclose of transient connection"); } return RPC_S_NORMAL; /* If tcp_status <=0 0: */ connection_fail: if (tcp_status<0) return inet_status("netread"); else { CTRACE(tfp, "RPC/TCP: Socket %d disconnected by peer\n", rsoc->mdp.soc_tcp.soc_s); if (soc->mdp.soc_tcp.soc_role==master) { (void) tcp_close(rsoc); } else return INET_VMS_ERROR+(ECONNRESET<<3); } }; /* for loop */ /*NOTREACHED*/ } /* Asynchronous Receive ** -------------------- ** ** On entry, ** pmessage is the address of a suitable message buffer ** action is the address of the routine to be called ** user_1 is not used at the moment. ** ** On exit, ** the parameters are stored only. Exits immediately. ** ** On arrival of the next message: ** The routine *action() is called, and passed the message as a parameter. ** If the buffer *pmessage is not used, it will be reused elsewhere and ** a different buffer passed to *action(). */ #ifdef __STDC__ PRIVATE rpc_status tcp_aread( rpc_message_pointer pmessage, rpc_pointer action, rpc_integer user_1) #else PRIVATE rpc_status tcp_aread(pmessage, action, user_1) rpc_message_pointer pmessage; rpc_pointer action; rpc_integer user_1; #endif { return RPC_S_NOT_IMPLEMENTED; } /* tcp_aread */ /* Open a transport connection tcp_open() ** --------------------------- ** ** On entry, ** soc points to a recently created socket, fields as follows: ** ** soc_last_call_sent NULL ** soc_last_reply_sent NULL ** soc_next-call_tid 0 ** soc_protocol valid pointer to protocol structure ** ** and otherwise uninitialised. ** ** tsap points to a zero-terminated string representing the address ** (with no .TCP on it). See the RPC User Maual for details of the ** syntax of this string. ** ** TSAP Syntax: ** node_name | byte.byte.byte.byte { : portnumber } ** ** e.g. 100.1.2.5:4 ** uxocb1:53 ** ** An omitted port number causes the creation of a new port. ** An omitted node number or name causes any connecting node to be serviced. ** A completely null tsap indicates a passive server started by daemon. */ #ifdef __STDC__ PRIVATE rpc_status tcp_open(socket_type soc, char * tsap) #else PRIVATE rpc_status tcp_open(soc, tsap) socket_type soc; char *tsap; #endif { BOOLEAN dynamic_allocation; /* Search for free port? */ rpc_status status = RPC_S_NORMAL; /* (unless something goes wrong)*/ soc->mdp.soc_tcp.soc_slaves = 0; /* Has no slaves by default */ soc->mdp.soc_tcp.soc_master = 0; /* Has no master by default */ /* Deal with PASSIVE socket: ** ** A passive TSAP is one which has been created by the inet daemon. ** It is indicated by a void TSAP name. In this case, the inet ** daemon has started this process and given it, as stdin, the connection ** which it is to use. */ if (*tsap == 0) { /* void tsap => passive */ dynamic_allocation = FALSE; /* not dynamically allocated */ soc->mdp.soc_tcp.soc_role = passive; /* Passive: started by daemon */ #ifdef vms { unsigned short channel; /* VMS I/O channel */ struct string_descriptor { /* This is NOT a proper descriptor*/ int size; /* but it will work. */ char *ptr; /* Should be word,byte,byte,long */ } sys_input = {10, "SYS$INPUT:"}; rpc_status status; /* Returned status of assign */ extern rpc_status sys$assign(); status = sys$assign(&sys_input, &channel, 0, 0); soc->mdp.soc_tcp.soc_s = channel; /* The channel is stdin */ CTRACE(tfp, "RPC/IP: Opened PASSIVE socket %d\n", channel); return status; } #else soc->mdp.soc_tcp.soc_s = 0; /* The channel is stdin */ CTRACE(tfp, "RPC/IP: PASSIVE socket 0 assumed from inet daemon\n"); return RPC_S_NORMAL; #endif /* Parse the name (if not PASSIVE) */ } else { /* Non-void TSAP */ register char *p = tsap; /* pointer to string */ char *q; struct hostent *phost; /* Pointer to host - See netdb.h */ register struct sockaddr_in* sin = &soc->mdp.soc_tcp.soc_address; /* Set up defaults: */ sin->sin_family = AF_INET; /* Family = internet, host order */ sin->sin_port = 0; /* Default: new port, */ dynamic_allocation = TRUE; /* dynamically allocated */ soc->mdp.soc_tcp.soc_role = single; /* Single by default */ /* Check for special characters: */ if (*p == WILDCARD) { /* Any node */ soc->mdp.soc_tcp.soc_role = master; p++; } else if (*p == '#') { /* Transient connections */ soc->mdp.soc_tcp.soc_role = transient; p++; } /* Strip off trailing port number if any: */ for(q=p; *q; q++) if (*q==':') { *q++ = 0; /* Terminate node string */ sin->sin_port = htons((unsigned short)parse_cardinal( &status, &q, (unsigned int)65535)); if (!(status &1)) return status; if (*q) return RPC_S_SYNTAX_4; /* Junk follows port number */ dynamic_allocation = FALSE; break; /* Exit for loop before we skip the zero */ } /*if*/ /* Get node name: */ if (*p == 0) { sin->sin_addr.s_addr = INADDR_ANY; /* Default: any address */ } else if (*p>='0' && *p<='9') { /* Numeric node address: */ sin->sin_addr.s_addr = inet_addr(p); /* See arpa/inet.h */ } else { /* Alphanumeric node name: */ phost=gethostbyname(p); /* See netdb.h */ if (!phost) { CTRACE(tfp, "RPC/IP: Can't find internet node name `%s'.\n",p); return inet_status("gethostbyname"); /* Fail? */ } memcpy(&sin->sin_addr, phost->h_addr, phost->h_length); } CTRACE(tfp, "RPC/TCP: Parsed address as port %4x, inet %d.%d.%d.%d\n", (unsigned int)ntohs(sin->sin_port), (int)*((unsigned char *)(&sin->sin_addr)+0), (int)*((unsigned char *)(&sin->sin_addr)+1), (int)*((unsigned char *)(&sin->sin_addr)+2), (int)*((unsigned char *)(&sin->sin_addr)+3)); } /* scope of p */ /* Master socket for server: */ if (soc->mdp.soc_tcp.soc_role == master) { /* Create internet socket */ if (soc->soc_protocol->reliable) soc->mdp.soc_tcp.soc_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); else soc->mdp.soc_tcp.soc_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (soc->mdp.soc_tcp.soc_s<0) return inet_status("socket"); CTRACE(tfp, "RPC/IP: Opened master socket number %d\n", soc->mdp.soc_tcp.soc_s); /* If the port number was not specified, then we search for a free one. */ if (dynamic_allocation) { unsigned short try; for (try=FIRST_TCP_PORT; try<=LAST_TCP_PORT; try++) { soc->mdp.soc_tcp.soc_address.sin_port = htons(try); if (bind(soc->mdp.soc_tcp.soc_s, &soc->mdp.soc_tcp.soc_address, sizeof(soc->mdp.soc_tcp.soc_address)) == 0) break; if (try == LAST_TCP_PORT) return inet_status("bind"); } CTRACE(tfp, "RPC/IP: Bound to port %u.\n", ntohs(soc->mdp.soc_tcp.soc_address.sin_port)); } else { /* Port was specified */ if (bind(soc->mdp.soc_tcp.soc_s, &soc->mdp.soc_tcp.soc_address, sizeof(soc->mdp.soc_tcp.soc_address))<0) return inet_status("bind"); } if (listen(soc->mdp.soc_tcp.soc_s, LISTEN_BACKLOG)<0) return inet_status("listen"); CTRACE(tfp, "RPC/TCP: Master socket(), bind() and listen() all OK\n"); return RPC_S_NORMAL; /* Transient connection socket: */ } else if (soc->mdp.soc_tcp.soc_role == transient) { soc->mdp.soc_tcp.soc_connected = FALSE; CTRACE(tfp, "RPC/TCP: Socket not created yet: transient connections\n"); return RPC_S_NORMAL; /* Normal single socket: */ } else { /* Normal single */ return tcp_connect(soc); } /* if transient */ /*NOTREACHED*/ } /* tcp_open */ /* Close a Transport Connection tcp_close() ** ---------------------------- ** ** On entry, ** soc Must be a socket opened by tcp_open(). ** ** On exit, ** returns a status of the close operation. */ #ifdef __STDC__ PRIVATE rpc_status tcp_close(socket_type soc) #else PRIVATE rpc_status tcp_close(soc) socket_type soc; #endif { register socket_type scan; /* Close slaves: */ while (scan = soc->mdp.soc_tcp.soc_slaves) (void)tcp_close(scan); /* dispose */ /* Close this socket itself: First, remove it from any queue of slaves */ if (scan = soc->mdp.soc_tcp.soc_master) { if (scan->mdp.soc_tcp.soc_slaves == soc) { scan->mdp.soc_tcp.soc_slaves = soc->soc_next; } else { scan = scan->mdp.soc_tcp.soc_slaves; while (scan->soc_next == soc) scan = scan->soc_next; scan->soc_next = soc->soc_next; } } /* Now do the TCP close: */ if (soc->mdp.soc_tcp.soc_connected) { CTRACE(tfp, "RPC/TCP: Closing socket %d\n", soc->mdp.soc_tcp.soc_s); if (NETCLOSE(soc->mdp.soc_tcp.soc_s) < 0) return inet_status("netclose"); } free(soc); /* Deallocate the socket itself */ return RPC_S_NORMAL; } /* tcp_close */ /* Data structure defining this medium: ** ----------------------------------- */ PRIVATE rpc_protocol tcp_protocol = { 0, /* Link to next (not yet used) */ "tcp", /* Name of medium used in address strings */ 1, /* Yes, reliable */ tcp_open, tcp_close, tcp_write, tcp_read, tcp_aread, tcp_my_address, tcp_peer_address, }; /* Register this protocol with the RPC system ** ------------------------------------------ */ #ifdef __STDC__ rpc_status use_tcp(void) #else rpc_status use_tcp() #endif { (void) rpc_use(&tcp_protocol); }