diff options
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_socket.c')
-rw-r--r-- | usr.sbin/atm/scspd/scsp_socket.c | 1349 |
1 files changed, 1349 insertions, 0 deletions
diff --git a/usr.sbin/atm/scspd/scsp_socket.c b/usr.sbin/atm/scspd/scsp_socket.c new file mode 100644 index 0000000..83f41cd --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_socket.c @@ -0,0 +1,1349 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: scsp_socket.c,v 1.6 1998/08/21 18:08:24 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP socket management routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_socket.c,v 1.6 1998/08/21 18:08:24 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Local variables + */ +static struct t_atm_llc llc_scsp = { + T_ATM_LLC_SHARING, + 8, + {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x5e, 0x00, 0x05} +}; + +static struct t_atm_aal5 aal5 = { + 0, /* forward_max_SDU_size */ + 0, /* backward_max_SDU_size */ + 0 /* SSCS_type */ +}; + +static struct t_atm_traffic traffic = { + { /* forward */ + T_ATM_ABSENT, /* PCR_high_priority */ + 0, /* PCR_all_traffic */ + T_ATM_ABSENT, /* SCR_high_priority */ + T_ATM_ABSENT, /* SCR_all_traffic */ + T_ATM_ABSENT, /* MBS_high_priority */ + T_ATM_ABSENT, /* MBS_all_traffic */ + T_NO /* tagging */ + }, + { /* backward */ + T_ATM_ABSENT, /* PCR_high_priority */ + 0, /* PCR_all_traffic */ + T_ATM_ABSENT, /* SCR_high_priority */ + T_ATM_ABSENT, /* SCR_all_traffic */ + T_ATM_ABSENT, /* MBS_high_priority */ + T_ATM_ABSENT, /* MBS_all_traffic */ + T_NO /* tagging */ + }, + T_YES /* best_effort */ +}; + +static struct t_atm_bearer bearer = { + T_ATM_CLASS_X, /* bearer_class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NULL, /* timing_requirements */ + T_NO, /* clipping_susceptibility */ + T_ATM_1_TO_1 /* connection_configuration */ +}; + +static struct t_atm_qos qos = { + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* forward */ + T_ATM_QOS_CLASS_0 /* qos_class */ + }, + { /* backward */ + T_ATM_QOS_CLASS_0 /* qos_class */ + } +}; + +static struct t_atm_app_name appname = { + "SCSP" +}; + + +/* + * Find a DCS, given its socket + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 not found + * address of DCS block corresponding to socket + * + */ +Scsp_dcs * +scsp_find_dcs(sd) + int sd; +{ + Scsp_server *ssp; + Scsp_dcs *dcsp; + + /* + * Loop through the list of servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + /* + * Check all the DCSs chained from each server + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (dcsp->sd_sock == sd) + break; + } + } + + return(dcsp); +} + + +/* + * Find a server, given its socket + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 not found + * address of server block corresponding to socket + * + */ +Scsp_server * +scsp_find_server(sd) + int sd; +{ + Scsp_server *ssp; + + /* + * Loop through the list of servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_sock == sd) + break; + } + + return(ssp); +} + + +/* + * Connect to a directly connected server + * + * Arguments: + * dcsp pointer to DCS block for server + * + * Returns: + * 0 success (dcsp->sd_sock is set) + * else errno indicating reason for failure + * + */ +int +scsp_dcs_connect(dcsp) + Scsp_dcs *dcsp; + +{ + int rc, sd; + struct sockaddr_atm DCS_addr; + + /* + * If the DCS already has an open connection, just return + */ + if (dcsp->sd_sock != -1) { + return(0); + } + + /* + * Open an ATM socket + */ + sd = socket(PF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (sd == -1) { + return(ESOCKTNOSUPPORT); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set up connection parameters for SCSP connection + */ + UM_ZERO(&DCS_addr, sizeof(DCS_addr)); +#if (defined(BSD) && (BSD >= 199103)) + DCS_addr.satm_len = sizeof(DCS_addr); +#endif + DCS_addr.satm_family = AF_ATM; + DCS_addr.satm_addr.t_atm_sap_addr.SVE_tag_addr = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_addr.SVE_tag_selector = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_addr.address_format = + dcsp->sd_addr.address_format; + DCS_addr.satm_addr.t_atm_sap_addr.address_length = + dcsp->sd_addr.address_length; + UM_COPY(dcsp->sd_addr.address, + DCS_addr.satm_addr.t_atm_sap_addr.address, + dcsp->sd_addr.address_length); + + DCS_addr.satm_addr.t_atm_sap_layer2.SVE_tag = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_layer2.ID_type = + T_ATM_SIMPLE_ID; + DCS_addr.satm_addr.t_atm_sap_layer2.ID.simple_ID = + T_ATM_BLLI2_I8802; + + DCS_addr.satm_addr.t_atm_sap_layer3.SVE_tag = + T_ATM_ABSENT; + DCS_addr.satm_addr.t_atm_sap_appl.SVE_tag = + T_ATM_ABSENT; + + /* + * Bind the socket to our address + */ + if (bind(sd, (struct sockaddr *)&DCS_addr, + sizeof(DCS_addr))) { + rc = errno; + goto connect_fail; + } + + /* + * Set non-blocking operation + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + scsp_log(LOG_ERR, "scsp_dcs_connect: fcntl failed"); + rc = errno; + goto connect_fail; + } + + /* + * Set AAL 5 options + */ + aal5.forward_max_SDU_size = dcsp->sd_server->ss_mtu; + aal5.backward_max_SDU_size = dcsp->sd_server->ss_mtu; + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + sizeof(aal5)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set traffic options + */ + switch(dcsp->sd_server->ss_media) { + case MEDIA_TAXI_100: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI100; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI100; + break; + case MEDIA_TAXI_140: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI140; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI140; + break; + case MEDIA_OC3C: + case MEDIA_UTP155: + traffic.forward.PCR_all_traffic = ATM_PCR_OC3C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC3C; + break; + case MEDIA_OC12C: + traffic.forward.PCR_all_traffic = ATM_PCR_OC12C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC12C; + break; + } + + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, sizeof(traffic)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set bearer capability options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, sizeof(bearer)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set QOS options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_QOS, + (caddr_t)&qos, sizeof(qos)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set LLC identifier + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_LLC, + (caddr_t)&llc_scsp, sizeof(llc_scsp)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Connect to DCS + */ + if (connect(sd, (struct sockaddr *)&DCS_addr, + sizeof(DCS_addr)) < 0 && + errno != EINPROGRESS) { + rc = errno; + goto connect_fail; + } + + /* + * Set return values + */ + dcsp->sd_sock = sd; + return(0); + +connect_fail: + /* + * Close the socket if something didn't work + */ + (void)close(sd); + dcsp->sd_sock = -1; + if (rc == 0) + rc = EFAULT; + return(rc); +} + + +/* + * Listen for ATM connections from DCSs + * + * Arguments: + * None + * + * Returns: + * sock socket which is listening (also set in + ssp->ss_dcs_lsock) + * -1 error encountered (reason in errno) + * + */ +int +scsp_dcs_listen(ssp) + Scsp_server *ssp; +{ + int rc, sd; + struct sockaddr_atm ls_addr; + + /* + * Open a socket + */ + sd = socket(PF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (sd == -1) { + rc = errno; + goto listen_fail; + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set up our address + */ + UM_ZERO(&ls_addr, sizeof(ls_addr)); +#if (defined(BSD) && (BSD >= 199103)) + ls_addr.satm_len = sizeof(ls_addr); +#endif + ls_addr.satm_family = AF_ATM; + ls_addr.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_addr.SVE_tag_selector = + T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_addr.address_format = + ssp->ss_addr.address_format; + ls_addr.satm_addr.t_atm_sap_addr.address_length = + ssp->ss_addr.address_length; + UM_COPY(ssp->ss_addr.address, + ls_addr.satm_addr.t_atm_sap_addr.address, + ssp->ss_addr.address_length); + + ls_addr.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID; + ls_addr.satm_addr.t_atm_sap_layer2.ID.simple_ID = + T_ATM_BLLI2_I8802; + + ls_addr.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + ls_addr.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + /* + * Bind the socket to our address + */ + rc = bind(sd, (struct sockaddr *)&ls_addr, sizeof(ls_addr)); + if (rc == -1) { + rc = errno; + goto listen_fail; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + scsp_log(LOG_ERR, "scsp_dcs_listen: fcntl failed"); + rc = errno; + goto listen_fail; + } + + /* + * Set AAL 5 options + */ + aal5.forward_max_SDU_size = ssp->ss_mtu; + aal5.backward_max_SDU_size = ssp->ss_mtu; + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + sizeof(aal5)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set traffic options + */ + switch(ssp->ss_media) { + case MEDIA_TAXI_100: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI100; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI100; + break; + case MEDIA_TAXI_140: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI140; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI140; + break; + case MEDIA_OC3C: + case MEDIA_UTP155: + traffic.forward.PCR_all_traffic = ATM_PCR_OC3C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC3C; + break; + case MEDIA_OC12C: + traffic.forward.PCR_all_traffic = ATM_PCR_OC12C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC12C; + break; + } + + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, sizeof(traffic)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set bearer capability options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, sizeof(bearer)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set QOS options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_QOS, + (caddr_t)&qos, sizeof(qos)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set LLC identifier + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_LLC, + (caddr_t)&llc_scsp, sizeof(llc_scsp)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Listen for new connections + */ + if (listen(sd, 5) < 0) { + rc = errno; + goto listen_fail; + } + + ssp->ss_dcs_lsock = sd; + return(sd); + +listen_fail: + /* + * Close the socket if anything didn't work + */ + (void)close(sd); + if (rc == 0) + errno = EFAULT; + else + errno = rc; + ssp->ss_dcs_lsock = -1; + return(-1); +} + + +/* + * Accept a connection from a DCS + * + * Arguments: + * ssp pointer to server block + * + * Returns: + * address of DCS with new connection + * 0 failure (errno has reason) + * + */ +Scsp_dcs * +scsp_dcs_accept(ssp) + Scsp_server *ssp; +{ + int len, rc, sd; + struct sockaddr_atm dcs_sockaddr; + struct t_atm_sap_addr *dcs_addr = &dcs_sockaddr.satm_addr.t_atm_sap_addr; + Atm_addr dcs_atmaddr; + Scsp_dcs *dcsp; + + /* + * Accept the new connection + */ + len = sizeof(dcs_sockaddr); + sd = accept(ssp->ss_dcs_lsock, + (struct sockaddr *)&dcs_sockaddr, &len); + if (sd < 0) { + return((Scsp_dcs *)0); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Copy the DCS's address from the sockaddr to an Atm_addr + */ + if (dcs_addr->SVE_tag_addr != T_ATM_PRESENT) { + dcs_atmaddr.address_format = T_ATM_ABSENT; + dcs_atmaddr.address_length = 0; + } else { + dcs_atmaddr.address_format = dcs_addr->address_format; + dcs_atmaddr.address_length = dcs_addr->address_length; + UM_COPY(dcs_addr->address, dcs_atmaddr.address, + dcs_addr->address_length); + } + + /* + * Find out which DCS this connection is for + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + /* + * Compare DCS's address to address + * configured by user + */ + if (ATM_ADDR_EQUAL(&dcsp->sd_addr, + &dcs_atmaddr)) + break; + } + + /* + * Make sure we have this DCS configured + */ + if (!dcsp) { + errno = EINVAL; + goto dcs_accept_fail; + } + + /* + * Make sure we are in a state to accept the connection + */ + if (ssp->ss_state != SCSP_SS_ACTIVE) { + errno = EACCES; + goto dcs_accept_fail; + } + + /* + * Make sure we don't already have a connection to this DCS + */ + if (dcsp->sd_sock != -1) { + errno = EALREADY; + goto dcs_accept_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto dcs_accept_fail; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + goto dcs_accept_fail; + } + + /* + * Cancel the open retry timer + */ + HARP_CANCEL(&dcsp->sd_open_t); + + /* + * Save the socket address and return the + * address of the DCS + */ + dcsp->sd_sock = sd; + return(dcsp); + +dcs_accept_fail: + /* + * An error has occured--clean up and return + */ + (void)close(sd); + return((Scsp_dcs *)0); +} + + +/* + * Read an SCSP message from a directly connected server + * + * Arguments: + * dcsp pointer to DCS block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_dcs_read(dcsp) + Scsp_dcs *dcsp; + +{ + int len, rc; + char *buff = (char *)0; + Scsp_server *ssp = dcsp->sd_server; + Scsp_msg *msg; + struct scsp_nhdr msg_hdr, *mhp; + + /* + * Get a buffer to hold the entire message + */ + len = ssp->ss_mtu; + buff = (char *)UM_ALLOC(len); + if (!buff) { + scsp_mem_err("scsp_dcs_read: ssp->ss_mtu"); + } + + /* + * Read the message + */ + len = read(dcsp->sd_sock, buff, len); + if (len < 0) { + goto dcs_read_fail; + } + + /* + * Parse the input message and pass it to the Hello FSM + */ + msg = scsp_parse_msg(buff, len); + if (msg) { + /* + * Write the message to the trace file if + * it's of a type we're tracing + */ + if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) && + msg->sc_msg_type == SCSP_HELLO_MSG) || + ((scsp_trace_mode & SCSP_TRACE_CA_MSG) && + msg->sc_msg_type != SCSP_HELLO_MSG)) { + scsp_trace_msg(dcsp, msg, 1); + scsp_trace("\n"); + } + + /* + * Pass the message to the Hello FSM + */ + rc = scsp_hfsm(dcsp, SCSP_HFSM_RCVD, msg); + scsp_free_msg(msg); + } else { + /* + * Message was invalid. Write it to the trace file + * if we're tracing messages. + */ + if (scsp_trace_mode & (SCSP_TRACE_HELLO_MSG & + SCSP_TRACE_CA_MSG)) { + int i; + scsp_trace("Invalid message received:\n"); + scsp_trace("0x"); + for (i = 0; i < len; i++) { + scsp_trace("%02x ", (u_char)buff[i]); + } + scsp_trace("\n"); + } + } + UM_FREE(buff); + + return(0); + +dcs_read_fail: + /* + * Error on read--check for special conditions + */ + rc = errno; + if (errno == ECONNRESET) { + /* + * VCC has been closed--pass the event to + * the Hello FSM + */ + rc = scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, + (Scsp_msg *)0); + } + if (errno == ECONNREFUSED) { + /* + * VCC open failed--set a timer and try + * again when it fires + */ + HARP_TIMER(&dcsp->sd_open_t, + SCSP_Open_Interval, + scsp_open_timeout); + rc = 0; + } + + if (buff) + UM_FREE(buff); + return(rc); +} + + +/* + * Listen for Unix connections from SCSP client servers + * + * Arguments: + * None + * + * Returns: + * sock socket which is listening + * -1 error (reason in errno) + * + */ +int +scsp_server_listen() +{ + int rc, sd; + + static struct sockaddr scsp_addr = { +#if (defined(BSD) && (BSD >= 199103)) + sizeof(struct sockaddr), /* sa_len */ +#endif + AF_UNIX, /* sa_family */ + SCSPD_SOCK_NAME /* sa_data */ + }; + + /* + * Unlink any old socket + */ + rc = unlink(SCSPD_SOCK_NAME); + if (rc < 0 && errno != ENOENT) + return(-1); + + /* + * Open a socket + */ + sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sd == -1) { + return(-1); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Bind the socket's address + */ + rc = bind(sd, &scsp_addr, sizeof(scsp_addr)); + if (rc == -1) { + (void)close(sd); + return(-1); + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + (void)close(sd); + return(-1); + } + + /* + * Listen for new connections + */ + if (listen(sd, 5) < 0) { + (void)close(sd); + return(-1); + } + + return(sd); +} + + +/* + * Accept a connection from a server + * + * We accept a connection, but we won't know which server it is + * from until we get the configuration data from the server. We + * put the connection on a 'pending' queue and will assign it to + * a server when the config data arrives. + * + * Arguments: + * ls listening socket to accept from + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +scsp_server_accept(ls) + int ls; + +{ + int len, rc, sd; + struct sockaddr server_addr; + Scsp_pending *psp; + + /* + * Accept the new connection + */ + len = sizeof(server_addr); + sd = accept(ls, (struct sockaddr *)&server_addr, &len); + if (sd < 0) { + return(errno); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set non-blocking operation + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + (void)close(sd); + rc = errno; + } + + /* + * Put the new socket on the 'pending' queue + */ + psp = (Scsp_pending *) UM_ALLOC(sizeof(Scsp_pending)); + if (!psp) { + scsp_mem_err("scsp_server_accept: sizeof(Scsp_pending)"); + } + psp->sp_sock = sd; + LINK2TAIL(psp, Scsp_pending, scsp_pending_head, sp_next); + + return(0); +} + + +/* + * Read a server interface message from a socket + * + * Arguments: + * sd socket to read from + * + * Returns: + * msg pointer to message read + * 0 failure (errno has reason) + * + */ +Scsp_if_msg * +scsp_if_sock_read(sd) + int sd; + +{ + int len, rc; + char *buff = (char *)0; + Scsp_if_msg *msg; + Scsp_if_msg_hdr msg_hdr; + + /* + * Read the message header from the socket + */ + len = read(sd, (char *)&msg_hdr, sizeof(msg_hdr)); + if (len != sizeof(msg_hdr)) { + if (len >= 0) + errno = EINVAL; + goto socket_read_fail; + } + + /* + * Get a buffer and read the rest of the message into it + */ + buff = (char *)UM_ALLOC(msg_hdr.sh_len); + if (!buff) { + scsp_mem_err("scsp_if_sock_read: msg_hdr.sh_len"); + } + msg = (Scsp_if_msg *)buff; + msg->si_hdr = msg_hdr; + len = read(sd, &buff[sizeof(Scsp_if_msg_hdr)], + msg->si_len - sizeof(Scsp_if_msg_hdr)); + if (len != msg->si_len - sizeof(Scsp_if_msg_hdr)) { + if (len >= 0) { + errno = EINVAL; + } + goto socket_read_fail; + } + + /* + * Trace the message + */ + if (scsp_trace_mode & SCSP_TRACE_IF_MSG) { + scsp_trace("Received server I/F message:\n"); + print_scsp_if_msg(scsp_trace_file, msg); + scsp_trace("\n"); + } + + return(msg); + +socket_read_fail: + if (buff) + UM_FREE(buff); + return((Scsp_if_msg *)0); +} + + +/* + * Write a server interface message to a socket + * + * Arguments: + * sd socket to write to + * msg pointer to message to write + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +scsp_if_sock_write(sd, msg) + int sd; + Scsp_if_msg *msg; +{ + int len, rc; + + /* + * Trace the message + */ + if (scsp_trace_mode & SCSP_TRACE_IF_MSG) { + scsp_trace("Writing server I/F message:\n"); + print_scsp_if_msg(scsp_trace_file, msg); + scsp_trace("\n"); + } + + /* + * Write the message to the indicated socket + */ + len = write(sd, (char *)msg, msg->si_len); + if (len != msg->si_len) { + if (len < 0) + rc = errno; + else + rc = EINVAL; + } else { + rc = 0; + } + + return(rc); +} + + +/* + * Read data from a local server + * + * Arguments: + * ssp pointer to server block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_server_read(ssp) + Scsp_server *ssp; +{ + int rc; + Scsp_dcs *dcsp; + Scsp_if_msg *msg; + + /* + * Read the message + */ + msg = scsp_if_sock_read(ssp->ss_sock); + if (!msg) { + if (errno == EWOULDBLOCK) { + /* + * Nothing to read--just return + */ + return(0); + } else { + /* + * Error--shut down the server entry + */ + scsp_server_shutdown(ssp); + } + return(errno); + } + + /* + * Process the received message + */ + switch(msg->si_type) { + case SCSP_NOP_REQ: + /* + * Ignore a NOP + */ + break; + case SCSP_CACHE_RSP: + /* + * Summarize the server's cache and try to open + * connections to all of its DCSs + */ + scsp_process_cache_rsp(ssp, msg); + ssp->ss_state = SCSP_SS_ACTIVE; + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (scsp_dcs_connect(dcsp)) { + /* + * Connect failed -- the DCS may not + * be up yet, so we'll try again later + */ + HARP_TIMER(&dcsp->sd_open_t, + SCSP_Open_Interval, + scsp_open_timeout); + } + } + ssp->ss_state = SCSP_SS_ACTIVE; + break; + case SCSP_SOLICIT_RSP: + /* + * The server has answered our request for a particular + * entry from its cache + */ + dcsp = (Scsp_dcs *)msg->si_tok; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_SOL_RSP, (Scsp_msg *)0, + msg); + break; + case SCSP_UPDATE_REQ: + /* + * Pass the update request to the FSMs for all + * DCSs associated with the server + */ + if (ssp->ss_state == SCSP_SS_ACTIVE) { + for (dcsp = ssp->ss_dcs; dcsp; + dcsp = dcsp->sd_next) { + rc = scsp_cfsm(dcsp, SCSP_CIFSM_UPD_REQ, + (Scsp_msg *)0, msg); + } + } + break; + case SCSP_UPDATE_RSP: + /* + * Pass the update response to the FSM for the + * DCS associated with the request + */ + dcsp = (Scsp_dcs *)msg->si_tok; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_UPD_RSP, + (Scsp_msg *)0, msg); + break; + default: + scsp_log(LOG_ERR, "invalid message type %d from server", + msg->si_type); + return(EINVAL); + } + + UM_FREE(msg); + return(0); +} + + +/* + * Send a Cache Indication to a server + * + * Arguments: + * ssp pointer to server block block + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_send_cache_ind(ssp) + Scsp_server *ssp; +{ + int rc; + Scsp_if_msg *msg; + + /* + * Get storage for a server interface message + */ + msg = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!msg) { + scsp_mem_err("scsp_send_cache_ind: sizeof(Scsp_if_msg)"); + } + UM_ZERO(msg, sizeof(Scsp_if_msg)); + + /* + * Fill out the message + */ + msg->si_type = SCSP_CACHE_IND; + msg->si_rc = 0; + msg->si_proto = ssp->ss_pid; + msg->si_len = sizeof(Scsp_if_msg_hdr); + msg->si_tok = (u_long)ssp; + + /* + * Send the message + */ + rc = scsp_if_sock_write(ssp->ss_sock, msg); + UM_FREE(msg); + return(rc); +} + + +/* + * Read data from a pending server connection + * + * Arguments: + * psp pointer to pending block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_pending_read(psp) + Scsp_pending *psp; + +{ + int rc; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_if_msg *msg; + + /* + * Read the message from the pending socket + */ + msg = scsp_if_sock_read(psp->sp_sock); + if (!msg) { + rc = errno; + goto pending_read_fail; + } + + /* + * Make sure this is configuration data + */ + if (msg->si_type != SCSP_CFG_REQ) { + scsp_log(LOG_ERR, "invalid message type %d from pending server", + msg->si_type); + rc = EINVAL; + goto pending_read_fail; + } + + /* + * Find the server this message is for + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (strcmp(ssp->ss_intf, msg->si_cfg.atmarp_netif) == 0) + break; + } + if (!ssp) { + scsp_log(LOG_ERR, "refused connection from server for %s", + msg->si_cfg.atmarp_netif); + rc = EINVAL; + goto config_reject; + } + + /* + * Make sure the server is ready to go + */ + rc = scsp_get_server_info(ssp); + if (rc) { + goto config_reject; + } + + /* + * Save the socket + */ + ssp->ss_sock = psp->sp_sock; + ssp->ss_state = SCSP_SS_CFG; + UNLINK(psp, Scsp_pending, scsp_pending_head, sp_next); + UM_FREE(psp); + + /* + * Listen for connections from the server's DCSs + */ + rc = scsp_dcs_listen(ssp); + if (rc < 0) { + rc = errno; + goto config_reject; + } + + /* + * Respond to the configuration message + */ + msg->si_type = SCSP_CFG_RSP; + msg->si_rc = SCSP_RSP_OK; + msg->si_len = sizeof(Scsp_if_msg_hdr); + rc = scsp_if_sock_write(ssp->ss_sock, msg); + if (rc) { + goto config_error;; + } + + /* + * Ask the server to send us its cache + */ + rc = scsp_send_cache_ind(ssp); + if (rc) { + goto config_error; + } + + UM_FREE(msg); + return(0); + +config_reject: + /* + * Respond to the configuration message + */ + msg->si_type = SCSP_CFG_RSP; + msg->si_rc = SCSP_RSP_REJ; + msg->si_len = sizeof(Scsp_if_msg_hdr); + (void)scsp_if_sock_write(ssp->ss_sock, msg); + +config_error: + if (ssp->ss_sock != -1) { + (void)close(ssp->ss_sock); + ssp->ss_sock = -1; + } + if (ssp->ss_dcs_lsock != -1) { + (void)close(ssp->ss_dcs_lsock); + ssp->ss_sock = -1; + } + ssp->ss_state = SCSP_SS_NULL; + UM_FREE(msg); + + return(rc); + +pending_read_fail: + /* + * Close the socket and free the pending read block + */ + (void)close(psp->sp_sock); + UNLINK(psp, Scsp_pending, scsp_pending_head, sp_next); + UM_FREE(psp); + if (msg) + UM_FREE(msg); + return(rc); +} |