📄 rsvptrace.c
字号:
/* * @(#) $Id: rsvptrace.c,v *//******************************************************************** * * rsvptrace - trace RSVP state over reverse path * * Written by: Subramaniam Vincent (svincent@isi.edu) * USC Information Sciences Institute * Marina del Rey, California * April 1997 * * Copyright (c) 1997 by the University of Southern California * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation in source and binary forms for non-commercial purposes * and without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both the copyright notice and * this permission notice appear in supporting documentation. and that * any documentation, advertising materials, and other materials related * to such distribution and use acknowledge that the software was * developed by the University of Southern California, Information * Sciences Institute. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about * the suitability of this software for any purpose. THIS SOFTWARE IS * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Other copyrights might apply to parts of this software and are so * noted when applicable. * ********************************************************************//* rsvptrace.c * * This utility is intended to trace rsvp state from a specific starting * hop called last hop, along the reverse path towards a specific sender. * * Currently reservation and path (sender) state are collected for a session. * * rsvptrace sends a UDP Diagnostic Request packet to a "Last-hop" rsvp router to * start the trace. rsvptrace gathers the replies, and prints them out. */#include "rsvp_daemon.h"#define tvsub(A, B) (A)->tv_sec -= (B)->tv_sec ;\ if (((A)->tv_usec -= (B)->tv_usec) < 0) {\ (A)->tv_sec-- ;\ (A)->tv_usec += 1000000 ; }#define tvGEQ(A,B) ( (A)->tv_sec > (B)->tv_sec || \ ( (A)->tv_sec == (B)->tv_sec && (A)->tv_usec >= (B)->tv_usec))#define tvadd(A, B) (A)->tv_sec += (B)->tv_sec ;\ if (((A)->tv_usec += (B)->tv_usec) > 1000000) {\ (A)->tv_sec++ ;\ (A)->tv_usec -= 1000000 ; }#define UCAST_TTL 63/* DIAG_DEF_TIMEOUT : 10 seconds * Reply wait time for timeouts : If first reply comes within * the specified timeout or the default value, we * wait an equal amount of time for all the other replies. * Each time we timeout waiting, increase timeout interval * exponentially. * * DIAG Retransmit count : 3 times * */#define DIAG_DEF_TIMEOUT 10#define DIAG_RETRY_COUNT 3/* NTP timestamp related */#define JAN_1970 2208988800UL#define iptoname(x) (IP_NumOnly ? net_inaddr_print((char *) (x),AF_INET) : net_inaddr_host((char *) (x),AF_INET))/* external declarations */int net_init_udp_only(net_addr *);char *fmt_filtspec(), *fmt_flowspec(), *fmt_tspec();/* forward declarations */int init_diag();int send_diag_request(struct packet *); int trace_prepare(struct packet *);int trace_accept_reply(struct packet *, net_addr *);int trace_print_status(int ,int );int trace_waitfor_replies(struct timeval *, int *);int trace_input();int next_wait(struct timeval *, int, struct timeval *);int do_sendmsg(int, net_addr *, net_addr *, int, u_char, u_char *, int);int do_sendto(net_addr *, net_addr *, u_char *data, int len, u_char ttl);u_long get_time_constant();char *time_stamp(struct timeval *);enum exitcode { DIAG_ALL_RECVD, DIAG_SOME_RECVD, DIAG_NONE_RECVD};typedef struct diag_request { SESSION_ipv4 rsvp_dsess; net_addr sender; net_addr last_hop; u_int16_t path_mtu ;#define DIAG_DEF_PATH_MTU 1400 u_char max_hops;#define DIAG_DEF_MAX_HOPS 10 u_char H; #define DIAG_REPLY_DIRECT 0#define DIAG_REPLY_HBH 1 net_addr resp_to ; struct packet req_pkt; u_char status; u_int32_t curr_id; /* latch for message id of first received reply */ u_int32_t timeout; /* retransmit timeout for diag requests */ u_char rcount;} diag_req_t ;/* Global control */static int IP_NumOnly ;int Max_rsvp_msg ;diag_req_t diag_req ;char recv_buff[MAX_PKT]; char *version = "R1.0 April 10th 1997";char *Usage_text = "\Usage: rsvptrace [-h<hops>] [-H] [-L<Last-hop addr>] [-m<path mtu>]\n\ [-s<timeout>] [-{U|T|p <proto#>}] [-n]\n\ <sess addr/port> <sender addr/port>\n"; intmain(argc, argv) int argc ; char **argv ; { u_int c, ss = 0; u_char parse_fail = 0; char *tp ; u_long host, addr; u_int16_t port; int mode = 0, count = 0; struct in_addr iaddr; struct timeval tsent; struct timezone tz; /* * Process command-line options */ if (argc < 2) { fprintf(stderr,Usage_text); exit(-1); }/* Initialize diagnostics */ (void)init_diag(); for (c = 1; c < argc ; c++) { if (argv[c][0] == '-') { switch(argv[c][1]) { case 's': /* -s<timeout> -- wait time in seconds for first * retransmit */ if((diag_req.timeout = (u_int32_t)atoi(&argv[c][2])) <= 0) parse_fail = 1; break; case 'h': /* -h<hops> -- max RSVP hops to traverse */ if((diag_req.max_hops = (u_char)atoi(&argv[c][2])) <= 0) parse_fail = 1; break; case 'n': /* -n -- Noconversion of host addrs to names */ IP_NumOnly = 1; break; case 'H': /* -H -- specifies HBH reply mode */ diag_req.H = DIAG_REPLY_HBH ; break ; case 'm': /* -m<path_mtu> -- max diag pkt size for trim/forward */ if ((diag_req.path_mtu = atoi(&argv[c][2])) <= 0) parse_fail = 1; break; case 'L': /* -L<Last-hop> -- RSVP router to start diagnosis from */ if( (addr = resolve_name(&argv[c][2])) <= 0) parse_fail = 1; else NET_GET_ADDR_UDP_IPv4(&diag_req.last_hop).sin_addr.s_addr = addr; break; case 'T': /* -U -- session type is TCP, UDP is the default */ diag_req.rsvp_dsess.sess_protid = IPPROTO_TCP; break ; case 'U': /* -U -- session type is UDP, this is the default */ diag_req.rsvp_dsess.sess_protid = IPPROTO_UDP; break ; case 'p': /* -p<proto> -- session type is IPPROTO_<proto> */ if((diag_req.rsvp_dsess.sess_protid = atoi(&argv[c][2])) <= 0) parse_fail = 1; break ; default: fprintf(stderr, Usage_text); exit(1) ; } } else { /* Parse in the sess addr/port & sender addr/port, in that order. * sess addr/port MUST come first, * and these two arguments MUST be the last arguments * Variable 'ss' tracks sess and sender info */ if ((tp = strpbrk(argv[c],":/"))) { *tp = '\0'; if ((port = hton16((u_int16_t)atoi(tp+1))) <= 0) parse_fail = 1; } else parse_fail = 1; if((host = resolve_name(argv[c])) <= 0) parse_fail = 1; if (ss == 0) { /* sess addr/port */ diag_req.rsvp_dsess.sess_destaddr.s_addr = host ; diag_req.rsvp_dsess.sess_destport = port ; ss++; } else if (ss == 1) { /* sender addr/port */ iaddr.s_addr = host; NET_SET_ADDR3_UDP_IPv4(&diag_req.sender,iaddr,port); ss++; } else parse_fail = 1; } } if (parse_fail || ss != 2) { fprintf(stderr, Usage_text); exit(1) ; } (void)trace_prepare(&diag_req.req_pkt); printf("Rsvptrace from %s ", iptoname(&(NET_GET_ADDR_UDP_IPv4(&diag_req.last_hop).sin_addr))); printf("to %s/%d ", iptoname(&(NET_GET_ADDR_UDP_IPv4(&diag_req.sender).sin_addr)), ntoh16(NET_GET_ADDR_UDP_IPv4(&diag_req.sender).sin_port)); printf("for session %s/%d\n",iptoname(&diag_req.rsvp_dsess.sess_destaddr), ntoh16(diag_req.rsvp_dsess.sess_destport)); printf("Querying reverse path..."); if (diag_req.H) printf("for hop by hop replies\n"); else printf("\n"); printf("Timeout in %d seconds...\n",diag_req.timeout); mode = send_diag_request(&diag_req.req_pkt); if (mode < 0) { perror("??"); exit(-1); } if (gettimeofday(&tsent,&tz) < 0) { perror("get time error "); exit(-1); } mode = trace_waitfor_replies(&tsent,&count);/* if we come here, we must be done */ (void)trace_print_status(mode,count); net_final(); return 0;}/* trace_print_status(): * * Called to print a summary line, at the end of a trace. */inttrace_print_status(int mode,int count) { switch(mode) { case DIAG_ALL_RECVD : /*printf("\n%d replies received\n",count);*/ break ; case DIAG_NONE_RECVD : assert(count == 0); printf("\nno replies received, timed out\n"); break; case DIAG_SOME_RECVD : assert(count > 0); printf("\n%d replies received, fragments due, but timed out\n",count); break ; default : assert(0); } return 0;}/* send_diag_request(): * sends a diagnostic request packet, that has already been built. * increments the message ID for each send. */int send_diag_request(struct packet * pkt) { /* * TTL setup is only for unicast packets. If this was a * diagnostics reply to a multicast address, ttl would have * already been set. */ if(!IN_IS_ADDR_MULTICAST(&NET_GET_ADDR_IPv4(&diag_req.last_hop))) pkt->pkt_ttl = UCAST_TTL; pkt->pkt_flags |= PKTFLG_NOENCAP ; pkt->pkt_map->rsvp_diag->diag_msgID++; return(build_send_pkt(-1, &diag_req.last_hop, NULL, &diag_req.req_pkt));} /* trace_waitfor_replies() * * A sort of dispatcher for diagnostics. * After the first DREQ is sent, this routine in called. * Retransmits, timeout interval adjustments are done here. */int trace_waitfor_replies(struct timeval *snt_tv, int *num) { struct timeval t_intvl; struct timeval t_recv, t_sent; struct timezone tz; fd_set rd_fds; int waittime = diag_req.timeout; int fd_wid, rc, wait; u_char rcount = 0, retr = 0, done = 0; t_sent = *snt_tv ; /* local copy */ wait = waittime; /* initialize wait to waittime *//* wait for "reply or multiple reply" I/O dispatcher loop */ (void)next_wait(&t_sent,wait,&t_intvl); fd_wid = getdtablesize(); while (!done) { net_poll_list(&rd_fds); rc = select(fd_wid,&rd_fds,(fd_set *)NULL,(fd_set *)NULL, &t_intvl); if (rc < 0) { assert(errno == EINTR); continue; } /* handle timeouts */ if (rc == 0) { if(rcount > 0) /* fragment receive timeout, * finish trace and exit */ return DIAG_SOME_RECVD ; if(rcount == 0 && retr == DIAG_RETRY_COUNT) /* No replies at all, and max * retransmits done */ return DIAG_NONE_RECVD ; /* retransmit the DREQ packet */ rc = send_diag_request(&diag_req.req_pkt); if (rc < 0) exit (-1) ; else { /* wait time for DREQ retransmit * goes up exponentially with * retransmits, for now. * {5,10,20} seconds, is the wait * time sequence. */ (void)gettimeofday(&t_sent,&tz); retr++; wait = 2*wait; /*(void)next_wait(&t_sent,((int)(retr+1)*waittime),&t_intvl); */ (void)next_wait(&t_sent,wait,&t_intvl); printf("* ");fflush(stdout); continue ; } } /* If we come here then we have a reply. * The status'es ALL_RECVD and SOME_RECVD * will be set while processing by * trace_accept_reply(). */ (void)gettimeofday(&t_recv,&tz); rc = trace_input(); if (rc == 0) *num = ++rcount; else /* Some invalid reply was received, so continue */ if (rc > 0) continue; /* In case there are more fragments and/or the * the udp read failed, continue waiting till * end of timeout. If the read succeeded for * an intermediary reply, but it had a parse error, * we will not know that and just wait till * timeout. */ if (diag_req.status == DIAG_SOME_RECVD || rc == -1) { tvsub(&t_recv,&t_sent); assert(1 == tvGEQ(&t_intvl,&t_recv)); tvsub(&t_intvl,&t_recv); } else /* if the first reply had some corruption/parse error, * we will not know if there are any more replies, so * we quit. */ done = 1; } return 0;}/* trace_input() * * Receive a UDP RSVP message, right now a diag reply. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -