summaryrefslogblamecommitdiffstats
path: root/c/src/librdbg/src/servtsp.c
blob: db342d58f9043f28bbb4d01013fe6a8a8b95b37e (plain) (tree)
1
2
3
4
5
6
7
8
9
10







                                                                           

       
































































































































































































































































































































                                                                                
/*
 **************************************************************************
 *
 *  Component:	RDBG
 *  Module:	servtsp.c
 *
 *  Synopsis:	Transport management for remote debug server.
 *
 * $Id$
 *
 **************************************************************************
 */

#include <sys/errno.h>
#include <rdbg/rdbg.h>	
#include <rdbg/servrpc.h>
#include <signal.h>		
#include <rpc/rpc.h>		
#include <rpc/svc.h>		
#include <netinet/in.h>		
#include <sys/socket.h>		

static int	out_sock;	
static int	warm_test;	

static void TimeTestHandler();	

    /*
     *  TspInit - Initialize the transport system.
     *
     */

    void
TspInit (int id)
{
    struct sigaction sa;

	/* setup a socket to send event messages back through */
    out_sock = socket (PF_INET, SOCK_DGRAM, 0);
    if (out_sock < 0) {
	DPRINTF (("TspInit: socket() failed %d errno %d\n",
		out_sock, getErrno()));
	return;		/* failed to open socket, let caller deal with */
    }
    {
	struct sockaddr_in addr;

	bzero ((void *)(&addr), sizeof addr);
	addr.sin_family = AF_INET;
	addr.sin_port = htons (BackPort);
	if (bind (out_sock, (struct sockaddr*) &addr, sizeof addr) < 0) {
	    DPRINTF (("TspInit: bind() failed\n"));
	}
    }
    /* setup alarm timer for warm testing */
    memset (&sa, 0, sizeof (sa));
    sa.sa_handler = TimeTestHandler;
    sigaction (SIGALRM, &sa, 0);
}

    /*
     *  TspTranslateRpcAddr - translate from an RPC handle to an
     *                        opaque address.
     *
     *  Converts the sender's address into the opaque data structure
     *  used for network addresses. This is used to look up the sender
     *  on each call.
     */

    Boolean
TspTranslateRpcAddr (struct svc_req* rqstp, NET_OPAQUE* opaque)
{
    struct sockaddr_in*	addr;	/* used as template to extract net info */
    unsigned char*	up;

    memset (opaque, 0, sizeof (NET_OPAQUE));
	/*
	 *  We interpret the remote address as a standard netbuf name.
	 *  The format is 2 bytes of address family (normally AF_INET)
	 *  and then a length (5) and then the IP address.
	 */
    if (rqstp->rq_xprt->xp_addrlen != 16)
    {
	DPRINTF (("TspTranslateRpcAddr: Unknown remote address!!!\n"));
	setErrno (EPROTONOSUPPORT);
	return False;		/* invalid, so fails */
    }
	/* addr = &rqstp->rq_xprt->xp_raddr; */
    addr = svc_getcaller (rqstp->rq_xprt);
	/* verify it is AF_INET */
    if (addr->sin_family != AF_INET) {		/* no, error */
	DPRINTF (("TspTranslateRpcAddr: Not an internet address!!\n"));
	setErrno (EAFNOSUPPORT);/* invalid addr family */
	return False;
    }
	/* good address type */
    up = (unsigned char *) &addr->sin_addr.s_addr;
    DPRINTF (("TspTranslateRpcAddr: Sent by %u.%u.%u.%u port #%u\n",
	up[0], up[1], up[2], up[3], htons (addr->sin_port)));
    memcpy (opaque, addr, sizeof (struct sockaddr_in));
    return True;
}

    /*
     *  TspValidateAddr - validate a passed in opaque address.
     *
     *  Checks that the passed in address is in the format
     *  expected.
     */

    Boolean
TspValidateAddr (NET_OPAQUE* opaque, NET_OPAQUE* sender)
{
    struct sockaddr_in*	addr;	/* used as template to extract net info */

    addr = (struct sockaddr_in*) opaque;
	/* Verify it is AF_INET. Should check against sender IP address too */
    if (addr->sin_family != AF_INET) {
	DPRINTF (("TspValidateAddr: Back port invalid: %d\n",
	    htons (addr->sin_port)));
	return False;		/* not valid */
    }
	/* otherwise, we copy in the IP address, since client may not know it */
    addr->sin_addr.s_addr = ((struct sockaddr_in*) sender)->sin_addr.s_addr;
    DPRINTF (("TspValidateAddr: Back port is %d\n", htons (addr->sin_port)));
    return True;
}

    /*
     *  TspConnGetIndex - lookup an rpc caller's address as a connection entry.
     *
     *  Looks up an ip address of a caller to locate the
     *  connection index in our connection array.
     */

    int
TspConnGetIndex (struct svc_req* rqstp)
{
    int		conn;
	/* &rqstp->rq_xprt->xp_raddr; */
    struct sockaddr_in *addr = svc_getcaller (rqstp->rq_xprt);

    for (conn = 0; conn < conn_list_cnt; conn++) {
	if (!conn_list[conn].in_use)
	    continue;			/* not used */

	if (addr->sin_addr.s_addr == ((struct sockaddr_in *)
		&conn_list [conn].sender)->sin_addr.s_addr
		&&  addr->sin_port == ((struct sockaddr_in *)
		&conn_list[conn].sender)->sin_port) {
	    return conn;
	}
    }
    return -1;
}


    /*
     *  TspSendWaitChange - send wait-change message to clients to
     *                      notify change.
     */

    void
TspSendWaitChange(
    int		conn,		/* connection to send to */
    BACK_MSG	msg,		/* BMSG type */
    UINT16	spec,		/* special information */
    PID		pid,		/* pid it refers to */
    UINT32	context,	/* additional context for message */
    Boolean	force)		/* force into being only message */
{
    int			idx;
    struct SEND_LIST*	snd_ptr;

    if (force) {
	    /* force to top, which means others gone */
	idx = 0;
	conn_list [conn].send_idx = 1;
	conn_list[conn].retry = 0;
    } else {
	for (idx = 0; idx < (int) conn_list[conn].send_idx; idx++) {
	    if (conn_list[conn].send_list[idx].send_type == msg
		&&  conn_list[conn].send_list[idx].pid == pid)
	    return;			/* already pended for this pid */
	}
	idx = conn_list[conn].send_idx;
	if (idx+1 > MAX_SEND)
	    return;			/* we lose it, what should we do??? */
	conn_list[conn].send_idx++;
    }
    snd_ptr = &conn_list[conn].send_list[idx];
    snd_ptr->send_type = msg;		/* message to send */
    snd_ptr->retry = TSP_RETRIES;	/* about 1 minute of retries */
    snd_ptr->spec = htons ((u_short) spec);
    snd_ptr->pid = htonl (pid);
    snd_ptr->context = htonl (context);
    TspSendMessage (conn, False);	/* now do the send */
}

    /*
     *  TspSendMessage - send message at top of send list for connection.
     */

    void
TspSendMessage( int conn, Boolean resend)
{
    struct sockaddr_in	addr;
    struct UDP_MSG	msg;
    int			cnt;

    if (!resend && conn_list[conn].retry)
	return;			/* already waiting for reply */

	/*
	 *  Note on above: if no back port we can't remove unless
	 *  someone blows off.
	 */
    if (!resend) {
	    /* first time, setup. Set retry count: */
	conn_list[conn].retry = conn_list[conn].send_list[0].retry;
	conn_list[conn].last_msg_num++; /* new sequence number */
	if (!warm_test++) { 		/* starting, so enable timer */
	    alarm (2);			/* resend every 2 seconds as needed */
	}
    }

    msg.type	= conn_list[conn].send_list[0].send_type;
    msg.msg_num	= conn_list[conn].last_msg_num;
    msg.spec	= conn_list[conn].send_list[0].spec;
    msg.pid	= conn_list[conn].send_list[0].pid;
    msg.context	= conn_list[conn].send_list[0].context;

    memset (&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = ((struct sockaddr_in*)&conn_list[conn].back_port)->sin_port;
    addr.sin_addr.s_addr = 
	((struct sockaddr_in*)&conn_list[conn].back_port)->sin_addr.s_addr;

    DPRINTF (("TspSendMessage: Sending msg %d (%s) to port %d\n",
	msg.type, BmsgNames [msg.type], HL_W (addr.sin_port)));

    cnt = sendto (out_sock, &msg, sizeof msg, 0, (struct sockaddr*) &addr,
		    sizeof addr);
    if (cnt != sizeof msg) {		/* failed on send */
	printf ("%s: Failed to send msg %d to conn %d (%d vs. %d)\n",
	    ActName, msg.type, conn, cnt, sizeof msg);
    }
}

    /*
     *  TspMessageReceive - confirmation received, now send next if any.
     *
     *  - since UDP is connectionless, we batch up the sends and use
     *    one at a time until we get a message indicating ready for
     *    next (from ack).
     */

    void
TspMessageReceive (int conn, PID pid)
{
	/* We remove the send list entry and use next if any */
    conn_list[conn].retry = 0;	/* reset */
    if (!warm_test || !--warm_test) {
	alarm (0);			/* reset timer if not used */
    }
#ifdef DDEBUG
    if (conn_list[conn].send_list[0].send_type == BMSG_WARM) {
	DPRINTF (("TspMessageReceive: Connection reset for conn %d\n", conn));
    }
#endif
	/* Move up by one if needed */
    if (!--conn_list[conn].send_idx)
	return;			/* no more to do */

    memcpy (conn_list[conn].send_list, conn_list[conn].send_list+1,
	conn_list[conn].send_idx * sizeof(struct SEND_LIST)); /* copy down */
    TspSendMessage (conn, 0);
}

    /*
     *  TspGetHostName - return client's host name.
     *
     *  - this routine returns the name of the client's host or the net
     *    number of unknown.
     */

    char*
TspGetHostName (conn_idx)
    int		conn_idx;	/* client connection number */
{
    static char		buff [30];	/* largest net num */
    unsigned char*	cp;

    cp = conn_list[conn_idx].sender.c+4;
    sprintf (buff, "%u.%u.%u.%u", cp[0], cp[1], cp[2], cp[3]);
    return buff;
}

    /*
     *  TimeTestHandler - alarm timer handler to resend warm/wait test.
     */

    static void
TimeTestHandler()
{
    int		conn;

    if (!warm_test)
	return;			/* no longer enabled */

    for (conn = 0; conn < conn_list_cnt; conn++) {	
	    /* locate all that are using this */
	if (!conn_list[conn].in_use)
	    continue;			/* not used */

	if (!conn_list[conn].retry) continue;
	    /* found one that we are testing */
	if (!--conn_list[conn].retry) {
		/*
		 *  Counted down the retries: blow off.
		 *  Need to have connection flag to indicate not blowing
		 *  off for cases where client is stopped due to being
		 *  debugged.
		 */
	    ConnDelete (conn, NULL, CLOSE_IGNORE);
	    continue;
	}
	TspSendMessage (conn, True);	/* send another message */
    }
    alarm (2);			/* setup for 2 seconds from now */
}