1
0
Files
irix-657m-src/eoe/cmd/bsd/rsvp/tools/rtap_cmds.c
2022-09-29 17:59:04 +03:00

1536 lines
36 KiB
C

/*
* rtap -- RealTime Application Program: Test program for RSVP
*
* rtap_cmds.c: Body of program
*
*
* This file contains the common elements are rtap that are needed
* when rtap is either integral with rsvpd or a separate process.
* Thus, it includes command parsing, command execution, and the
* RSVP API rapi_xxx interface calls.
*
* Separate process: rtap = rtap_main.c + rtap_cmds.c
*
* Integral with rsvpd: rtap = rsvp_rtap.c + rtap_cmds.c +
* <hooks in rsvp_main.c>
*
* Written by Bob Braden, ISI
*/
/*******************************************************************
Copyright (c) 1996 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 any purpose and without
fee is hereby granted, provided that both the above copyright notice
and this permission notice appear in all copies. and that any
documentation, advertising materials, and other materials related to
such distribution and use acknowledge that the software was developed
in part 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.
********************************************************************/
#include "config.h" /* must come first */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <math.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <cap_net.h>
#include "rapi_lib.h"
#include "rapi_err.h"
#include "rsvp.h"
#include "rsvp_api.h" /* To include management interface */
#ifdef INCLUDE_SYSTEM_H
#include "system.h"
int printf(), strcasecmp();
#endif
#include "Pm_parse.h"
#define show_help(op) printf(cmd_table[op].cmd_help)
#define RAPI_OBJLEN(objp) ( (*(int *) objp)? *(int *)objp : sizeof(int))
/* Define standard header for an area to hold vector of variable-length
* flowspecs, filterspecs, etc.
*/
typedef struct {
short area_size; /* total size of area */
short area_offset; /* Offset of next available space in area */
int area_cnt; /* Number of objects in area */
} area_t;
area_t *init_Area(area_t **, int size);
char *Area_offset(area_t *);
void Cat_Area(area_t *orig, rapi_hdr_t *new);
#define Area_Data(cast, p) (cast ((p)? (rapi_hdr_t *) (p)+1: NULL))
/*
* Forward & External Declarations
*/
void rtap_sleep(int), rtap_sleepdone();
void rapi_fmt_flowspec(rapi_flowspec_t *, char *, int);
void rapi_fmt_tspec(rapi_tspec_t *, char *, int);
void rapi_fmt_adspec(rapi_adspec_t *, char *, int);
void rapi_fmt_filtspec(rapi_filter_t *, char *, int);
void Send_data(void);
int Do_Command(char *, FILE *);
void saddr_to_rapi_filt(struct sockaddr_in *, rapi_filter_t *);
int pfxcmp(char *, char *);
void print_errno(char *, int);
void print_status(void);
void Set_Recv(struct sockaddr_in *, struct sockaddr_in *);
void Set_Send(struct sockaddr_in *, struct sockaddr_in *, int);
int next_word(char **, char *);
int get_sockaddr(int, struct sockaddr_in *);
int get_flowspec(int, area_t **, int);
int get_tspec(int, area_t **, int);
int get_filter(int, area_t **, int);
char *fmt_filterspec(rapi_filter_t *);
char *rsvp_timestamp();
int asynch_handler(rapi_sid_t, rapi_eventinfo_t, int,
int, int, struct sockaddr *, u_char,
int, rapi_filter_t *, int, rapi_flowspec_t *,
int, rapi_adspec_t *, void *);
int Do_rsvp_cmd(int, int);
rapi_sid_t rapi_rsvp_cmd(rapi_cmd_t *, int *);
int Get_Socket(int);
int tolower(int);
void rtap_hexmsg(int, int, struct in_addr *, u_char *, int);
int get_GPIfilter(int, area_t **, int);
/*
* Globals
*/
#define MAX_NFLWDS 64
#define MAX_T 64
int T = 1; /* Current Thread number */
area_t *Filter_specs[MAX_T];
area_t *Flowspecs[MAX_T];
area_t *snd_template[MAX_T];
area_t *snd_flowspec[MAX_T];
rapi_sid_t Sid[MAX_T];
int ttl[MAX_T];
rapi_styleid_t Style[MAX_T];
struct sockaddr_in dest[MAX_T];
struct sockaddr_in src[MAX_T];
struct sockaddr_in rcvr[MAX_T];
int Mode[MAX_T];
#define NO_MODE 0
#define S_MODE 0x01 /* Send only */
#define R_MODE 0x02 /* Receive only */
#define RS_MODE S_MODE+R_MODE /* Send/Receive */
#define GPI_MODE 0x10
int protid[MAX_T];
int resv_flags[MAX_T]; /* reservation flags */
int udpsock[MAX_T]; /* Data socket */
extern int rtap_fd; /* Unix socket to rsvpd */
#ifdef DATA
struct timeval timeout, nexttime;
struct timeval Default_interval = {1, 0}; /* Default is 1 per second */
#define MAXDATA_SIZE 1500
#define DEFAULTDATA_SIZE 512
char data_buff[MAXDATA_SIZE];
int data_size[MAX_T] = 0; /* size of data packet to send */
long send_data_bytes[MAX_T] = 0;
long send_data_msgs = 0;
long recv_data_bytes = 0;
long recv_data_msgs = 0;
#endif
#define MAX_PACKET 1024
u_char packet_buff[MAX_PACKET];
int packet_size;
#undef FD_SETSIZE
#define FD_SETSIZE 32
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
enum op_codes {
/* order must be same as entries cmd_table[].cmd_op below!! */
OP_HELP = 1, OP_QUIT, OP_DEST, OP_SESS, OP_SENDER, OP_RESV,
OP_CLOSE, OP_STATUS, OP_DATA, OP_RECV,
OP_TTL, OP_CONFIRM, OP_TEMPLATE, OP_AUTH,
OP_ASYNC, OP_SLEEP, OP_DLEVEL, OP_DMASK, OP_MEMORY, OP_HEXMSG,
OP_ECHO, OP_BUG, OP_NULL,
OP_proto, OP_hostport, OP_hp1, OP_hp2, OP_tspec,
OP_wf, OP_ff, OP_se, OP_flowspec, OP_filter
};
/* Following table MUST match enum order of op_codes !
*/
struct cmds {
char *cmd_verb;
int cmd_op;
char *cmd_help;
} cmd_table[] = {
{ "?", OP_HELP, "Commands are:\n" },
{ "help", OP_HELP, " help | ?\n" },
{ "quit", OP_QUIT, " quit\n" },
{ "T", OP_HELP, " T <#>\n" },
{ "dest", OP_SESS, " dest [gpi] [intserv] <proto> <dest addr>[:<dest port>]\n" },
{ "session", OP_SESS, " session (same as 'dest')\n" },
{ "sender", OP_SENDER, "\
sender [<src host>:]<src port> <Tspec>\n" },
{ "reserve", OP_RESV, "\
reserve [recv addr] wf [*] <flowspec> |\n\
reserve [rcv addr] ff <filtspec> <flowspec> [<filtspec> <flowspec>] ... |\n\
reserve [rcv addr] se [<filtspec> ...] <flowspec>\n" },
{ "close", OP_CLOSE, " close\n" },
{ "status", OP_STATUS, " status\n" },
{ "data", OP_DATA, " data [<# per sec> [<size>]]\n" },
{ "receive", OP_RECV, " receive [recv host]\n" },
{ "ttl", OP_TTL, " ttl <integer>\n" },
{ "confirm", OP_CONFIRM, " confirm (Req confirmation)\n" },
{ "template", OP_TEMPLATE, " (Not supported)\n"} ,
{ "auth", OP_AUTH, " auth <user credential string>\n" },
{ "async", OP_ASYNC, " async\n" },
{ "sleep", OP_SLEEP, " sleep <seconds>\n" },
{ "dlevel", OP_DLEVEL, " dlevel <logging level>\n" },
{ "dmask", OP_DMASK, " dmask <debug mask>\n" },
#ifdef ISI_TEST
{ "memory", OP_MEMORY, " memory (=>mallocmap)\n"},
#endif
{ "hexmsg", OP_HEXMSG, " hexmsg <type> <host> [vif] x<hex string>\n"},
{ "echo", OP_ECHO, " echo <text>\n\n" },
{ "bug", OP_BUG, " bug (Toggles on/off)\n" },
{ "", OP_NULL, "" } /* MUST BE LAST IN CMD TABLE */
};
char *Other_help = "\
Notes:\n\
Commands 'template' and 'ttl' are optional.\n\
Any command may be preceded by 'T<thread#><sp>'\n\
\n\
<proto> ::= 'tcp' | 'udp' | 'proto' <integer>\n\
\n\
<Flowspec> ::= \n\
'[' 'g' <R> <S> <r(Bps)> <b(B)> <p(Bps)> <m(B)> <M(B)> ']' |\n\
'[' 'cl' <r(Bps)> <b(B)> <m(B)> <M(B)> ']' |\n\
\n\
<Tspec> ::= \n\
'[' 't' <r(Bps)> <b(B)> <p(Bps)> <m(B)> <M(B)> ']'\n\
\n\
<Filtspec> ::= <host name|number>:<port #>\n\
\n\
<type> ::= 'path'|'resv'|'ptear'|'rtear'|'perr'|'rerr'|'confirm'\n\n";
enum {
Ahelp = 1, Aotherhelp, Attl, Aunsupported,
Asession, Asender1, Asender2, Aconfirm,
Asleep, Asynch, Aclose,
Astatus, Aquit, Adata, Abug,
Aflowspec, Afilter, Aresv_init, Aresv_fin,
Adlevel, Admask, Arecv, Arcvr,
Amemory, Ahexmsg
};
Pm_inst rtap_mem[400] = {
Label( OP_HELP ),
Action( Ahelp, NULL, OK),
Label( OP_BUG ),
Action( Abug, NULL, OK),
/* [gpi] [intserv] <proto> <dest addr>[:<dest port>] */
Label( OP_SESS ),
Not_String( "gpi", 2),
SetLit( 1, 2),
SetLit( 0, 1),
Not_String( "intserv", 2),
SetLit( 1, 2),
SetLit( 0, 1),
IsNot( OP_proto, "Missing: udp|tcp|<int>", ERR ),
Not_Host("Bad dest host", ERR),
EOL( NULL, 3),
Not_Char(":/", 3),
Not_Integer(NULL, 2),
Action( Asession, NULL, OK),
Print("Bad dest port", ERR),
Label( OP_proto ),
Not_String( "udp", 2),
SetLit( 17, OK),
Not_String( "tcp", 2),
SetLit( 6, OK),
Not_String( "proto", NO),
Not_Integer( "Pm: Bad proto", NO),
Go( OK),
/* data [<# per sec> [<size>]] */
Label( OP_DATA ),
#ifdef DATA
Not_Integer( NULL, 3),
Not_Integer( NULL, 2),
Not_EOL("Bad data parms", ERR),
Action( Adata, NULL, OK),
#else
Action( Aunsupported, NULL, OK),
#endif
/* receive [recv host] */
Label( OP_RECV ),
Not_Host(NULL, 1),
Action( Arecv, NULL, OK),
/* <ttl value> */
Label( OP_TTL ),
Not_Integer("Bad TTL parm", ERR),
Action( Attl, NULL, OK),
/* Generalized <sender template> */
Label( OP_TEMPLATE ),
Action( Aunsupported, NULL, OK),
/* [[<sender host>:]<port>] <tspec> OR
* <empty>
*/
Label( OP_SENDER ),
IsNot( OP_hostport, NULL, 3),
InFile( OP_tspec, ".rsvp.profile", 2),
IsNot( OP_tspec, "Sender Tspec required", ERR),
Action( Asender2, NULL, OK),
Label( OP_CLOSE),
Action( Aclose, NULL, OK),
Label( OP_CONFIRM ),
/* Turn on confirm flag in next reserv call */
Action( Aconfirm, NULL, OK),
Label( OP_ASYNC ),
Action( Asynch, NULL, OK),
Label( OP_SLEEP ),
Not_Integer(NULL, 1),
Action( Asleep, NULL, OK ),
Label( OP_STATUS ),
Action( Astatus, NULL, OK),
Label( OP_QUIT ),
Action( Aquit, NULL, OK),
Label( OP_DLEVEL),
Not_Integer( NULL, 1),
Action( Adlevel, NULL, OK),
Label( OP_DMASK ),
Not_Integer( NULL, 1),
Action( Admask, NULL, OK),
#ifdef ISI_TEST
Label( OP_MEMORY ),
Action( Amemory, NULL, OK),
#endif /* ISI_TEST */
Label( OP_HEXMSG ),
Char( "x", 20),
Not_String( "path", 2),
SetLit( 1, 14),
Not_String( "resv", 2),
SetLit( 2, 12),
Not_String( "perr", 2),
SetLit( 3, 10),
Not_String( "rerr", 2),
SetLit( 4, 8),
Not_String( "ptear", 2),
SetLit( 5, 6),
Not_String( "rtear", 2),
SetLit( 6, 4),
Not_String( "confirm", 2),
SetLit( 7, 2),
Print("Bad msg type", ERR),
Not_Host( "host?", ERR),
Integer( NULL, 2),
SetLit( -1, 1),
Not_Char( "x", 1),
Action( Ahexmsg, NULL, OK),
Label( OP_hostport ),
/* [host :] port WhSp
* Needs recursive calls, back-tracking
*/
Is( OP_hp1, NULL, OK),
Is( OP_hp2, NULL, OK),
Not_Host( NULL, NO),
SetLit( 0, 1),
Go( OK),
Label( OP_hp1 ),
/* host : port WhSp
*/
Not_Host( NULL, NO),
Not_Char( ":/", NO),
Not_Integer( "Bad port", ERR),
Not_WhSp( "Bad port", ERR),
Go( OK),
Label( OP_hp2 ),
/* [host == 0] port WhSp
*/
SetLit( 0, 1),
Not_Integer( NULL, NO),
Not_WhSp( NULL, NO),
Go( OK),
Label( OP_RESV ),
Not_Char( "?", 2),
Action( Aotherhelp, NULL, OK),
Action( Aresv_init, NULL, 1),
Not_String("wf", 2),
Is( OP_wf, NULL, OK),
Not_String("ff", 2),
Is( OP_ff, NULL, OK),
Not_String("se", 2),
Is( OP_se, NULL, OK),
Not_Host( "Bad style", ERR),
Action(Arcvr, NULL, 1),
Not_String("wf", 2),
Is( OP_wf, NULL, OK),
Not_String("ff", 2),
Is( OP_ff, NULL, OK),
Not_String("se", 2),
Is( OP_se, NULL, OK),
Print( "Bad style", ERR),
Label( OP_wf ),
/*
* WF parms: ['*'] <flowspec>
*/
SetLit( RAPI_RSTYLE_WILDCARD, 1),
EOL( NULL, 5),
Char( "*", 1),
InFile( OP_flowspec, ".rsvp.profile", 2),
IsNot( OP_flowspec, "Flowspec illegal or missing", ERR),
Action( Aflowspec, NULL, 1),
Action( Aresv_fin, NULL, OK),
Label( OP_ff ),
/*
* FF parms: { { <filtspec> }*1 <flowspec> }*
* really: { <filtspec> <flowspec> }*
*/
SetLit( RAPI_RSTYLE_FIXED, 1),
Not_EOL( NULL, 2),
Action( Aresv_fin, NULL, OK),
IsNot( OP_filter, "Bad filterspec", ERR),
Action( Afilter, NULL, 1),
InFile( OP_flowspec, ".rsvp.profile", 2),
IsNot( OP_flowspec, "Bad flowspec", ERR),
Action( Aflowspec, NULL, -6),
/*
* SE parms: [ <filtspec>*1 <flowspec> ]
*/
Label( OP_se ),
SetLit( RAPI_RSTYLE_SE, 1),
Not_EOL( NULL, 2),
Action( Aresv_fin, NULL, OK),
IsNot( OP_filter, "Missing filter spec", ERR),
Action( Afilter, NULL, 1),
Is( OP_filter, NULL, -1),
InFile( OP_flowspec, ".rsvp.profile", 2),
IsNot( OP_flowspec, "Missing flowspec", ERR),
Action( Aflowspec, NULL, -7),
Label( OP_tspec ),
/* Tspec
* '[' 't' <r> <b> [<p> [<m> [<M>]]] ']'
*/
Not_Char("[", NO),
Not_String("t", 2),
SetLit(QOS_TSPEC, 2),
Print("Unknown service", ERR),
Not_Integer("Missing r: TB depth", ERR),
Not_Integer("Missing b: TB rate", ERR),
Not_Integer(NULL, 3),
Not_Integer(NULL, 2),
Not_Integer(NULL, 1),
Char("]", OK),
Print("Missing ]", ERR),
Label( OP_flowspec ),
/* '[' 'cl' <b> <r> [<m> [<M>]] ']'
* '[' {'g'|'gx'} <R> <S> <b> <r> [<p> [<m> [<M>]]] ']'
*/
Not_Char("[", NO),
Not_String("g", 2),
SetLit(QOS_GUARANTEED, 12),
Not_String("gx", 2),
SetLit(QOS_GUARANTEEDX, 10),
Not_String("cl", 2),
SetLit(QOS_CNTR_LOAD, 2),
Print("Unknown service", ERR),
Not_Integer("Missing r: TB depth", ERR),
Not_Integer("Missing b: TB rate", ERR),
Not_Integer(NULL, 2),
Not_Integer(NULL, 1),
Char("]", OK),
Print("Missing ]", ERR),
Not_Integer("Missing R: Rate", ERR),
Not_Integer("Missing S: Slack", ERR),
Not_Integer("Missing r: TB depth", ERR),
Not_Integer("Missing b: TB rate", ERR),
Not_Integer(NULL, 1),
Go( -11),
Label( OP_filter ),
/* host [ : port ]
*/
Not_Host(NULL, NO),
WhSp( NULL, OK),
Char(":/", 2),
Print("Bad dest port", ERR),
Not_Integer(NULL, -1),
Go( OK),
Label( 0 )
};
int
Pm_Action(int op, int vi, int parm)
{
int i, sid, rc;
char *cp;
u_char u_ch, flags;
#ifdef DATA
double F_intvl;
long I_intvl;
#endif
#ifdef ISI_TEST
void mallocmap();
#endif
switch (op) {
case Ahelp:
for (i = 0; i < OP_NULL; i++)
printf("%s", cmd_table[i].cmd_help);
case Aotherhelp:
printf(Other_help);
break;
case Abug:
Pm_debug = !Pm_debug;
break;
case Asession:
/* val stack:
* gpi?1|0 intserv?1:0 proto desthost [destport]
*/
flags = 0;
if (val0) {
flags = RAPI_GPI_SESSION;
Mode[T] |= GPI_MODE;
}
if (val1)
flags |= RAPI_USE_INTSERV;
protid[T] = val2;
get_sockaddr(3, &dest[T]);
if (Sid[T] != NULL_SID) {
printf("close first\n");
break;
}
sid = rapi_session((struct sockaddr *)&dest[T],
protid[T], flags,
(rapi_event_rtn_t) asynch_handler, 0, &rc);
if (sid == NULL_SID)
print_errno("rsvp_session()", rc);
else {
Sid[T] = sid;
rtap_fd = rapi_getfd(sid);
printf("T%d: rapi_session => sid= %d, fd= %d\n",
T, sid, rtap_fd);
}
#ifdef DATA
send_data_bytes = recv_data_bytes = 0;
send_data_msgs = recv_data_msgs = 0;
#endif
break;
#ifdef DATA
case Adata:
if (Pm_vi > 0) {
F_intvl = atof(val0);
I_intvl = (long) rint(1e6/F_intvl);
timeout.tv_sec = I_intvl/1000000;
timeout.tv_usec = I_intvl%1000000;
if (Pm_vi > 1)
data_size = val1;
else
data_size = DEFAULTDATA_SIZE;
}
gettimeofday(&nexttime, NULL);
tvadd(&nexttime, &timeout);
break;
#endif /* DATA */
case Arecv:
if (Sid[T] == NULL_SID) {
printf("Must issue dest cmd first\n");
break;
}
memset(&rcvr[T], 0, sizeof(struct sockaddr_in));
if (udpsock[T] < 0)
udpsock[T] = Get_Socket(dest[T].sin_port);
Set_Recv(&dest[T], &rcvr[T]);
break;
case Attl:
if (Pm_vi > 0)
ttl[T] = val0;
#ifdef DATA
if (( Mode & S_MODE ) && data_size > 0)
Set_Send(&dest[T], &src[T], ttl[T]);
#endif
break;
case Aunsupported:
printf("Not supported\n");
break;
case Asender2:
if (Sid[T] == NULL_SID) {
printf("Must issue dest cmd first\n");
break;
}
if (Pm_vi) {
if (Mode[T] & GPI_MODE) {
init_Area((area_t **)&snd_template[T],
sizeof(rapi_filter_t));
get_GPIfilter(vi, &snd_template[T],
sizeof(rapi_filter_t));
}
else
get_sockaddr(vi, &src[T]);
init_Area((area_t **)&snd_flowspec[T],
sizeof(rapi_flowspec_t));
get_tspec(vi+2, &snd_flowspec[T],
sizeof(rapi_flowspec_t));
}
/*
* Make rapi_sender call to RSVP API
*/
rc = rapi_sender(Sid[T], 0,
(Pm_vi>0)? (struct sockaddr *)&src[T]: NULL,
Area_Data((rapi_filter_t *), snd_template[T]),
Area_Data((rapi_tspec_t *), snd_flowspec[T]),
NULL, NULL, ttl[T]);
if (rc)
print_errno("rsvp_sender()", rc);
else
printf("rapi_sender() OK\n");
Mode[T] |= S_MODE;
break;
case Aclose:
if (Sid[T] == NULL_SID) {
printf("Already closed\n");
break;
}
rc = rapi_release(Sid[T]);
if (rc)
print_errno("rapi_release()", rc);
printf("T%d: rapi_release(): sid= %d, fd= %d\n",
T, Sid[T], rtap_fd);
Sid[T] = NULL_SID;
Mode[T] = NO_MODE;
if (udpsock[T] >= 0)
close(udpsock[T]); /* close data socket */
udpsock[T] = -1;
break;
case Aconfirm:
resv_flags[T] = RAPI_REQ_CONFIRM;
break;
case Asynch:
rc = rapi_dispatch();
if (rc)
print_errno("rapi_dispatch()", rc);
case Amemory:
#if defined(ISI_TEST) && defined(SunOS)
mallocmap();
#else
printf("Not supported.\n");
#endif
break;
case Ahexmsg: /* To send arbitrary RSVP message, use:
* hexmsg <type> <host> <vif> x<hex string>
* If the packet is larger than 100 bytes or for
* convenience, can split into multiple lines, ended
* with the ! :
* hexmsg x<hex string1>
* hexmsg x<hex string2>
* ...
* hexmsg <tyhpe> <host> [vif] x<last hex string>
*
* Val stack: [<msg type #> <target host> <vif|-1>]
*/
#ifdef RTAP
u_ch = i = 0;
for (cp = Pm_cp; *cp; cp++) {
if (isxdigit(*cp)) {
#define tohex(c) (isdigit(c)?c-'0':tolower(c)-'a'+10)
u_ch = (u_ch<<4)|tohex(*cp);
if (++i == 2) {
packet_buff[packet_size++] = u_ch;
i = u_ch = 0;
}
}
else if ((*cp == ' '||*cp == '#') &&(i)) {
printf("Bad hex @ +%d\n", cp-Pm_cp-1);
break;
}
if (*cp == '#')
break;
}
/* Only last line of multi-line message specifies host
*/
if (Pm_vi == 0)
break;
rtap_hexmsg(val0, val2, (struct in_addr *)&val1, packet_buff,
packet_size);
packet_size = sizeof(common_header); /* somewhat of a kludge */
#else
printf("Unsupported by remote rtap\n");
#endif
break;
case Asleep:
rtap_sleep((Pm_vi > 0)? val0:0);
break;
case Astatus:
print_status();
break;
case Aquit:
if (Sid[T] != NULL_SID) {
rc = rapi_release(Sid[T]);
if (rc)
print_errno("rapi_release()", rc);
printf("Closed sid= %d, fd= %d\n", Sid[T], rtap_fd);
}
if (udpsock[T] >= 0)
close(udpsock[T]); /* close data socket */
exit(0);
case Afilter:
get_filter(1+vi, &Filter_specs[T], sizeof(rapi_filter_t));
Pm_vi = vi+1;
break;
case Aflowspec:
/* Value stack: <style> <service> <parm> ...
*/
get_flowspec(1+vi, &Flowspecs[T], sizeof(rapi_flowspec_t));
Pm_vi = vi+1;
break;
case Aresv_fin:
Mode[T] |= R_MODE;
Style[T] = (rapi_styleid_t) Pm_val[vi];
rc = rapi_reserve(Sid[T], resv_flags[T],
(struct sockaddr *) &rcvr[T],
Style[T], NULL, NULL,
Filter_specs[T]->area_cnt,
Area_Data((rapi_filter_t *), Filter_specs[T]),
Flowspecs[T]->area_cnt,
Area_Data((rapi_flowspec_t *), Flowspecs[T]));
if (rc)
print_errno("rapi_reserve()", rc);
resv_flags[T] = 0;
break;
case Arcvr:
Append_Val(0); /* No port */
get_sockaddr(vi, &rcvr[T]);
break;
case Aresv_init:
memset(&rcvr[T], 0, sizeof(struct sockaddr_in));
init_Area((area_t **)&Filter_specs[T],
MAX_NFLWDS*sizeof(rapi_filter_t));
init_Area((area_t **)&Flowspecs[T],
MAX_NFLWDS*sizeof(rapi_flowspec_t));
break;
case Adlevel:
Do_rsvp_cmd((Pm_vi)?Pm_val[0]: -1, RAPI_CMD_DEBUG_LEVEL);
break;
case Admask:
Do_rsvp_cmd((Pm_vi)?Pm_val[0]: -1, RAPI_CMD_DEBUG_MASK);
break;
}
return(OK);
}
/* get_sockaddr: Create sockaddr from host, port values in value list
* at offset voff, voff+1.
*/
int
get_sockaddr(voff, sinp)
int voff;
struct sockaddr_in *sinp;
{
memset(sinp, 0, sizeof(struct sockaddr_in));
sinp->sin_family = AF_INET;
#if BSD > 199103
sinp->sin_len = sizeof(struct sockaddr_in);
#endif
sinp->sin_addr.s_addr = Pm_val[voff];
if (Pm_vi > voff+1)
sinp->sin_port = hton16((u_short)Pm_val[voff+1]);
else
sinp->sin_port = 0;
return(0);
}
/*
* Construct RAPI flowspec object from value list:
* voff+: 0=type
* type = g|p: 1=r, 2=b, [3=d, [4=dl]]
* type = cl: 1=r, 2=b, [3=m, [4=M]]
* type = gx: 1=R, 2=S, 3=r, 4=b, [5=p, [6=m, [7=M]]]
*/
int
get_flowspec(int voff, area_t **areapp, int size)
{
rapi_flowspec_t Tflow, *flowsp = &Tflow;
#ifdef OBSOLETE_API
qos_flowspec_t *cszp = &flowsp->specbody_qos;
#endif
qos_flowspecx_t *csxp = &flowsp->specbody_qosx;
int type = Pm_val[voff];
switch (type) {
#ifdef OBSOLETE_API
case QOS_PREDICTIVE:
case QOS_GUARANTEED:
cszp->spec_type = type;
cszp->spec_r = Pm_val[voff+1];
cszp->spec_b = Pm_val[voff+2];
cszp->spec_d = 0;
cszp->spec_sl = -1;
if (Pm_vi > voff+3) {
cszp->spec_d = Pm_val[voff+3];
if (Pm_vi > voff+4)
cszp->spec_sl = Pm_val[voff+4];
}
flowsp->form = RAPI_FLOWSTYPE_CSZ;
break;
#endif
case QOS_CNTR_LOAD:
csxp->spec_type = type;
csxp->xspec_r = Pm_val[voff+1];
csxp->xspec_b = Pm_val[voff+2];
csxp->xspec_p = INFINITY32f;
csxp->xspec_m = 0;
csxp->xspec_M = 65535;
if (Pm_vi > voff+3) {
csxp->xspec_m = Pm_val[voff+3];
if (Pm_vi > voff+4)
csxp->xspec_M = Pm_val[voff+4];
}
flowsp->form = RAPI_FLOWSTYPE_Simplified;
break;
case QOS_GUARANTEEDX:
csxp->spec_type = type;
csxp->xspec_R = Pm_val[voff+1];
csxp->xspec_S = Pm_val[voff+2];
csxp->xspec_r = Pm_val[voff+3];
csxp->xspec_b = Pm_val[voff+4];
csxp->xspec_p = INFINITY32f;
csxp->xspec_m = 0;
csxp->xspec_M = 65535;
if (Pm_vi > voff+5) {
csxp->xspec_p = Pm_val[voff+5];
if (Pm_vi > voff+6) {
csxp->xspec_m = Pm_val[voff+6];
if (Pm_vi > voff+7)
csxp->xspec_M = Pm_val[voff+7];
}
}
flowsp->form = RAPI_FLOWSTYPE_Simplified;
break;
default:
printf("Unknown flowspec type: %d\n", Pm_val[voff]);
return(-1);
}
flowsp->len = sizeof(rapi_flowspec_t);
Cat_Area(*areapp, (rapi_hdr_t *) flowsp);
return (0);
}
/*
* Construct RAPI sender-tspec object from value list:
* voff: +0=type
* type = g|p: +1=r, +2=b, [+3=d, [+4=dl]]
* type = cl: +1=r, +2=b, [+3=m, [+4=M]]
* type = gx|t: +1=r, +2=b, [+3=p, [+4=m, [+5=M]]]
*/
int
get_tspec(int voff, area_t **areapp, int size)
{
rapi_tspec_t Tspec, *tspecp = &Tspec;
#ifdef OBSOLETE_API
qos_flowspec_t *cszp = &tspecp->specbody_qos;
#endif /* OBSOLETE_API */
qos_tspecx_t *ctxp = &tspecp->tspecbody_qosx;
int type = Pm_val[voff];
switch (type) {
#ifdef OBSOLETE_API
case QOS_PREDICTIVE:
case QOS_GUARANTEED:
cszp->spec_type = QOS_TSPEC;
cszp->spec_r = Pm_val[voff+1];
cszp->spec_b = Pm_val[voff+2];
cszp->spec_d = 0;
cszp->spec_sl = -1;
if (Pm_vi > voff+3) {
cszp->spec_d = Pm_val[voff+3];
if (Pm_vi > voff+4)
cszp->spec_sl = Pm_val[voff+4];
}
tspecp->form = RAPI_FLOWSTYPE_CSZ;
tspecp->len = sizeof(rapi_hdr_t) + sizeof(qos_flowspec_t);
break;
#endif /* OBSOLETE_API */
case QOS_CNTR_LOAD:
ctxp->spec_type = type;
ctxp->xtspec_r = Pm_val[voff+1];
ctxp->xtspec_b = Pm_val[voff+2];
ctxp->xtspec_p = INFINITY32f;
ctxp->xtspec_m = 0;
ctxp->xtspec_M = 65535;
if (Pm_vi > voff+3) {
ctxp->xtspec_m = Pm_val[voff+3];
if (Pm_vi > voff+4)
ctxp->xtspec_M = Pm_val[voff+4];
}
tspecp->form = RAPI_TSPECTYPE_Simplified;
tspecp->len = sizeof(rapi_hdr_t) + sizeof(qos_tspecx_t);
break;
case QOS_GUARANTEEDX:
case QOS_TSPECX:
ctxp->spec_type = QOS_GUARANTEEDX;
ctxp->xtspec_r = Pm_val[voff+1];
ctxp->xtspec_b = Pm_val[voff+2];
ctxp->xtspec_p = INFINITY32f;
ctxp->xtspec_m = 0;
ctxp->xtspec_M = 65535;
if (Pm_vi > voff+3) {
ctxp->xtspec_p = Pm_val[voff+3];
if (Pm_vi > voff+4) {
ctxp->xtspec_m = Pm_val[voff+4];
if (Pm_vi > voff+5)
ctxp->xtspec_M = Pm_val[voff+5];
}
}
tspecp->len = sizeof(rapi_hdr_t) + sizeof(qos_tspecx_t);
tspecp->form = RAPI_TSPECTYPE_Simplified;
break;
default:
printf("Unknown flowspec type: %d\n", Pm_val[voff]);
return(-1);
}
Cat_Area(*areapp, (rapi_hdr_t *) tspecp);
return (0);
}
int
get_filter(int voff, area_t **areap, int size)
{
struct sockaddr_in sin;
rapi_filter_t Tfilt;
get_sockaddr(voff, &sin);
saddr_to_rapi_filt(&sin, &Tfilt);
Cat_Area(*areap, (rapi_hdr_t *) &Tfilt);
return (0);
}
int
get_GPIfilter(int voff, area_t **areap, int size)
{
rapi_filter_t Tfilt;
Tfilt.filt_u.gpi.sender.s_addr = Pm_val[voff];
Tfilt.filt_u.gpi.gpi = Pm_val[voff+1];
Tfilt.len = sizeof(rapi_hdr_t)+sizeof(rapi_filter_gpi_t);
Tfilt.form = RAPI_FILTERFORM_GPI;
Cat_Area(*areap, (rapi_hdr_t *) &Tfilt);
return (0);
}
/*
* rtap_cmds_init(): Initialization routine, called to start things off.
*/
void
rtap_cmds_init()
{
int i;
Pm_Init(rtap_mem);
for (i = 0; i < MAX_T; i++) {
Filter_specs[i] = NULL;
Flowspecs[i] = NULL;
snd_template[i] = NULL;
snd_flowspec[i] = NULL;
Sid[i] = ttl[i] = 0;
Mode[i] = NO_MODE;
resv_flags[i] = 0;
udpsock[i] = -1;
memset(&dest[i], 0, sizeof(struct sockaddr_in));
memset(&src[i], 0, sizeof(struct sockaddr_in));
memset(&rcvr[i], 0, sizeof(struct sockaddr_in));
#ifdef DATA
timeout = Default_interval;
data_size = 0;
#endif
}
packet_size = sizeof(common_header);
}
/*
* Do_Command(): Top-level routine to read the next line from a given
* file and execute the command it contains. Returns 0 if EOF, else 1.
*/
int
Do_Command(char *infile, FILE *infp)
{
char cmd_line[256], cmd_op[80];
struct cmds *cmdp;
char *cp;
int rc;
if (fgets(cmd_line, sizeof(cmd_line), infp) == NULL) {
printf("No input\n");
return(0);
}
/* remove trailing NL */
cp = cmd_line + strlen(cmd_line) - 1;
if (*cp == '\n')
*cp = '\0';
else {
printf("LINE > 255 CHARS: %s.\n", cmd_line);
exit(1);
}
/*** printf("Do_Command: %s\n", cmd_line); ***/
if (infile)
printf("%12s > %s\n", rsvp_timestamp(), cmd_line);
if (cmd_line[0] == '#') { /* Comment, skip this line */
return(1);
}
cp = cmd_line;
if (!next_word(&cp, cmd_op))
return(1);
if (cmd_op[0] == 'T') {
T = atoi(&cmd_op[1]);
if (!next_word(&cp, cmd_op))
return(1);
}
cmdp = cmd_table;
while ((cmdp->cmd_op != OP_NULL) && pfxcmp(cmd_op, cmdp->cmd_verb))
cmdp++;
if (cmdp->cmd_op == OP_NULL) {
if (cmd_op[0])
printf(" ?? %s\n", cmd_op);
return(1);
}
/* Initialize parse machine: semantic stack and scan pointer.
*/
Pm_vi = 0;
Pm_cp = cp;
if (packet_size > sizeof(common_header) && cmdp->cmd_op != OP_HEXMSG) {
printf("Hexmsg cmd not terminated \n");
packet_size = sizeof(common_header);
}
rc = Parse_machine(rtap_mem, cmdp->cmd_op);
if (rc != OK)
printf("Error.\n");
if (rc == NO)
return(0);
return(1);
}
void
saddr_to_rapi_filt(
struct sockaddr_in *host,
rapi_filter_t *p)
{
p->len = sizeof(rapi_hdr_t) + sizeof(rapi_filter_base_t);
p->form = RAPI_FILTERFORM_BASE;
p->filt_u.base.sender = *host;
}
/*
* Prefix string comparison: Return 0 if s1 string is prefix of s2 string, 1
* otherwise.
*/
int
pfxcmp(s1, s2)
register char *s1, *s2;
{
while (*s1)
if (*s1++ != *s2++)
return (1);
return (0);
}
int
asynch_handler(
rapi_sid_t sid,
rapi_eventinfo_t event,
int styleid,
int errcode,
int errval,
struct sockaddr *errnode,
u_char errflags,
int filt_num,
rapi_filter_t *filt_list,
int flow_num,
rapi_flowspec_t *flow_list,
int adspec_num,
rapi_adspec_t *adspec_list,
void *myparm)
{
rapi_filter_t *filtp = filt_list;
rapi_flowspec_t *flowp = flow_list;
rapi_adspec_t *adsp = adspec_list;
int isPath = 1;
char buff[128], out1[80];
int T, i;
extern char *rapi_rstyle_names[];
for (T=0 ; T < MAX_T; T++) /* Map sid into thread# T */
if (Sid[T] == sid)
break;
sprintf(out1, " Session= %.32s:%d", inet_ntoa(dest[T].sin_addr),
ntoh16(dest[T].sin_port));
printf(
"---------------------------------------------------------------\n");
switch (event) {
case RAPI_PATH_EVENT:
printf("T%d: Path Event -- %s\n", T, out1);
if (flow_num == 0)
printf(" (No Path state)\n");
break;
case RAPI_RESV_EVENT:
printf("T%d: Resv Event -- %s\n", T, out1);
if (flow_num == 0)
printf(" (No Resv state)\n");
isPath = 0;
break;
case RAPI_RESV_ERROR:
isPath = 0;
case RAPI_PATH_ERROR:
printf("T%d: sid=%d %s -- RSVP error: %s\n",
T, sid, out1,
(errcode==RSVP_Err_API_ERROR)?
rapi_errlist[errval]:
rsvp_errlist[errcode]);
if (event == RAPI_RESV_ERROR)
printf(" Style=%s", rapi_rstyle_names[styleid]);
printf(" Code=%d Val=%d Node= %s",
errcode, errval,
inet_ntoa(((struct sockaddr_in *)errnode)->sin_addr));
if (errflags&RAPI_ERRF_InPlace)
printf(" *InPlace*");
if (errflags&RAPI_ERRF_NotGuilty)
printf(" *NotGuilt*");
printf("\n");
break;
case RAPI_RESV_STATUS:
isPath = 0;
printf("T%d: Resv State -- %s:\n", T, out1);
break;
case RAPI_PATH_STATUS:
printf("T%d: Path Stat -- %s:\n", T, out1);
break;
case RAPI_RESV_CONFIRM:
isPath = 0;
printf("T%d: Confirm Event -- %s:\n", T, out1);
break;
default:
printf("!!?\n");
break;
}
for (i = 0; i < MAX(filt_num, flow_num); i++) {
if (i < filt_num) {
printf("\t%s", fmt_filterspec(filtp));
filtp = (rapi_filter_t *)After_RAPIObj(filtp);
}
else
printf("\t\t");
if (i < flow_num) {
if (isPath)
rapi_fmt_tspec((rapi_tspec_t *)flowp,
buff, sizeof(buff));
else
rapi_fmt_flowspec(flowp, buff, sizeof(buff));
printf("\t%s\n", buff);
flowp = (rapi_flowspec_t *)After_RAPIObj(flowp);
}
else
printf("\n");
if (i < adspec_num) {
rapi_fmt_adspec(adsp, buff, sizeof(buff));
printf("\t\t%s\n", buff);
adsp = (rapi_adspec_t *)After_RAPIObj(adsp);
}
}
printf(
"---------------------------------------------------------------\n");
fflush(stdout);
return 0;
}
/*
* Skip leading blanks, then copy next word (delimited by blank or zero, but
* no longer than 63 bytes) into buffer b, set scan pointer to following
* non-blank (or end of string), and return 1. If there is no non-blank text,
* set scan ptr to point to 0 byte and return 0.
*/
int
next_word(char **cpp, char *b)
{
char *tp;
int L;
*cpp += strspn(*cpp, " \t");
if (**cpp == '\0' || **cpp == '\n' || **cpp == '#')
return(0);
tp = strpbrk(*cpp, " \t\n#");
L = MIN((tp)?(tp-*cpp):strlen(*cpp), 63);
strncpy(b, *cpp, L);
*(b + L) = '\0';
*cpp += L;
*cpp += strspn(*cpp, " \t");
return (1);
}
char *
argscan(argcp, argvp)
int *argcp;
register char ***argvp;
{
register char *cp;
if (*(cp = 2 + **argvp))
return (cp);
else if (--*argcp > 0)
return (*++*argvp);
exit(1);
/* make the sgi compiler happy -mwang*/
return NULL;
}
void
print_errno(char *cp, int rapi_errno)
{
printf("RAPI: %s err %d : %s\n", cp, rapi_errno,
rapi_errlist[rapi_errno]);
}
void
print_status()
{
char *state_str;
char buff[128];
int mode;
#ifdef ISI_TEST
int rc;
#endif
mode = Mode[T] & (RS_MODE);
if (mode == RS_MODE) state_str = "Open SR";
else if (mode == R_MODE) state_str = "Open R";
else if (mode == S_MODE) state_str = "Open S";
else state_str = "Closed";
printf("T%d STATUS:\n", T);
printf(" State: %s sid= %d \n", state_str, Sid[T]);
printf(" Session:\n Dest= %s:%d\n",
inet_ntoa(dest[T].sin_addr),
ntoh16(dest[T].sin_port));
if (src[T].sin_addr.s_addr) {
printf(" Sender:\n %s:%d", inet_ntoa(src[T].sin_addr),
ntoh16(src[T].sin_port));
if (snd_template[T])
printf(" Snd_Templ= %s",
fmt_filterspec(Area_Data((rapi_filter_t *),
snd_template[T])));
if (snd_flowspec[T]) {
rapi_fmt_tspec(Area_Data((rapi_tspec_t *),
snd_flowspec[T]), buff, 128);
printf(" Tspec= %s", buff);
}
printf("\n");
}
#ifdef DATA
printf(" Data:\n Size= %d Timeout= %ld.%06ld TTL= %d\n",
data_size, timeout.tv_sec, timeout.tv_usec, ttl);
printf(" Sent %ld bytes, %ld msgs; Rcvd %ld bytes, %ld msgs\n",
send_data_bytes, send_data_msgs, recv_data_bytes, recv_data_msgs);
#endif
#ifdef ISI_TEST
rc = rapi_status(Sid[T], RAPI_STAT_PATH+RAPI_STAT_RESV);
if (rc)
print_errno("rapi_status()", rc);
#endif
sleep(2);
}
#define MinRAPILen 8 /* minimum RAPI filterspec length */
char *
fmt_filterspec(rapi_filter_t *rfiltp)
{
static char FIbuff[256];
rapi_fmt_filtspec(rfiltp, FIbuff, 256);
return(FIbuff);
}
area_t *
init_Area(area_t **app, int size)
{
area_t *ap = *app;
if (ap == NULL) {
size += sizeof(area_t);
if (size <= 0 || (ap = (area_t *) malloc(size)) == NULL)
return(NULL);
*app = ap;
ap->area_size = size;
}
ap->area_offset = sizeof(area_t);
ap->area_cnt = 0;
return(ap);
}
char *
Area_offset(area_t *ap) {
return((char *) ap + ap->area_offset);
}
void
Cat_Area(area_t *orig, rapi_hdr_t *objp) {
if (orig->area_offset + objp->len > orig->area_size) {
printf("!!Area overflow\n");
return;
}
memcpy((rapi_hdr_t *)Area_offset(orig), objp, objp->len);
orig->area_offset += objp->len;
orig->area_cnt++;
}
int
Get_Socket(int port)
{
struct sockaddr_in sin;
int one = 1;
int sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("rtap socket:");
exit(1);
}
memset((char *) &sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
#if BSD >= 199103
sin.sin_len = sizeof(sin);
#endif
sin.sin_port = port;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one))){
perror("rtap sockopt:");
exit(1);
}
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin))) {
perror("rtap bind:");
exit(1);
}
return (sock);
}
void
Set_Recv(dstp, srcp)
struct sockaddr_in *dstp;
struct sockaddr_in *srcp;
{
struct ip_mreq mreq;
if (!IN_MULTICAST(ntoh32(dstp->sin_addr.s_addr)))
return;
mreq.imr_multiaddr = dstp->sin_addr;
mreq.imr_interface = srcp->sin_addr;
if (0 > cap_setsockopt(udpsock[T], IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *) &mreq, sizeof(mreq))) {
perror("Can't join multicast group");
return;
}
printf("Joined multicast group %s\n", inet_ntoa(dstp->sin_addr));
}
#ifdef DATA
/* Following code is carried over from earlier version of rtap,
* which could send data. This code is currently incomplete.
*/
void
Set_Send((struct sockaddr_in *, struct sockaddr_in *, int T)
{
int sock = udpsock[T];
u_char zero = 0;
u_char ttlv = ttl[T];
if (0 > cap_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
&ttlv, sizeof(ttlv))) {
perror("Can't set multicast TTL");
exit(1);
}
if (0 > cap_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
&zero, sizeof(zero))) {
perror("Can't set no loopback");
exit(1);
}
if (0 > cap_setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
&srcp->sin_addr, sizeof(struct in_addr))) {
perror("Can't set mcast iface");
exit(1);
}
}
void
Send_data(T)
{
int rc;
rc = sendto(udpsock[T], data_buff, data_size, 0,
(struct sockaddr *) dstp, sizeof(struct sockaddr_in));
if (rc < 0) {
perror("sendto");
return;
}
send_data_bytes[T] += rc;
send_data_msgs[T] ++;
}
#endif /* DATA */
int
Do_rsvp_cmd(int flags, int type)
{
int old_level, errnum;
rapi_cmd_t cmd;
cmd.rapi_cmd_len = 1;
cmd.rapi_cmd_type = type;
cmd.rapi_filler = flags;
old_level = rapi_rsvp_cmd(&cmd, &errnum);
if (type == RAPI_CMD_DEBUG_LEVEL)
printf("Rsvpd logging level:\n");
else
printf("Rsvpd debug mask:\n");
if (flags != -1)
printf(" Changing to: %d\n", flags);
if (old_level < 0)
printf("rapi_debug_level error: %d\n", errnum);
return(0);
}