📄 rapi_lib.c
字号:
/* * @(#) $Id: rapi_lib.c,v 1.1.1.1 2000/05/08 22:51:24 wenqing Exp $ *//**************************************************************************** RSVPD -- ReSerVation Protocol Daemon USC Information Sciences Institute Marina del Rey, California Original Version: Don Hoffman, Sun Microsystems Current Version: Bob Braden, May 1996. 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.********************************************************************//* History: * Oct 94 Vers 1: Original code written by Don Hoffman @ Sun Microsystems * ??? 95 Vers 2: Updated by Bob Braden @ ISI * Aug 95 Vers 3: Update client calls to match ID07 protocol spec. * Sep 95 Vers 3.10: Add new calls rapi_session(), rapi_sender() as * alternative to rapi_register(). Also, included improvements developed by Joshua Gahm (JBG) at BBN. * Sep 95 Vers 3.11: Include adspecs in upcalls. * Apr 96 Vers 4.0: Remove non-reentrant rapi_errno variable. * Remove obs parameters and add some new ones. * Allow null rapi_sender call to imply path_tear. * Jun 97 Vers 5.01: [Rel4.1a6] Conform to final int-serv specs, and * to coming XOPEN document. * Aug 98 Vers 5.1: [Rel4.2a4] Support network byte order in pipe to * daemon. Require event_rtn param in session call. */#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 <sys/un.h>#include <sys/uio.h>#include <signal.h>#include <fcntl.h>#include <stddef.h>#include "config.h"#include "rsvp_socks.h"#include "rsvp.h"#include "rapi_lib.h"#include "rsvp_api.h"#include "rsvp_specs.h"/* IP protocol Ids for IPSEC: should come from some system * file. XXX */#define IPPROTID_IPSEC_ESP 50#define IPPROTID_IPSEC_AH 51/* Serial numbers to use in calls to connect_to_daemon to distinguish UNIX filenames for the pipes. NB: can only have one outstanding DEBUG connection to the server at a time, so not safe for multi-threaded use. */ #define MAIN_RSVP_CONNECTION_SERIAL_NUM 0 #define DEBUG_RSVP_CONNECTION_SERIAL_NUM 1 /* * Define an entry in client session table. */typedef struct Sid_info { api_addr dest; /* Destination addr, port */ u_char protid; /* Protocol Id */ u_char in_use; /* in-use flag */ u_char flags; /* Session flags */ rapi_event_rtn_t event_rtn; void *event_rtn_arg;} sid_rec;/* * Client session table; index into this table is * the session handle given to application. */static sid_rec sid_vec[MAX_RAPI_SESS];/* * Global variables */static int rapi_errno = RAPI_ERR_OK;static int pid, init_flag = 0;static int max_sid = 0; /* (To shorten linear search time) */char client_namestr[70]; /* Name of client send of socket */api_addr api_address2;net_addr api_address;/* Define empty RAPI and API objects: just header (framing) */int Empty_RObj[2] = {sizeof(rapi_hdr_t), 0};#define Empty_APIObj Empty_RObj /* empty API object */#define Empty_Flowspec (rapi_flowspec_t *) &Empty_RObj#define Empty_Filter (rapi_filter_t *) &Empty_RObj /* JBG: the single socket that will be connected to the * RSVP server. All individual sids will have their socket * fields set to this value when they are in use. */ static int rsvp_socket = -1; static int rsvp_socket_refs = 0; #define mark_sid_inuse(sid_to_mark) \if (! sid_vec[sid_to_mark].in_use) \ rsvp_socket_refs++; \sid_vec[sid_to_mark].in_use = 1; #define mark_sid_free(sid_to_mark) \if (sid_vec[sid_to_mark].in_use) \ rsvp_socket_refs--; \sid_vec[sid_to_mark].in_use = 0; /* * Forward declarations */static rapi_sid_t common_register(rapi_sid_t, struct sockaddr *, int, rapi_filter_t *, rapi_tspec_t *, rapi_adspec_t *, rapi_policy_t *, int);static int rapi_dispatch_fd(int);static int Get_free_slot();static void sig_pipe(int sig);static int init_rapi();static int connect_to_daemon(int);static int send_req(rsvp_req *, int, long, int);static char *copy_policy_i2d(rapi_policy_t *, rapi_policy_t *, char *, int);static char *copy_flowspec_i2d(rapi_flowspec_t *, API_Flowspec *, char *);static char *copy_tspec_i2d(rapi_tspec_t *, API_TSpec *, char *);static char *copy_adspec_i2d(rapi_adspec_t *, API_Adspec *, char *);static char *copy_filterspec_i2d(rapi_filter_t *, API_FilterSpec *, char *);static int copy_flowspec_d2i(API_Flowspec *, rapi_flowspec_t *, char *, int);static int copy_tspec_d2i(API_TSpec *, rapi_tspec_t *, char *, int);static int copy_filterspec_d2i(API_FilterSpec *, rapi_filter_t *, char *);static int copy_adspec_d2i(API_Adspec *, rapi_adspec_t *, char *, int);static char *copy_sender_desc(rapi_filter_t *, rapi_tspec_t *, rapi_adspec_t *, API_FlowDesc *, char *);void sockaddr2filterbase(struct sockaddr *, rapi_filter_t *);int CSZXtoG_spec(qos_flowspecx_t *, IS_specbody_t *);int CSZXtoGen_tspec(qos_tspecx_t *, IS_tspbody_t *);int CSZXtoCL_spec(qos_flowspecx_t *, IS_specbody_t *);int CSZXtoIS_adspec(qos_adspecx_t *, IS_adsbody_t *);int CLtoCSZX_spec(IS_specbody_t *, qos_flowspecx_t *);int GtoCSZX_spec(IS_specbody_t *, qos_flowspecx_t *);int GentoCSZX_tspec(IS_tspbody_t *, qos_tspecx_t *);int IStoCSZX_adspec(IS_adsbody_t *, qos_adspecx_t *);int writev();int List_Length(char *, int);int vDstPort_OK(api_addr *, int);int api_addr_assign(api_addr *addr,const struct sockaddr *s);int sockaddr_assign(struct sockaddr *s,const api_addr *addr);#ifdef USE_NET_BOvoid hton_rapi_cmd(rapi_cmd_t *);/* External declarations * */int hton_rapi_flowspec();int ntoh_rapi_flowspec();int hton_rapi_adspec();int ntoh_rapi_adspec();#endif /* USE_NET_BO */#ifdef sunextern int gethostname(char *,int);#endif /* sun */#define is_valid(sid) (init_flag && sid <= max_sid && (sid_vec[sid].in_use))#define IS2RAPI_len(x) (4*(x) + sizeof(rapi_hdr_t) + sizeof(IS_main_hdr_t))#define RAPI2IS_len(y) wordsof((y)- sizeof(rapi_hdr_t) - sizeof(IS_main_hdr_t))#define API_IsPath(x) ((x)->resp_type == RAPI_PATH_EVENT || \ (x)->resp_type == RAPI_PATH_ERROR || \ (x)->resp_type == RAPI_PATH_STATUS)/* Check "GPI-ness" of filter spec or sender template: it should * have form _GPI or _GPI6 if and only if the session has the GPI * flag on. Return TRUE iff GPI-ness matches. */#define GPIness_matches(fp) (((flags&RAPI_GPI_SESSION)!=0) == \ ((fp->form == RAPI_FILTERFORM_GPI)|(fp->form == RAPI_FILTERFORM_GPI6)))#define Protid_OK(pid, flags) (!(flags&RAPI_GPI_SESSION) || \ pid == IPPROTID_IPSEC_AH || pid == IPPROTID_IPSEC_ESP)/* For IPSEC, (virtual) dest port must be non-zero. * (I have no idea why...!) */char *rapi_rstyle_names[] = {"?", "WF", "FF", "SE"};/********************************************************** * Visible RAPI Routines * **********************************************************//* rapi_session(): * Register with the RSVP daemon, creating a new API session. * If successful, return local session id, else return -1 and * set error code in variable. */rapi_sid_trapi_session( struct sockaddr *dest, /* Destination host, port */ int protid, int flags, rapi_event_rtn_t event_rtn, void * event_rtn_arg, int *errnop) { rapi_sid_t sid = NULL_SID; if (dest == NULL || event_rtn == NULL) { rapi_errno = RAPI_ERR_INVAL; goto exit; } if (!init_flag) { if (init_rapi() < 0) { rapi_errno = RAPI_ERR_NORSVP; goto exit; } } /* Locate empty session slot */ if ((int)(sid = Get_free_slot()) < 0) { rapi_errno = RAPI_ERR_MAXSESS; goto exit; } mark_sid_inuse(sid); /* Mark it in use */ sid_vec[sid].protid = protid; sid_vec[sid].flags = (flags &= (RAPI_USE_INTSERV|RAPI_GPI_SESSION)); api_addr_assign(&sid_vec[sid].dest,dest); sid_vec[sid].event_rtn = event_rtn; sid_vec[sid].event_rtn_arg = event_rtn_arg; /* For GPI_SESSION flag (IPSEC), check that protocol Id * is correct for IPSEC. (because the spec calls for it). */ if (!Protid_OK(protid, flags)) { rapi_errno = RAPI_ERR_BADPROTO; goto exit; } if (!vDstPort_OK(&sid_vec[sid].dest, flags)) { rapi_errno = RAPI_ERR_BADVDPORT; goto exit; } rapi_errno = common_register(sid, NULL, flags, NULL, NULL, NULL,NULL, 0);exit: if (rapi_errno != RAPI_ERR_OK) { mark_sid_free(sid); sid = NULL_SID; } if (errnop) *errnop = rapi_errno; return sid;}/* rapi_sender(): * Set/modify sender parameters. */intrapi_sender( rapi_sid_t sid, int flags, /* Currently, none used */ struct sockaddr *LHost, /* Sender host, port (optional) */ rapi_filter_t * sender_template, rapi_tspec_t * sender_tspec, rapi_adspec_t * sender_adspec, rapi_policy_t * sender_policy, int ttl) { rapi_errno = RAPI_ERR_OK; if (!is_valid(sid)) return RAPI_ERR_BADSID; /* sid_vec[sid].flags |= flags; (None defined) */ /* Assumes session and sender flags are distinct. */ if ((LHost||sender_template) && !sender_tspec) return RAPI_ERR_NOTSPEC; rapi_errno = common_register(sid, LHost, flags, sender_template, sender_tspec, sender_adspec, sender_policy, ttl); return (rapi_errno);}/* rapi_reserve(): * Make/modify/delete reservation for session. * */intrapi_reserve( rapi_sid_t sid, int rflags, struct sockaddr * rhost, /* Receiver host (optional) */ rapi_styleid_t styleid, rapi_stylex_t * style_ext, /* style extension */ rapi_policy_t * rcvr_policy, int n_filter, rapi_filter_t * filter_spec_list, int n_flow, rapi_flowspec_t * flowspec_list) { char *req_buf = NULL, *cp, *End_buf; rsvp_req *req = (rsvp_req *) req_buf; int i, len, n1, n2, nflwd, flags; rapi_filter_t *rfiltp; rapi_flowspec_t *rflowp; rapi_errno = RAPI_ERR_OK; if (!is_valid(sid)) return RAPI_ERR_BADSID; /* Check parameters according to style */ flags = sid_vec[sid].flags; /* session flags */ rfiltp = filter_spec_list; rflowp = flowspec_list; nflwd = 0; switch (styleid) { case RAPI_RSTYLE_WILDCARD: if (n_flow == 0) break; /* Teardown case */ if (n_filter < 0 || n_filter > 1 || n_flow != 1) return RAPI_ERR_N_FFS; if (rflowp == NULL) return RAPI_ERR_INVAL; nflwd = 1; break; case RAPI_RSTYLE_FIXED: if (n_flow == 0) break; /* Teardown case */ if (n_filter != n_flow || n_filter <= 0) return RAPI_ERR_N_FFS; if (rfiltp == NULL || rflowp == NULL) return RAPI_ERR_INVAL; nflwd = n_filter; break; case RAPI_RSTYLE_SE: if (n_flow == 0) break; /* Teardown case */ if (n_flow != 1 || n_filter <= 0) { return RAPI_ERR_N_FFS; } if (rfiltp == NULL || rflowp == NULL) return RAPI_ERR_INVAL; nflwd = n_filter; break; default: return RAPI_ERR_BADSTYLE; } /* Must scan parm lists to get total length in order to * dynamically alloc buffer. */ if ((n1 = List_Length( (char *)rflowp, n_flow)) < 0 || (n2 = List_Length( (char *)rfiltp, n_filter)) < 0) { return RAPI_ERR_INVAL; } else len = sizeof(rsvp_req) + n1 + n2 + abs(n_flow - n_filter)*sizeof( Empty_RObj ); if (!(req_buf = malloc(len))) return RAPI_ERR_MEMFULL; req = (rsvp_req *) req_buf; End_buf = req_buf + len; memset((char *)req, 0, len); req->rq_style = (u_char) styleid; req->rq_type = API2_RESV; req->rq_dest = sid_vec[sid].dest; req->rq_protid = sid_vec[sid].protid; if (rhost) api_addr_assign(&req->rq_host, rhost); else req->rq_host = api_address2; req->rq_nflwd = nflwd;#ifdef USE_NET_BO HTON16(req->rq_nflwd);#endif req->rq_flags = (rflags &= (RAPI_REQ_CONFIRM)); cp = copy_policy_i2d(rcvr_policy, req->rq_policy, End_buf, 1); if (!cp) goto exit; /* If n_flow == 0, simply remove existing reservation (without * releasing API session). */ if (n_flow == 0) { req->rq_nflwd = 0; (void)send_req(req, cp - req_buf, sid, rsvp_socket); goto exit; } /* * Copy ({flowspec|EMPTY}, {filter_spec|EMPTY}) pairs * into request. Note that copy_xxxx_i2d() routines * check that there is room in buffer and if not, set * rapi_errno and return NULL. * * copy_flowspec_i2d translates contents into Intserv format. * copy_filterspec_i2d (currently) simply copies without change. */ for (i = 0; i < nflwd; i++) { if (i < n_filter) { if (!GPIness_matches(rfiltp)) { /* The IPSEC document does not say this must be * checked in the API, but for consistency it * should be. */ rapi_errno = RAPI_ERR_GPI_CONFLICT; goto exit; } } cp = (char *)copy_filterspec_i2d( (i < n_filter)? rfiltp : Empty_Filter, (API_FilterSpec *)cp, End_buf); if (!cp) goto exit; cp = copy_flowspec_i2d((i < n_flow)? rflowp : Empty_Flowspec, (API_Flowspec *)cp, End_buf); if (!cp) goto exit; if (i < n_filter) rfiltp = (rapi_filter_t *) After_RAPIObj(rfiltp); if (i < n_flow) rflowp = (rapi_flowspec_t *) After_RAPIObj(rflowp); } (void)send_req(req, cp - req_buf, sid, rsvp_socket);exit: if (req_buf) free(req_buf); return rapi_errno;}/* rapi_release(): * Delete API session and free session handle. */intrapi_release(rapi_sid_t sid) { char req_buf[MAX_MSG]; /* TBD: dyn alloc */ rsvp_req *req = (rsvp_req *) req_buf; if (!is_valid(sid)) return RAPI_ERR_BADSID; memset(req_buf, 0, sizeof req_buf); /* Redundant, but cautious */ req->rq_nflwd = 0; req->rq_type = API_CLOSE; (void)send_req(req, sizeof(rsvp_req), sid, rsvp_socket); mark_sid_free(sid); return (RAPI_ERR_OK);}/* rapi_getfd(): * Return file descriptor for socket used now. */intrapi_getfd(rapi_sid_t sid) { if (!is_valid(sid)) return -1; return rsvp_socket;}/* rapi_dispatch(): * Dispatch upcalls. */intrapi_dispatch() { fd_set tmp_fds; int fd_wid; struct timeval tout; rapi_errno = RAPI_ERR_OK; if (rsvp_socket == -1) return RAPI_ERR_OK; FD_ZERO(&tmp_fds); FD_SET(rsvp_socket, &tmp_fds); fd_wid = rsvp_socket+1; memset(&tout, 0, sizeof(tout)); /* Poll for input ready on socket */ if (select(fd_wid, &tmp_fds, NULL, NULL, &tout) <= 0) return RAPI_ERR_OK; if (FD_ISSET(rsvp_socket, &tmp_fds))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -