📄 svc_udp.c
字号:
/* @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC *//* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */#if 0static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";#endif/* * svc_udp.c, * Server side for UDP/IP based RPC. (Does some caching in the hopes of * achieving execute-at-most-once semantics.) * * Copyright (C) 1984, Sun Microsystems, Inc. */#define __FORCE_GLIBC#define _GNU_SOURCE#include <features.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <rpc/rpc.h>#include <sys/socket.h>#include <errno.h>#ifdef IP_PKTINFO#include <sys/uio.h>#endif#ifdef USE_IN_LIBIO# include <wchar.h># include <libio/iolibio.h># define fputs(s, f) _IO_fputs (s, f)#endif#define rpc_buffer(xprt) ((xprt)->xp_p1)#ifndef MAX#define MAX(a, b) ((a > b) ? a : b)#endifstatic bool_t svcudp_recv (SVCXPRT *, struct rpc_msg *);static bool_t svcudp_reply (SVCXPRT *, struct rpc_msg *);static enum xprt_stat svcudp_stat (SVCXPRT *);static bool_t svcudp_getargs (SVCXPRT *, xdrproc_t, caddr_t);static bool_t svcudp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);static void svcudp_destroy (SVCXPRT *);static const struct xp_ops svcudp_op ={ svcudp_recv, svcudp_stat, svcudp_getargs, svcudp_reply, svcudp_freeargs, svcudp_destroy};static int cache_get (SVCXPRT *, struct rpc_msg *, char **replyp, u_long *replylenp);static void cache_set (SVCXPRT *xprt, u_long replylen);/* * kept in xprt->xp_p2 */struct svcudp_data { u_int su_iosz; /* byte size of send.recv buffer */ u_long su_xid; /* transaction id */ XDR su_xdrs; /* XDR handle */ char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ char *su_cache; /* cached data, NULL if no cache */ };#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))/* * Usage: * xprt = svcudp_create(sock); * * If sock<0 then a socket is created, else sock is used. * If the socket, sock is not bound to a port then svcudp_create * binds it to an arbitrary port. In any (successful) case, * xprt->xp_sock is the registered socket number and xprt->xp_port is the * associated port number. * Once *xprt is initialized, it is registered as a transporter; * see (svc.h, xprt_register). * The routines returns NULL if a problem occurred. */SVCXPRT *svcudp_bufcreate (sock, sendsz, recvsz) int sock; u_int sendsz, recvsz;{ bool_t madesock = FALSE; SVCXPRT *xprt; struct svcudp_data *su; struct sockaddr_in addr; socklen_t len = sizeof (struct sockaddr_in); int pad; void *buf; if (sock == RPC_ANYSOCK) { if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror (_("svcudp_create: socket creation problem")); return (SVCXPRT *) NULL; } madesock = TRUE; } memset ((char *) &addr, 0, sizeof (addr)); addr.sin_family = AF_INET; if (bindresvport (sock, &addr)) { addr.sin_port = 0; (void) bind (sock, (struct sockaddr *) &addr, len); } if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0) { perror (_("svcudp_create - cannot getsockname")); if (madesock) (void) close (sock); return (SVCXPRT *) NULL; } xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT)); su = (struct svcudp_data *) mem_alloc (sizeof (*su)); buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4); if (xprt == NULL || su == NULL || buf == NULL) {#ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) __fwprintf (stderr, L"%s", _("svcudp_create: out of memory\n")); else#endif (void) fputs (_("svcudp_create: out of memory\n"), stderr); mem_free (xprt, sizeof (SVCXPRT)); mem_free (su, sizeof (*su)); mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4); return NULL; } su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4; rpc_buffer (xprt) = buf; xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_p2 = (caddr_t) su; xprt->xp_verf.oa_base = su->su_verfbody; xprt->xp_ops = &svcudp_op; xprt->xp_port = ntohs (addr.sin_port); xprt->xp_sock = sock;#ifdef IP_PKTINFO if ((sizeof (struct iovec) + sizeof (struct msghdr) + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo)) > sizeof (xprt->xp_pad)) {# ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) __fwprintf (stderr, L"%s", _("svcudp_create: xp_pad is too small for IP_PKTINFO\n")); else# endif (void) fputs (_("svcudp_create: xp_pad is too small for IP_PKTINFO\n"), stderr); return NULL; } pad = 1; if (setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad, sizeof (pad)) == 0) /* Set the padding to all 1s. */ pad = 0xff; else#endif /* Clear the padding. */ pad = 0; memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad)); xprt_register (xprt); return xprt;}SVCXPRT *svcudp_create (sock) int sock;{ return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);}static enum xprt_statsvcudp_stat (xprt) SVCXPRT *xprt;{ return XPRT_IDLE;}static bool_tsvcudp_recv (xprt, msg) SVCXPRT *xprt; struct rpc_msg *msg;{ struct svcudp_data *su = su_data (xprt); XDR *xdrs = &(su->su_xdrs); int rlen; char *reply; u_long replylen; socklen_t len; /* It is very tricky when you have IP aliases. We want to make sure that we are sending the packet from the IP address where the incoming packet is addressed to. H.J. */#ifdef IP_PKTINFO struct iovec *iovp; struct msghdr *mesgp;#endifagain: /* FIXME -- should xp_addrlen be a size_t? */ len = (socklen_t) sizeof(struct sockaddr_in);#ifdef IP_PKTINFO iovp = (struct iovec *) &xprt->xp_pad [0]; mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)]; if (mesgp->msg_iovlen) { iovp->iov_base = rpc_buffer (xprt); iovp->iov_len = su->su_iosz; mesgp->msg_iov = iovp; mesgp->msg_iovlen = 1; mesgp->msg_name = &(xprt->xp_raddr); mesgp->msg_namelen = len; mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec) + sizeof (struct msghdr)]; mesgp->msg_controllen = sizeof(xprt->xp_pad) - sizeof (struct iovec) - sizeof (struct msghdr); rlen = recvmsg (xprt->xp_sock, mesgp, 0); if (rlen >= 0) len = mesgp->msg_namelen; } else#endif rlen = recvfrom (xprt->xp_sock, rpc_buffer (xprt), (int) su->su_iosz, 0, (struct sockaddr *) &(xprt->xp_raddr), &len); xprt->xp_addrlen = len; if (rlen == -1 && errno == EINTR) goto again; if (rlen < 16) /* < 4 32-bit ints? */ return FALSE; xdrs->x_op = XDR_DECODE; XDR_SETPOS (xdrs, 0); if (!xdr_callmsg (xdrs, msg)) return FALSE; su->su_xid = msg->rm_xid; if (su->su_cache != NULL) { if (cache_get (xprt, msg, &reply, &replylen)) {#ifdef IP_PKTINFO if (mesgp->msg_iovlen) { iovp->iov_base = reply; iovp->iov_len = replylen; (void) sendmsg (xprt->xp_sock, mesgp, 0); } else#endif (void) sendto (xprt->xp_sock, reply, (int) replylen, 0, (struct sockaddr *) &xprt->xp_raddr, len); return TRUE; } } return TRUE;}static bool_tsvcudp_reply (xprt, msg) SVCXPRT *xprt; struct rpc_msg *msg;{ struct svcudp_data *su = su_data (xprt); XDR *xdrs = &(su->su_xdrs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -