#include #include #include #include #include #include #include #include "scrapi.h" /* * @(#) $Id: scrapi.c,v 1.10 1998/09/24 22:15:53 lindell Exp $ */ /**************************************************************************** SCRAPI: A Simplied RSVP API USC Information Sciences Institute Marina del Rey, California Original Version: Bob Lindell, March 1998. Copyright (c) 1998 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. ********************************************************************/ #if defined(AF_INET6) && defined(IPPROTO_IPV6) #define HAS_IPV6 #endif /* defined(AF_INET6) && defined(IPPROTO_IPV6) */ #ifndef NO_IPV6 #ifdef HAS_IPV6 #define USE_IPV6 #endif /* HAS_IPV6 */ #endif /* NO_IPV6 */ /****************************************************************************** * * Strictly RFC 2133 * *****************************************************************************/ #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN sizeof("XXX.XXX.XXX.XXX") #endif /* INET_ADDRSTRLEN */ #ifndef __FreeBSD__ #ifdef USE_IPV6 extern const struct in6_addr in6addr_any; #endif /* USE_IPV6 */ static const char * inet_ntop(int af,const void *src,char *dst,size_t size); static int inet_pton(int af,const char *src,void *dst); static struct hostent * gethostbyname2(const char *name,int af); #endif /* __FreeBSD__ */ /****************************************************************************** * * Extensions to RFC 2133 * *****************************************************************************/ #ifdef USE_IPV6 #define MAX_ADDRSTRLEN INET6_ADDRSTRLEN #else /* USE_IPV6 */ #define MAX_ADDRSTRLEN INET_ADDRSTRLEN #endif /* USE_IPV6 */ #define MAX_ADDRPORTSTRLEN (MAX_ADDRSTRLEN + sizeof("/XXXXX")) #define MAX_HOSTSTRLEN MAXHOSTNAMELEN #define MAX_HOSTPORTSTRLEN (MAX_HOSTSTRLEN + sizeof("/XXXXX")) #define IN_IS_ADDR_MULTICAST(x) IN_MULTICAST(ntohl((x)->s_addr)) #define IN_ARE_ADDR_EQUAL(x,y) ((x)->s_addr == (y)->s_addr) static const struct in_addr inaddr_any; /****************************************************************************** * * Macros and functions for socket structures. * *****************************************************************************/ #ifdef __FreeBSD__ #define NET_SOCKADDR_SIZE_IPv4(x) \ { \ (x)->sin_len = sizeof(struct sockaddr_in); \ } #define NET_SOCKADDR_SIZE_IPv6(x) \ { \ (x)->sin6_len = sizeof(struct sockaddr_in6); \ } #else /* __FreeBSD__ */ #define NET_SOCKADDR_SIZE_IPv4(x) #define NET_SOCKADDR_SIZE_IPv6(x) #endif /* __FreeBSD__ */ #define NET_SOCKADDR_IPv4(x,addr) NET_SOCKADDR_UDP_IPv4(x,addr,htons(0)) #define NET_SOCKADDR_UDP_IPv4(x,addr,port) { \ memset((char *) (x),0,sizeof(struct sockaddr_in)); \ (x)->sin_family = AF_INET; \ (x)->sin_addr = addr; \ (x)->sin_port = port; \ NET_SOCKADDR_SIZE_IPv4(x); \ } #ifdef USE_IPV6 #define NET_SOCKADDR_IPv6(x,addr) NET_SOCKADDR_UDP_IPv6(x,addr,htons(0)) #define NET_SOCKADDR_UDP_IPv6(x,addr,port) { \ memset((char *) (x),0,sizeof(struct sockaddr_in6)); \ (x)->sin6_family = AF_INET6; \ (x)->sin6_addr = addr; \ (x)->sin6_port = port; \ NET_SOCKADDR_SIZE_IPv6(x); \ } #endif /* USE_IPV6 */ #define SAP(x) ((struct sockaddr *) (x)) #define SAP4(x) ((struct sockaddr_in *) (x)) #define SAP6(x) ((struct sockaddr_in6 *) (x)) static int sockaddr_equal(const struct sockaddr *x, const struct sockaddr *y); static int sockaddr_equal_wild(const struct sockaddr *x, const struct sockaddr *y); static int sockaddr_assign(struct sockaddr *x,const struct sockaddr *y); /****************************************************************************** * * Useful Definitions and Macros * *****************************************************************************/ #ifndef TRUE #define TRUE (0 == 0) #endif /* TRUE */ #ifndef FALSE #define FALSE (0 != 0) #endif /* FALSE */ #define SYS_ERROR (-1) #define SYS_NOERROR 0 #define FAILED(x) ((x) == SYS_ERROR) #define C_MAX(x,y) (((x) >= (y)) ? (x) : (y)) #define C_MIN(x,y) (((x) <= (y)) ? (x) : (y)) /****************************************************************************** * * RSVP Definitions and Macros * *****************************************************************************/ #ifndef RSVP_Err_API_ERROR #define RSVP_Err_API_ERROR 20 #endif /* RSVP_Err_API_ERROR */ #ifndef rapi_filt4 #define rapi_filt4 filt_u.base.sender #endif /* rapi_filt4 */ #define MAXSESSIONS 256 #define Object_Type(x) (((rapi_hdr_t *) (x))->form) #define Object_Length(x) (((rapi_hdr_t *) (x))->len) #define Object_Next(type,x) ((type *) (((char *) (x)) + Object_Length(x))) #define MAX_INTERFACES 32 #define MIN_PACKET_SIZE 64 #define MAX_PACKET_SIZE 576 /* * Status bits */ #define S_NONE 0x00000000 #define S_RESV 0x00000001 #define S_SEND_STATES 0x0000000f #define S_PATH 0x00000010 #define S_CONFIRM 0x00000020 #define S_RECV_STATES 0x000000f0 #define S_STATES 0x000000ff #define S_PATH_REQUEST 0x00000100 #define S_SEND_REQUESTS 0x00000f00 #define S_RESV_REQUEST 0x00001000 #define S_RECV_REQUESTS 0x0000f000 #define S_REQUESTS 0x0000ff00 #define S_PATH_ERROR 0x00010000 #define S_SEND_ERRORS 0x000f0000 #define S_RESV_ERROR 0x00100000 #define S_RECV_ERRORS 0x00f00000 #define S_ERRORS 0x00ff0000 #define S_OPEN 0x01000000 #define S_SEND_NOT_REQUESTS (S_SEND_STATES | S_SEND_ERRORS) #define S_RECV_NOT_REQUESTS (S_RECV_STATES | S_RECV_ERRORS) #define S_SEND_ALL (S_SEND_STATES | S_SEND_REQUESTS | S_SEND_ERRORS) #define S_RECV_ALL (S_RECV_STATES | S_RECV_REQUESTS | S_RECV_ERRORS) struct sender { unsigned long status; struct SOCKADDR src; rapi_flowspec_t spec; struct sender *next; }; typedef struct sender sender; struct session { unsigned long status; struct SOCKADDR dst; int proto; scrapi_style style; enum qos_service_type service; sender *flows; }; typedef struct session session; int scrapi_errno = 0; static FILE *eout = stderr; static FILE *dout = NULL; static session sessions[MAXSESSIONS]; static struct sockaddr * get_rapi_filter(rapi_filter_t *p) { static struct SOCKADDR addr; switch(Object_Type(p)) { case RAPI_FILTERFORM_BASE: NET_SOCKADDR_UDP_IPv4(SAP4(&addr), p->rapi_filt4.sin_addr, p->rapi_filt4.sin_port); return(SAP(&addr)); #ifdef USE_IPV6 case RAPI_FILTERFORM_BASE6: NET_SOCKADDR_UDP_IPv6(SAP6(&addr), p->rapi_filt6.sin6_addr, p->rapi_filt6.sin6_port); return(SAP(&addr)); #endif /* USE_IPV6 */ default: return(NULL); } } static void set_rapi_filter(rapi_filter_t *p,struct sockaddr *host) { switch (host->sa_family) { case AF_INET: Object_Type(p) = RAPI_FILTERFORM_BASE; Object_Length(p) = sizeof(rapi_hdr_t) + sizeof(rapi_filter_base_t); p->rapi_filt4 = *SAP4(host); break; #ifdef USE_IPV6 case AF_INET6: Object_Type(p) = RAPI_FILTERFORM_BASE6; Object_Length(p) = sizeof(rapi_hdr_t) + sizeof(rapi_filter_base6_t); p->rapi_filt6 = *SAP6(host); break; #endif /* USE_IPV6 */ default: Object_Type(p) = RAPI_EMPTY_OTYPE; break; } } static sender * get_sender(rapi_sid_t sid,const struct sockaddr *src) { struct SOCKADDR host; sender *s,*w; for (s = sessions[sid].flows;s != NULL;s = s->next) if (sockaddr_equal(SAP(&s->src),src)) return(s); s = (sender *) malloc(sizeof(sender)); s->src = *(struct SOCKADDR *) src; s->status = S_NONE; /* * Apply wild address or port status. */ scrapi_sockaddr_any(SAP(&host),src->sa_family); for (w = sessions[sid].flows;w != NULL;w = w->next) { /* * Wild src ports take precedence over wild src * addresses. */ if (sockaddr_equal_wild(src,SAP(&w->src))) { s->status |= w->status & S_REQUESTS; break; } if (sockaddr_equal(SAP(&host),SAP(&w->src))) s->status |= w->status & S_REQUESTS; } s->next = sessions[sid].flows; sessions[sid].flows = s; return(s); } static void set_sender(rapi_sid_t sid,rapi_filter_t *filt,rapi_flowspec_t *spec) { rapi_flowspec_t *r; qos_flowspecx_t *q; qos_tspecx_t *t; struct sockaddr *src; session *sp; sender *s; t = &((rapi_tspec_t *) spec)->tspecbody_qosx; if (t->spec_type != QOS_TSPEC) return; src = get_rapi_filter(filt); sp = &sessions[sid]; s = get_sender(sid,src); r = &s->spec; Object_Type(r) = RAPI_FLOWSTYPE_Simplified; Object_Length(r) = sizeof(rapi_flowspec_t); q = &r->specbody_qosx; q->spec_type = sp->service; q->xspec_r = t->xtspec_r; q->xspec_R = t->xtspec_r; q->xspec_S = 0; q->xspec_b = t->xtspec_b; q->xspec_p = t->xtspec_p; q->xspec_m = t->xtspec_m; q->xspec_M = t->xtspec_M; s->status |= S_PATH; } static void mod_sender(sender *s,enum qos_service_type service,unsigned long status) { if (status == S_NONE) { /* * Must retain PATH state status when we turn off * a reservation. */ s->status &= ~S_RECV_ALL | S_PATH; return; } s->status &= ~S_RECV_REQUESTS; s->status |= status; s->spec.specbody_qosx.spec_type = service; } static void send_reservations_shared(rapi_sid_t sid,int n,rapi_flowspec_t *spec) { int i; session *sp; sender *s; rapi_filter_t *filter; sp = &sessions[sid]; filter = (rapi_filter_t *) malloc(n * sizeof(rapi_filter_t)); i = 0; for (s = sp->flows;s != NULL;s = s->next) { if (!(s->status & S_PATH)) continue; if (!(s->status & S_RESV_REQUEST)) continue; set_rapi_filter(&filter[i],SAP(&s->src)); spec[i++] = s->spec; } scrapi_errno = rapi_reserve(sid,RAPI_REQ_CONFIRM,NULL, RAPI_RSTYLE_SE,NULL,NULL,n,filter,1,spec); free(filter); } static void send_reservations_distinct(rapi_sid_t sid,int n) { int i; session *sp; sender *s; rapi_filter_t *filter; rapi_flowspec_t *spec; sp = &sessions[sid]; filter = (rapi_filter_t *) malloc(n * sizeof(rapi_filter_t)); spec = (rapi_flowspec_t *) malloc(n * sizeof(rapi_flowspec_t)); i = 0; for (s = sp->flows;s != NULL;s = s->next) { if (!(s->status & S_PATH)) continue; if (!(s->status & S_RESV_REQUEST)) continue; set_rapi_filter(&filter[i],SAP(&s->src)); spec[i++] = s->spec; } scrapi_errno = rapi_reserve(sid,RAPI_REQ_CONFIRM,NULL, RAPI_RSTYLE_FIXED,NULL,NULL,n,filter,n,spec); free(filter); free(spec); } static void send_reservations(rapi_sid_t sid) { int nflows,nreqs; session *sp; sender *s; rapi_flowspec_t spec; qos_flowspecx_t *q = &spec.specbody_qosx; sp = &sessions[sid]; Object_Type(&spec) = RAPI_FLOWSTYPE_Simplified; Object_Length(&spec) = sizeof(rapi_flowspec_t); q->spec_type = sp->service; q->xspec_r = 0; q->xspec_R = 0; q->xspec_S = ULONG_MAX; q->xspec_b = 0; q->xspec_p = 0; q->xspec_m = ULONG_MAX; q->xspec_M = 0; nflows = 0; nreqs = 0; for (s = sp->flows;s != NULL;s = s->next) { if (!(s->status & S_PATH)) continue; nflows++; if (!(s->status & S_RESV_REQUEST)) continue; q->xspec_r = C_MAX(q->xspec_r,s->spec.specbody_qosx.xspec_r); q->xspec_R = C_MAX(q->xspec_R,s->spec.specbody_qosx.xspec_r); q->xspec_S = C_MIN(q->xspec_S,s->spec.specbody_qosx.xspec_S); q->xspec_b = C_MAX(q->xspec_b,s->spec.specbody_qosx.xspec_b); q->xspec_p = C_MAX(q->xspec_p,s->spec.specbody_qosx.xspec_p); q->xspec_m = C_MIN(q->xspec_m,s->spec.specbody_qosx.xspec_m); q->xspec_M = C_MAX(q->xspec_M,s->spec.specbody_qosx.xspec_M); nreqs++; } if (nreqs == 0) { scrapi_errno = rapi_reserve(sid,0,NULL,RAPI_RSTYLE_SE, NULL,NULL,0,NULL,0,NULL); return; } switch (sp->style) { case scrapi_style_distinct: send_reservations_distinct(sid,nreqs); break; case scrapi_style_shared: if (nflows == nreqs) scrapi_errno = rapi_reserve(sid, RAPI_REQ_CONFIRM,NULL, RAPI_RSTYLE_WILDCARD,NULL,NULL, 0,NULL,1,&spec); else send_reservations_shared(sid,nreqs,&spec); break; default: } } static int close_session(rapi_sid_t sid) { session *sp; sender *s,*next; sp = &sessions[sid]; scrapi_sockaddr_any(SAP(&sp->dst),SAP(&sp->dst)->sa_family); for (s = sp->flows;s != NULL;s = next) { next = s->next; free(s); } sp->flows = NULL; sp->status = S_NONE; return(rapi_release(sid)); } static int timed_wait(rapi_sid_t sid,unsigned long flags,unsigned long msecs) { int n; session *sp = &sessions[sid]; struct timeval tv,tv1,tv2; fd_set rfds; if (msecs == 0) return(TRUE); tv.tv_sec = msecs / 1000; tv.tv_usec = 1000 * (msecs - 1000 * (msecs / 1000)); FD_ZERO(&rfds); FD_SET(rapi_getfd(sid),&rfds); do { scrapi_errno = rapi_dispatch(); if (scrapi_errno != RAPI_ERR_OK) break; if (sp->status & S_ERRORS) break; if (sp->status & flags) return(TRUE); tv2 = tv; gettimeofday(&tv1,NULL); n = select(FD_SETSIZE,&rfds,(fd_set *) NULL, (fd_set *) NULL,&tv2); gettimeofday(&tv2,NULL); tv.tv_sec -= tv2.tv_sec - tv1.tv_sec; tv.tv_usec -= tv2.tv_usec - tv1.tv_usec; } while (n == 1); return(FALSE); } static int fail(rapi_sid_t sid) { close_session(sid); return(FALSE); } static int callback(rapi_sid_t sid,rapi_eventinfo_t event,int style, int errcode,int errval,struct sockaddr *errnode,u_char errflag, int nfilts,rapi_filter_t *filt,int nspecs,rapi_flowspec_t *spec, int nadspecs,rapi_adspec_t *adspec,void *data) { int i; session *sp; sender *s; struct sockaddr *src; static void print_callback(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 *); if (dout) { print_callback(sid,event,style,errcode,errval,errnode,errflag, nfilts,filt,nspecs,spec,nadspecs,adspec,data); } sp = &sessions[sid]; switch (event) { case RAPI_PATH_EVENT: break; case RAPI_RESV_EVENT: if (nspecs == 0) sp->status &= ~S_RESV; else { sp->status |= S_RESV; sp->status &= ~S_PATH_ERROR; } return(0); case RAPI_RESV_CONFIRM: sp->status |= S_CONFIRM; sp->status &= ~S_RESV_ERROR; if (filt != NULL) { src = get_rapi_filter(filt); if (src != NULL) { s = get_sender(sid,src); s->status |= S_CONFIRM; s->status &= ~S_RESV_ERROR; } } return(0); case RAPI_PATH_ERROR: sp->status |= S_PATH_ERROR; return(0); case RAPI_RESV_ERROR: sp->status |= S_RESV_ERROR; sp->status &= ~S_CONFIRM; if (filt != NULL) { src = get_rapi_filter(filt); if (src != NULL) { s = get_sender(sid,src); s->status |= S_RESV_ERROR; s->status &= ~S_CONFIRM; } } return(0); default: return(0); } for (s = sp->flows;s != NULL;s = s->next) s->status &= ~S_PATH; nspecs = C_MIN(nspecs,nfilts); for (i = 0;i < nspecs; i++) { if (Object_Type(spec) != RAPI_TSPECTYPE_Simplified) continue; set_sender(sid,filt,spec); spec = Object_Next(rapi_flowspec_t,spec); filt = Object_Next(rapi_filter_t,filt); } for (s = sp->flows;s != NULL;s = s->next) if (!(s->status & S_PATH)) s->status &= ~S_RECV_NOT_REQUESTS; if (nspecs == 0) sp->status &= ~S_RECV_NOT_REQUESTS; send_reservations(sid); return(0); } static rapi_sid_t get_session(const struct sockaddr *dest,int proto) { int i; rapi_sid_t sid; session *sp; struct SOCKADDR dst; /* make a clean copy */ if (!sockaddr_assign(SAP(&dst),dest)) return(NULL_SID); for (i = 0;i < MAXSESSIONS; i++) { if (!sockaddr_equal(SAP(&dst),SAP(&sessions[i].dst))) continue; if (proto == sessions[i].proto) return(i); } sid = rapi_session(SAP(&dst),proto,0,&callback,NULL,&scrapi_errno); if (sid == NULL_SID) return(NULL_SID); sp = &sessions[sid]; sockaddr_assign(SAP(&sp->dst),SAP(&dst)); sp->proto = proto; sp->status = S_OPEN; sp->flows = NULL; return(sid); } /* * This is unfortunately very system dependent! */ static unsigned int max_packet_size() { int fd,mtu = MAX_PACKET_SIZE; struct ifconf ifc; struct ifreq ifr,*p,*last; static char buffer[MAX_INTERFACES * sizeof(struct ifreq) + sizeof(struct ifconf)]; fd = socket(AF_INET,SOCK_DGRAM,PF_UNSPEC); if (FAILED(fd)) return(mtu); ifc.ifc_buf = buffer; ifc.ifc_len = sizeof(buffer); if (FAILED(ioctl(fd,SIOCGIFCONF,(caddr_t) &ifc))) { close(fd); return(mtu); } last = ((struct ifreq *) ifc.ifc_req) + ifc.ifc_len; for (p = (struct ifreq *) ifc.ifc_req;p < last; #ifdef __FreeBSD__ p = (struct ifreq *) (((char *) &p->ifr_addr) + p->ifr_addr.sa_len)) { #else /* __FreeBSD__ */ p++) { #endif /* __FreeBSD__ */ if (strncmp(p->ifr_name,"",IFNAMSIZ) == 0) break; if (strncmp(p->ifr_name,"lo0",IFNAMSIZ) == 0) continue; switch (p->ifr_addr.sa_family) { case AF_INET: #ifdef USE_IPV6 case AF_INET6: #endif /* USE_IPV6 */ break; default: continue; } strncpy(ifr.ifr_name,p->ifr_name,IFNAMSIZ); if (FAILED(ioctl(fd,SIOCGIFMTU,(caddr_t) &ifr))) continue; mtu = C_MAX(mtu,ifr.ifr_metric); } close(fd); return(mtu); } /****************************************************************************** * * Simplified RAPI inteface. * *****************************************************************************/ int scrapi_sender(const struct sockaddr *dest,int proto,const struct sockaddr *src, double bw,int ttl,unsigned long msecs) { rapi_sid_t sid; session *sp; struct SOCKADDR host; rapi_tspec_t tspec; qos_tspecx_t *q = &tspec.tspecbody_qosx; scrapi_errno = rapi_dispatch(); if (scrapi_errno != RAPI_ERR_OK) return(FALSE); sid = get_session(dest,proto); if (sid == NULL_SID) return(FALSE); sp = &sessions[sid]; if (bw == 0) { /* * Stop sending PATH messages */ sp->status &= ~S_SEND_ALL; scrapi_errno = rapi_sender(sid,0,NULL,NULL,NULL, NULL,NULL,0); if (scrapi_errno != RAPI_ERR_OK) return(fail(sid)); return(TRUE); } if (src == NULL) { if (!scrapi_sockaddr_any(SAP(&host),dest->sa_family)) return(FALSE); } else { if (!sockaddr_assign(SAP(&host),src)) return(FALSE); } sp->status &= ~S_SEND_REQUESTS; sp->status |= S_PATH_REQUEST; q->spec_type = QOS_TSPEC; q->xtspec_r = bw; q->xtspec_b = 2 * bw; q->xtspec_p = 2 * bw; q->xtspec_m = MIN_PACKET_SIZE; q->xtspec_M = max_packet_size(); tspec.form = RAPI_TSPECTYPE_Simplified; tspec.len = sizeof(rapi_hdr_t) + sizeof(qos_tspecx_t); scrapi_errno = rapi_sender(sid,0,SAP(&host),NULL,&tspec,NULL,NULL,ttl); if (scrapi_errno != RAPI_ERR_OK) return(fail(sid)); return(timed_wait(sid,S_RESV,msecs)); } int scrapi_receiver(const struct sockaddr *dest,int proto, const struct sockaddr *src,int on,scrapi_service service, scrapi_style style,unsigned long msecs) { rapi_sid_t sid; session *sp; sender *s; struct SOCKADDR host,any; unsigned long status; scrapi_errno = rapi_dispatch(); if (scrapi_errno != RAPI_ERR_OK) return(FALSE); sid = get_session(dest,proto); if (sid == NULL_SID) return(FALSE); sp = &sessions[sid]; if (src == NULL) { if (!scrapi_sockaddr_any(SAP(&host),dest->sa_family)) return(FALSE); } else { /* FIX: reject wild address, non-wild port */ if (!sockaddr_assign(SAP(&host),src)) return(FALSE); } if (!scrapi_sockaddr_any(SAP(&any),dest->sa_family)) return(FALSE); sp->style = style; sp->service = (service == scrapi_service_cl) ? QOS_CNTR_LOAD : QOS_GUARANTEED; status = on ? S_RESV_REQUEST : S_NONE; mod_sender(get_sender(sid,SAP(&host)),sp->service,status); if (sockaddr_equal(SAP(&host),SAP(&any))) { /* * Apply the wild src address to all sources. */ for (s = sp->flows;s != NULL;s = s->next) mod_sender(s,sp->service,status); } else { /* * Apply the wild src port to all sources with the * same address. */ if (scrapi_sockaddr_get_port(src) == htons(0)) for (s = sp->flows;s != NULL;s = s->next) { if (!sockaddr_equal_wild(src,SAP(&s->src))) continue; mod_sender(s,sp->service,status); } } send_reservations(sid); return(timed_wait(sid,S_CONFIRM,msecs)); } int scrapi_close(const struct sockaddr *dest,int proto) { int i,ret = TRUE; rapi_sid_t sid; scrapi_errno = rapi_dispatch(); if (scrapi_errno != RAPI_ERR_OK) return(FALSE); if (dest != NULL) { sid = get_session(dest,proto); if (sid == NULL_SID) return(FALSE); return(close_session(sid)); } for (i = 0;i < MAXSESSIONS; i++) if (sessions[i].status & S_OPEN) ret |= close_session(i); return(ret); } int scrapi_dispatch() { scrapi_errno = rapi_dispatch(); return(scrapi_errno != RAPI_ERR_NORSVP); } int scrapi_getfd(const struct sockaddr *dest,int proto) { rapi_sid_t sid; sid = get_session(dest,proto); if (sid == NULL_SID) return(SYS_ERROR); return(rapi_getfd(sid)); } scrapi_status scrapi_get_status(const struct sockaddr *dest,int proto, const struct sockaddr *source) { rapi_sid_t sid; session *sp; sender *s; int confirm = FALSE,request = FALSE; scrapi_errno = rapi_dispatch(); if (scrapi_errno != RAPI_ERR_OK) return(scrapi_status_red); sid = get_session(dest,proto); if (sid == NULL_SID) return(scrapi_status_red); sp = &sessions[sid]; if (source == NULL) { if (sp->status & S_ERRORS) return(scrapi_status_red); if (sp->status & S_CONFIRM) return(scrapi_status_green); if (sp->status & S_RESV) return(scrapi_status_green); if (sp->status & S_REQUESTS) return(scrapi_status_yellow); return(scrapi_status_red); } if (scrapi_sockaddr_get_port(source) != htons(0)) { s = get_sender(sid,source); if (s->status & S_ERRORS) return(scrapi_status_red); if (s->status & S_CONFIRM) return(scrapi_status_green); if (s->status & S_REQUESTS) return(scrapi_status_yellow); return(scrapi_status_red); } /* * Apply the wild src port to all sources with the * same address. */ for (s = sp->flows;s != NULL;s = s->next) { if (!sockaddr_equal_wild(source,SAP(&s->src))) continue; if (s->status & S_ERRORS) return(scrapi_status_red); if (s->status & S_CONFIRM) confirm = TRUE; if (s->status & S_RECV_REQUESTS) request = TRUE; } if (confirm) return(scrapi_status_green); if (request) return(scrapi_status_yellow); return(scrapi_status_red); } const char * scrapi_errlist(int errno) { return(rapi_errlist[errno]); } void scrapi_perror(const char *str) { if (!eout) return; fprintf(eout,"%s: %s\n",str,rapi_errlist[scrapi_errno]); fflush(eout); } void scrapi_stderr(FILE *f) { eout = f; } void scrapi_debug(FILE *f) { dout = f; } /****************************************************************************** * * Utility functions for socket structures and the like. * *****************************************************************************/ #ifdef sun static const struct in_addr inaddr_any = {{{INADDR_ANY}}}; #else /* sun */ static const struct in_addr inaddr_any = {INADDR_ANY}; #endif /* sun */ int scrapi_sockaddr_parse(struct sockaddr *s,const char *addr,unsigned short port) { struct hostent *hp; struct in_addr in; #ifdef USE_IPV6 struct in6_addr in6; #endif /* USE_IPV6 */ if (inet_pton(AF_INET,addr,&in) == 1) { NET_SOCKADDR_UDP_IPv4(SAP4(s),in,port); return(TRUE); } hp = gethostbyname2(addr,AF_INET); if (hp != NULL) { memcpy(&in,hp->h_addr,hp->h_length); NET_SOCKADDR_UDP_IPv4(SAP4(s),in,port); return(TRUE); } #ifdef USE_IPV6 if (inet_pton(AF_INET6,addr,&in6) == 1) { NET_SOCKADDR_UDP_IPv6(SAP6(s),in6,port); return(TRUE); } hp = gethostbyname2(addr,AF_INET6); if (hp != NULL) { memcpy(&in6,hp->h_addr,hp->h_length); NET_SOCKADDR_UDP_IPv6(SAP6(s),in6,port); return(TRUE); } #endif /* USE_IPV6 */ return(FALSE); } const char * scrapi_sockaddr_print(const struct sockaddr *s) { static char buffer[MAX_ADDRPORTSTRLEN],buffer2[MAX_ADDRSTRLEN]; switch (s->sa_family) { case AF_INET: sprintf(buffer,"%s/%hu",inet_ntop(AF_INET, &SAP4(s)->sin_addr,buffer2,sizeof(buffer2)), ntohs(SAP4(s)->sin_port)); return(buffer); #ifdef USE_IPV6 case AF_INET6: sprintf(buffer,"%s/%hu",inet_ntop(AF_INET6, &SAP6(s)->sin6_addr,buffer2,sizeof(buffer2)), ntohs(SAP6(s)->sin6_port)); return(buffer); #endif /* USE_IPV6 */ default: return(NULL); } } int scrapi_sockaddr_multicast(const struct sockaddr *s) { switch (s->sa_family) { case AF_INET: return(IN_IS_ADDR_MULTICAST(&SAP4(s)->sin_addr)); #ifdef USE_IPV6 case AF_INET6: return(IN6_IS_ADDR_MULTICAST(&SAP6(s)->sin6_addr)); #endif /* USE_IPV6 */ default: return(FALSE); } } int scrapi_sockaddr_set_port(const struct sockaddr *s,unsigned short port) { switch (s->sa_family) { case AF_INET: SAP4(s)->sin_port = port; break; #ifdef USE_IPV6 case AF_INET6: SAP6(s)->sin6_port = port; break; #endif /* USE_IPV6 */ default: return(FALSE); } return(TRUE); } unsigned short scrapi_sockaddr_get_port(const struct sockaddr *s) { switch (s->sa_family) { case AF_INET: return(SAP4(s)->sin_port); #ifdef USE_IPV6 case AF_INET6: return(SAP6(s)->sin6_port); #endif /* USE_IPV6 */ default: return(0); } } int scrapi_sockaddr_any(struct sockaddr *s,int family) { switch (family) { case AF_INET: NET_SOCKADDR_UDP_IPv4(SAP4(s),inaddr_any,htons(0)); return(TRUE); #ifdef USE_IPV6 case AF_INET6: NET_SOCKADDR_UDP_IPv6(SAP6(s),in6addr_any,htons(0)); return(TRUE); #endif /* USE_IPV6 */ default: return(FALSE); } } static int sockaddr_equal(const struct sockaddr *x,const struct sockaddr *y) { if (x->sa_family != y->sa_family) return(FALSE); switch (x->sa_family) { case AF_INET: if (!IN_ARE_ADDR_EQUAL(&SAP4(x)->sin_addr, &SAP4(y)->sin_addr)) return(FALSE); return(SAP4(x)->sin_port == SAP4(y)->sin_port); #ifdef USE_IPV6 case AF_INET6: if (!IN6_ARE_ADDR_EQUAL(&SAP6(x)->sin6_addr, &SAP6(y)->sin6_addr)) return(FALSE); return(SAP6(x)->sin6_port == SAP6(y)->sin6_port); #endif /* USE_IPV6 */ default: return(FALSE); } } static int sockaddr_equal_wild(const struct sockaddr *x,const struct sockaddr *y) { if (x->sa_family != y->sa_family) return(FALSE); switch (x->sa_family) { case AF_INET: if (!IN_ARE_ADDR_EQUAL(&SAP4(x)->sin_addr, &SAP4(y)->sin_addr)) return(FALSE); if (SAP4(x)->sin_port == htons(0)) return(TRUE); if (SAP4(y)->sin_port == htons(0)) return(TRUE); return(SAP4(x)->sin_port == SAP4(y)->sin_port); #ifdef USE_IPV6 case AF_INET6: if (!IN6_ARE_ADDR_EQUAL(&SAP6(x)->sin6_addr, &SAP6(y)->sin6_addr)) return(FALSE); if (SAP6(x)->sin6_port == htons(0)) return(TRUE); if (SAP6(y)->sin6_port == htons(0)) return(TRUE); return(SAP6(x)->sin6_port == SAP6(y)->sin6_port); #endif /* USE_IPV6 */ default: return(FALSE); } } static int sockaddr_assign(struct sockaddr *x,const struct sockaddr *y) { switch (y->sa_family) { case AF_INET: NET_SOCKADDR_UDP_IPv4(SAP4(x),SAP4(y)->sin_addr, SAP4(y)->sin_port); return(TRUE); #ifdef USE_IPV6 case AF_INET6: NET_SOCKADDR_UDP_IPv6(SAP6(x),SAP6(y)->sin6_addr, SAP6(y)->sin6_port); return(TRUE); #endif /* USE_IPV6 */ default: return(FALSE); } } #ifndef __FreeBSD__ static const char * inet_ntop(int af,const void *src,char *dst,size_t size) { switch (af) { case AF_INET: if (size < INET_ADDRSTRLEN) return(NULL); strncpy(dst,inet_ntoa(*(struct in_addr *) src), INET_ADDRSTRLEN); return(dst); #ifdef USE_IPV6 case AF_INET6: if (size < INET6_ADDRSTRLEN) return(NULL); strncpy(dst,addr2ascii(AF_INET6, (struct in6_addr *) src, sizeof(struct in6_addr),NULL), INET6_ADDRSTRLEN); return(dst); #endif /* USE_IPV6 */ default: return(NULL); } } static int inet_pton(int af,const char *src,void *dst) { switch (af) { case AF_INET: ((struct in_addr *) dst)->s_addr = inet_addr(src); return((((struct in_addr *) dst)->s_addr == SYS_ERROR) ? FALSE : 1); #ifdef USE_IPV6 case AF_INET6: return((ascii2addr(AF_INET6,src,dst) == SYS_ERROR) ? FALSE : 1); #endif /* USE_IPV6 */ default: return(SYS_ERROR); } } static struct hostent * gethostbyname2(const char *name,int af) { switch (af) { case AF_INET: return(gethostbyname(name)); #ifdef USE_IPV6 case AF_INET6: return(hostname2addr(name,AF_INET6)); #endif /* USE_IPV6 */ default: return(NULL); } return(NULL); } #endif /* __FreeBSD__ */ static void print_callback( 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]; const char *str; int T, i; static char *rapi_rstyle_names[] = {"?", "WF", "FF", "SE"}; T = sid; /* Map sid into thread# T */ sprintf(out1, " Session= %.32s", scrapi_sockaddr_print(SAP(&sessions[T].dst))); fprintf(dout, "---------------------------------------------------------------\n"); switch (event) { case RAPI_PATH_EVENT: fprintf(dout,"T%d: Path Event -- %s\n", T, out1); if (flow_num == 0) fprintf(dout," (No Path state)\n"); break; case RAPI_RESV_EVENT: fprintf(dout,"T%d: Resv Event -- %s\n", T, out1); if (flow_num == 0) fprintf(dout," (No Resv state)\n"); isPath = 0; break; case RAPI_RESV_ERROR: isPath = 0; case RAPI_PATH_ERROR: fprintf(dout,"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) fprintf(dout," Style=%s", rapi_rstyle_names[styleid]); str = scrapi_sockaddr_print(errnode); str = (str != NULL) ? str : "(null)"; fprintf(dout," Code=%d Val=%d Node= %s", errcode, errval, str); if (errflags&RAPI_ERRF_InPlace) fprintf(dout," *InPlace*"); if (errflags&RAPI_ERRF_NotGuilty) fprintf(dout," *NotGuilt*"); fprintf(dout,"\n"); break; case RAPI_RESV_STATUS: isPath = 0; fprintf(dout,"T%d: Resv State -- %s:\n", T, out1); break; case RAPI_PATH_STATUS: fprintf(dout,"T%d: Path Stat -- %s:\n", T, out1); break; case RAPI_RESV_CONFIRM: isPath = 0; fprintf(dout,"T%d: Confirm Event -- %s:\n", T, out1); break; default: fprintf(dout,"!!?\n"); break; } for (i = 0; i < C_MAX(filt_num, flow_num); i++) { if (i < filt_num) { rapi_fmt_filtspec(filtp, buff, sizeof(buff)); fprintf(dout,"\t%s", buff); filtp = (rapi_filter_t *)After_RAPIObj(filtp); } else fprintf(dout,"\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)); fprintf(dout,"\t%s\n", buff); flowp = (rapi_flowspec_t *)After_RAPIObj(flowp); } else fprintf(dout,"\n"); if (i < adspec_num) { rapi_fmt_adspec(adsp, buff, sizeof(buff)); fprintf(dout,"\t\t%s\n", buff); adsp = (rapi_adspec_t *)After_RAPIObj(adsp); } } fprintf(dout, "---------------------------------------------------------------\n"); fflush(dout); return; }