/* 
 * $Id: util.c,v 1.11 90/08/06 11:36:34 qjb Exp $
 * $Source: /afs/athena.mit.edu/user/q/qjb/source/qrpc/src/RCS/util.c,v $
 * $Author: qjb $
 *
 * This file contains utilities for the qrpc library. 
 */

#if !defined(lint) && !defined(SABER) && !defined(RCS_HDRS)
static char *rcsid = "$Id: util.c,v 1.11 90/08/06 11:36:34 qjb Exp $";
#endif /* lint || SABER || RCS_HDRS */

#include <stdio.h>
#include <strings.h>

#include "qrpc.h"
#include "qrpc_private.h"

/*
 * The following for routines translate 16 and 32 bit quantities to
 * and from arrays of bytes for sending across the network.  They put
 * the quantities in network byte order (MSB first) , though they do
 * this by hand (rather than with htons, htonl, ntohs, and ntohl) to
 * avoid dependence on shorts being 16 bits and longs being 32 bits.
 */

#ifdef __STDC__
qrpc_error_t qrpci_ushort_to_bit16(u_short s, bit16 b)
#else
qrpc_error_t qrpci_ushort_to_bit16(s, b)
  u_short s;
  bit16 b;
#endif /* __STDC__ */
{
    b[1] = (u_char)s;
    b[0] = (u_char)(s >> 8);
    return (QRPC_SUCCESS);
}

#ifdef __STDC__
qrpc_error_t qrpci_ulong_to_bit32(u_long l, bit32 b)
#else
qrpc_error_t qrpci_ulong_to_bit32(l, b)
  u_long l;
  bit32 b;
#endif /* __STDC__ */
{
    b[3] = (u_char)l;
    b[2] = (u_char)(l >> 8);
    b[1] = (u_char)(l >> 16);
    b[0] = (u_char)(l >> 24);
    return (QRPC_SUCCESS);
}

#ifdef __STDC__
qrpc_error_t qrpci_bit16_to_ushort(bit16 b, u_short *s)
#else
qrpc_error_t qrpci_bit16_to_ushort(b, s)
  bit16 b;
  u_short *s;
#endif /* __STDC__ */
{
    *s = b[1] + (b[0] << 8);
    return (QRPC_SUCCESS);
}

#ifdef __STDC__
qrpc_error_t qrpci_bit32_to_ulong(bit32 b, u_long *l)
#else
qrpc_error_t qrpci_bit32_to_ulong(b, l)
  bit32 b;
  u_long *l;
#endif /* __STDC__ */
{
    *l = b[3] + (b[2] << 8) + (b[1] << 16) + (b[0] << 24);
    return (QRPC_SUCCESS);
}

#ifdef __STDC__
char *qrpc_error_string(qrpc_t qrpc, qrpc_error_t error)
#else
char *qrpc_error_string(qrpc, error)
  qrpc_t qrpc;
  qrpc_error_t error;
#endif /* __STDC__ */
{
    extern char *error_message();

    if (qrpc == NULL) 
	return (error_message(error));
    else 
	return (qrpc->errmsg);
}

	
#ifdef __STDC__
void qrpc_print_error(qrpc_t qrpc, qrpc_error_t error)
#else
void qrpc_print_error(qrpc, error)
  qrpc_t qrpc;
  qrpc_error_t error;
#endif /* __STDC__ */
{
    qrpc->error_fn(qrpc_error_string(qrpc, error));
}


#ifdef __STDC__
void qrpc_error_exit(qrpc_t qrpc, qrpc_error_t error, qrpc_byte exitstatus)
#else
void qrpc_error_exit(qrpc, error, exitstatus)
  qrpc_t qrpc;
  qrpc_error_t error;
  qrpc_byte exitstatus;
#endif /* __STDC__ */
{
    char *string;
    int i;

    string = qrpc_error_string(qrpc, error);
    qrpc->error_fn(string);

    /* 
     * Drop the connection unless the error is QRPC_ERR_REMOTE.  If it
     * is, we've been dropped.  Dropping in return will result in a
     * broken pipe.
     */       
    if (error != QRPC_ERR_REMOTE) {
	/* 
	 * If this is a listener, drop all connections.  Otherwise,
	 * it is a connection, so drop it.
	 */
	if (qrpc->listen_info) {
	    for (i = 0; qrpc->listen_info->accepted[i]; i++)
		qrpc_drop(qrpc->listen_info->accepted[i], string);
	}
	else
	    qrpc_drop(qrpc, string);
    }

    if (qrpc->listen_info) 
	for (i = 0; qrpc->listen_info->accepted[i]; i++)
	    qrpc_destroy(&(qrpc->listen_info->accepted[i]));

    qrpc_destroy(&qrpc);

    exit(exitstatus);
}


#ifdef __STDC__
void qrpc_set_error_fn(qrpc_t qrpc, qrpc_error_fn_t error_fn)
#else
void qrpc_set_error_fn(qrpc, error_fn)
  qrpc_t qrpc;
  qrpc_error_fn_t error_fn;
#endif /* __STDC__ */
{
    if (error_fn == NULL)
	qrpc->error_fn = qrpc->default_error_fn;
    else
	qrpc->error_fn = error_fn;
}


#ifdef __STDC__
qrpc_error_t qrpci_send_success(qrpc_t qrpc)
#else
qrpc_error_t qrpci_send_success(qrpc)
  qrpc_t qrpc;
#endif /* __STDC__ */
{
    return(qrpci_send_packet(qrpc, QRPC_OP_STATUS, (qrpc_data_t) "", 0));  
}


#ifdef __STDC__
qrpc_error_t qrpci_send_error(qrpc_t qrpc, char *error)
#else
qrpc_error_t qrpci_send_error(qrpc, error)
  qrpc_t qrpc;
  char *error;
#endif /* __STDC__ */
{
    return(qrpci_send_packet(qrpc, QRPC_OP_STATUS, (qrpc_data_t) error,
			     (qrpc_length_t) strlen(error)));
}    


#ifdef __STDC__
qrpc_error_t qrpci_recv_status(qrpc_t qrpc, qrpc_data_t msg, 
			      qrpc_length_t *length)
#else 
qrpc_error_t qrpci_recv_status(qrpc, msg, length)
  qrpc_t qrpc;
  qrpc_data_t msg;
  qrpc_length_t *length;
#endif /* __STDC__ */
{
    return(qrpci_recv_packet(qrpc, QRPC_OP_STATUS, msg, length));
}


#ifdef __STDC__
qrpc_error_t qrpc_is_client(qrpc_t qrpc, qrpc_byte *val)
#else
qrpc_error_t qrpc_is_client(qrpc, val)
  qrpc_t qrpc;
  qrpc_byte *val;
#endif /* __STDC__ */
{
    switch (qrpc->client_or_server) {
      case QRPC_IS_CLIENT:
	*val = TRUE;
	break;
      case QRPC_IS_SERVER:
	*val = FALSE;
	break;
      default:
	sprintf(qrpc->errmsg, 
		"qrpc_is_client detects illegal client_or_server value (%d)",
		qrpc->client_or_server);
	return (QRPC_ERR_INTERNAL);
    }

    return (QRPC_SUCCESS);
}


#ifdef __STDC__
qrpc_error_t qrpc_is_server(qrpc_t qrpc, qrpc_byte *val)
#else
qrpc_error_t qrpc_is_server(qrpc, val)
  qrpc_t qrpc;
  qrpc_byte *val;
#endif /* __STDC__ */
{
    switch (qrpc->client_or_server) {
      case QRPC_IS_CLIENT:
	*val = FALSE;
	break;
      case QRPC_IS_SERVER:
	*val = TRUE;
	break;
      default:
	sprintf(qrpc->errmsg, 
		"qrpc_is_server detects illegal client_or_server value (%d)",
		qrpc->client_or_server);
	return (QRPC_ERR_INTERNAL);
    }

    return (QRPC_SUCCESS);
}

#ifdef __STDC__
void qrpci_dprint(qrpc_t qrpc, char *string)
#else
void qrpci_dprint(qrpc, string)
  qrpc_t qrpc;
  char *string;
#endif /* __STDC__ */
{
    extern int qrpc_debug;

    if (qrpc_debug) 
	qrpc->error_fn(string);
}
