svc_dg.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* svc_dg.c, Server side for connectionless RPC.
*
* Does some caching in the hopes of achieving execute-at-most-once semantics.
*/
#include "mt.h"
#include "rpc_mt.h"
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef RPC_CACHE_DEBUG
#include <netconfig.h>
#include <netdir.h>
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
static struct xp_ops *svc_dg_ops();
static void cache_set();
static int cache_get();
/*
* kept in xprt->xp_p2
*/
struct svc_dg_data {
/* XXX: optbuf should be the first field, used by ti_opts.c code */
char *su_cache; /* cached data, NULL if none */
};
/*
* Usage:
* xprt = svc_dg_create(sock, sendsize, recvsize);
* Does other connectionless specific initializations.
* Once *xprt is initialized, it is registered.
* see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
* system defaults are chosen.
* The routines returns NULL if a problem occurred.
*/
static const char svc_dg_str[] = "svc_dg_create: %s";
static const char svc_dg_err1[] = "could not get transport information";
static const char svc_dg_err2[] = " transport does not support data transfer";
static const char svc_dg_err3[] =
"fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);";
static const char __no_mem_str[] = "out of memory";
/* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */
extern struct svc_auth_ops svc_auth_any_ops;
void
{
/* LINTED pointer alignment */
/* LINTED pointer alignment */
return;
}
if (rpc_buffer(xprt))
}
SVCXPRT *
int fd;
{
if (RPC_FD_NOTIN_FDSET(fd)) {
}
}
/*
* Find the receive and the send size
*/
}
goto freedata;
/* LINTED pointer alignment */
goto freedata;
goto freedata;
/* LINTED pointer alignment */
/* LINTED pointer alignment */
return (xprt);
if (xprt)
}
SVCXPRT *
int fd;
{
return (xprt);
}
SVCXPRT *
{
struct svc_dg_data *su;
return (NULL);
/* LINTED pointer alignment */
/* LINTED pointer alignment */
return (NULL);
}
}
return (NULL);
}
}
return (NULL);
}
== NULL) {
return (NULL);
}
/* LINTED pointer alignment */
return (NULL);
}
return (xprt);
}
/*ARGSUSED*/
static enum xprt_stat
{
trace1(TR_svc_dg_stat, 0);
return (XPRT_IDLE);
}
static bool_t
{
/* LINTED pointer alignment */
int moreflag;
/* XXX: tudata should have been made a part of the server handle */
trace1(TR_svc_dg_recv, 0);
moreflag = 0;
#ifdef RPC_DEBUG
#endif
int lookres;
(struct t_uderr *)0) < 0)) {
/*EMPTY*/
#ifdef RPC_DEBUG
"svc_dg_recv: t_rcvuderr t_errno = %d\n",
t_errno);
#endif
}
goto again;
goto again;
else {
return (FALSE);
}
}
if ((moreflag) ||
/*
* If moreflag is set, drop that data packet. Something wrong
*/
return (FALSE);
}
XDR_SETPOS(xdrs, 0);
return (FALSE);
}
char *reply;
/* tu_data.addr is already set */
return (FALSE);
}
}
/*
* get local ip address
*/
"svc_dg_recv: ip(udp), t_errno=%d, errno=%d",
}
"svc_dg_recv: ip (udp6), t_errno=%d, errno=%d",
}
return (FALSE);
}
}
}
}
return (TRUE);
}
static bool_t
{
/* LINTED pointer alignment */
trace1(TR_svc_dg_reply, 0);
} else
XDR_SETPOS(xdrs, 0);
/* LINTED pointer alignment */
xdr_location))) {
int slen;
}
} else {
goto try_again;
"svc_dg_reply: t_sndudata error t_errno=%d errno=%d\n",
}
}
return (stat);
}
static bool_t
{
trace1(TR_svc_dg_getargs, 0);
if (svc_mt_mode != RPC_SVC_MT_NONE)
/* LINTED pointer alignment */
return (dummy_stat1);
}
static bool_t
{
/* LINTED pointer alignment */
trace1(TR_svc_dg_freeargs, 0);
return (dummy_stat2);
}
static void
{
trace1(TR_svc_dg_destroy, 0);
}
void
{
if (svc_mt_mode != RPC_SVC_MT_NONE) {
/* LINTED pointer alignment */
/* LINTED pointer alignment */
/* LINTED pointer alignment */
/* LINTED pointer alignment */
return;
}
if (svc_mt_mode != RPC_SVC_MT_NONE)
else
}
/*ARGSUSED*/
static bool_t
void *in;
{
switch (rq) {
case SVCGET_XID:
return (FALSE);
} else {
/* LINTED pointer alignment */
return (TRUE);
}
default:
return (FALSE);
}
}
static struct xp_ops *
{
/* VARIABLES PROTECTED BY ops_lock: ops */
trace1(TR_svc_dg_ops, 0);
}
return (&ops);
}
/* The CACHING COMPONENT */
/*
* Could have been a separate file, but some part of it depends upon the
* private structure of the client handle.
*
* Fifo cache for cl server
* Copies pointers to reply buffers into fifo cache
* Buffers are sent again if retransmissions are detected.
*/
/*
* An entry in the cache
*/
typedef struct cache_node *cache_ptr;
struct cache_node {
/*
* Index into cache is xid, proc, vers, prog and address
*/
struct netbuf cache_addr;
/*
* The cached reply and length
*/
char *cache_reply;
/*
* Next node on the list, if there is a collision
*/
};
/*
* The entire cache
*/
struct cl_cache {
};
/*
* the hashing function
*/
extern mutex_t dupreq_lock;
/*
* Enable use of the cache. Returns 1 on success, 0 on failure.
* Note: there is no disable.
*/
static const char cache_enable_str[] = "svc_enablecache: %s %s";
static const char alloc_err[] = "could not allocate cache ";
static const char enable_err[] = "cache already enabled";
int
{
struct svc_dg_data *su;
/* LINTED pointer alignment */
/* LINTED pointer alignment */
else
/* LINTED pointer alignment */
enable_err, " ");
return (0);
}
alloc_err, " ");
return (0);
}
uc->uc_nextvictim = 0;
alloc_err, "data");
return (0);
}
alloc_err, "fifo");
return (0);
}
return (1);
}
/*
* Set an entry in the cache. It assumes that the uc entry is set from
* the earlier call to cache_get() for the same procedure. This will always
* happen because cache_get() is calle by svc_dg_recv and cache_set() is called
* by svc_dg_reply(). All this hoopla because the right RPC parameters are
* not available at svc_dg_reply time.
*/
static const char cache_set_str[] = "cache_set: %s";
static const char cache_set_err1[] = "victim not found";
static const char cache_set_err2[] = "victim alloc failed";
static const char cache_set_err3[] = "could not allocate new rpc buffer";
static void
{
struct svc_dg_data *su;
int my_mallocs = 0;
#ifdef RPC_CACHE_DEBUG
char *uaddr;
#endif
/* LINTED pointer alignment */
/* LINTED pointer alignment */
else
/* LINTED pointer alignment */
/* LINTED pointer alignment */
/*
* Find space for the new entry, either by
* reusing an old entry, or by mallocing a new one
*/
/* LINTED pointer alignment */
;
return;
}
} else {
return;
}
return;
}
my_mallocs = 1;
}
/*
* Store it away
*/
#ifdef RPC_CACHE_DEBUG
"cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
}
#endif
if (my_mallocs) {
}
return;
}
/* LINTED pointer alignment */
}
/*
* Try to get an entry from the cache
* return 1 if found, 0 if not found and set the stage for cache_set()
*/
static int
char **replyp;
{
struct svc_dg_data *su;
#ifdef RPC_CACHE_DEBUG
char *uaddr;
#endif
trace1(TR_cache_get, 0);
/* LINTED pointer alignment */
/* LINTED pointer alignment */
else
/* LINTED pointer alignment */
/* LINTED pointer alignment */
/* LINTED pointer alignment */
#ifdef RPC_CACHE_DEBUG
"cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
}
#endif
return (1);
}
}
/*
* Failed to find entry
* Remember a few things so we can do a set later
*/
return (0);
}