/* ************************************************************************** * * Component: RDBG * Module: servtsp.c * * Synopsis: Transport management for remote debug server. * * $Id$ * ************************************************************************** */ #include #include #include #include #include #include #include #include static int out_sock; static int warm_test; static void TimeTestHandler (); /* * TspInit - Initialize the transport system. * */ void TspInit (int id) { struct sigaction sa; struct sockaddr_in addr; /* * 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 */ } memset ((void *) (&addr), 0, 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. %ld)\n", taskName, msg.type, conn, cnt, (long int) 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 */ }