xref: /illumos-gate/usr/src/cmd/rpcbind/rpcb_stat.c (revision 9498083eeaed1aacdde41369b7fa6f3b84870791)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * rpcb_stat.c
24  * Allows for gathering of statistics
25  *
26  * Copyright (c) 1990 by Sun Microsystems, Inc.
27  */
28 /*
29  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
30  */
31 
32 #include <stdio.h>
33 #include <netconfig.h>
34 #include <rpc/rpc.h>
35 #include <rpc/rpcb_prot.h>
36 #include <sys/stat.h>
37 #ifdef PORTMAP
38 #include <rpc/pmap_prot.h>
39 #endif
40 #include <stdlib.h>
41 #include <atomic.h>
42 #include <assert.h>
43 #include <thread.h>
44 #include <synch.h>
45 #include <string.h>
46 #include "rpcbind.h"
47 
48 static rpcb_stat_byvers inf;
49 static rwlock_t inf_lock = DEFAULTRWLOCK;
50 
51 void
52 rpcbs_procinfo(int rtype, rpcproc_t proc)
53 {
54 	assert(rtype >= 0 && rtype < RPCBVERS_STAT);
55 
56 #ifdef PORTMAP
57 	if ((rtype == RPCBVERS_2_STAT) && (proc > rpcb_highproc_2))
58 		return;
59 #else
60 	assert(rtype != RPCBVERS_2_STAT);
61 #endif
62 
63 	if ((rtype == RPCBVERS_3_STAT) && (proc > rpcb_highproc_3))
64 		return;
65 
66 	if ((rtype == RPCBVERS_4_STAT) && (proc > rpcb_highproc_4))
67 		return;
68 
69 	atomic_add_int((uint_t *)&inf[rtype].info[proc], 1);
70 }
71 
72 void
73 rpcbs_set(int rtype, bool_t success)
74 {
75 	assert(rtype >= 0 && rtype < RPCBVERS_STAT);
76 
77 	if (success == FALSE)
78 		return;
79 
80 	atomic_add_int((uint_t *)&inf[rtype].setinfo, 1);
81 }
82 
83 void
84 rpcbs_unset(int rtype, bool_t success)
85 {
86 	assert(rtype >= 0 && rtype < RPCBVERS_STAT);
87 
88 	if (success == FALSE)
89 		return;
90 
91 	atomic_add_int((uint_t *)&inf[rtype].unsetinfo, 1);
92 }
93 
94 void
95 rpcbs_getaddr(int rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
96     char *uaddr)
97 {
98 	rpcbs_addrlist *al;
99 	rpcbs_addrlist *s;
100 	rpcbs_addrlist *wal;
101 	struct netconfig *nconf;
102 
103 	assert(rtype >= 0 && rtype < RPCBVERS_STAT);
104 
105 	/*
106 	 * First try with read lock only.
107 	 */
108 	(void) rw_rdlock(&inf_lock);
109 	for (s = al = inf[rtype].addrinfo; al; al = al->next) {
110 		if ((al->prog == prog) && (al->vers == vers) &&
111 		    (strcmp(al->netid, netid) == 0)) {
112 			(void) rw_unlock(&inf_lock);
113 
114 			if ((uaddr == NULL) || (uaddr[0] == NULL))
115 				atomic_add_int((uint_t *)&al->failure, 1);
116 			else
117 				atomic_add_int((uint_t *)&al->success, 1);
118 
119 			return;
120 		}
121 	}
122 	(void) rw_unlock(&inf_lock);
123 
124 	/*
125 	 * If not found, we will likely need to add a new entry,
126 	 * so pre-allocate it, and then try to search again with write lock.
127 	 */
128 	nconf = rpcbind_get_conf(netid);
129 	if (nconf == NULL) {
130 		return;
131 	}
132 
133 	al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist));
134 	if (al == NULL) {
135 		return;
136 	}
137 
138 	al->prog = prog;
139 	al->vers = vers;
140 	al->netid = nconf->nc_netid;
141 	if ((uaddr == NULL) || (uaddr[0] == NULL)) {
142 		al->failure = 1;
143 		al->success = 0;
144 	} else {
145 		al->failure = 0;
146 		al->success = 1;
147 	}
148 
149 	(void) rw_wrlock(&inf_lock);
150 	for (wal = inf[rtype].addrinfo; wal != s; wal = wal->next) {
151 		if ((wal->prog == prog) && (wal->vers == vers) &&
152 		    (strcmp(wal->netid, netid) == 0)) {
153 			(void) rw_unlock(&inf_lock);
154 
155 			free(al);
156 
157 			if ((uaddr == NULL) || (uaddr[0] == NULL))
158 				atomic_add_int((uint_t *)&wal->failure, 1);
159 			else
160 				atomic_add_int((uint_t *)&wal->success, 1);
161 
162 			return;
163 		}
164 	}
165 
166 	al->next = inf[rtype].addrinfo;
167 	inf[rtype].addrinfo = al;
168 	(void) rw_unlock(&inf_lock);
169 }
170 
171 /*
172  * rpcbproc - rpcbind proc number on which this was called
173  */
174 void
175 rpcbs_rmtcall(int rtype, rpcproc_t rpcbproc, rpcprog_t prog, rpcvers_t vers,
176     rpcproc_t proc, char *netid, rpcblist_ptr rbl)
177 {
178 	rpcbs_rmtcalllist *rl;
179 	rpcbs_rmtcalllist *s;
180 	rpcbs_rmtcalllist *wrl;
181 	struct netconfig *nconf;
182 
183 	assert(rtype >= 0 && rtype < RPCBVERS_STAT);
184 
185 	/*
186 	 * First try with read lock only.
187 	 */
188 	(void) rw_rdlock(&inf_lock);
189 	for (s = rl = inf[rtype].rmtinfo; rl; rl = rl->next) {
190 		if ((rl->prog == prog) && (rl->vers == vers) &&
191 		    (rl->proc == proc) && (strcmp(rl->netid, netid) == 0)) {
192 			(void) rw_unlock(&inf_lock);
193 
194 			if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers))
195 				atomic_add_int((uint_t *)&rl->failure, 1);
196 			else
197 				atomic_add_int((uint_t *)&rl->success, 1);
198 			if (rpcbproc == RPCBPROC_INDIRECT)
199 				atomic_add_int((uint_t *)&rl->indirect, 1);
200 
201 			return;
202 		}
203 	}
204 	(void) rw_unlock(&inf_lock);
205 
206 	/*
207 	 * If not found, we will likely need to add a new entry,
208 	 * so pre-allocate it, and then try to search again with write lock.
209 	 */
210 	nconf = rpcbind_get_conf(netid);
211 	if (nconf == NULL) {
212 		return;
213 	}
214 
215 	rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist));
216 	if (rl == NULL) {
217 		return;
218 	}
219 
220 	rl->prog = prog;
221 	rl->vers = vers;
222 	rl->proc = proc;
223 	rl->netid = nconf->nc_netid;
224 	if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) {
225 		rl->failure = 1;
226 		rl->success = 0;
227 	} else {
228 		rl->failure = 0;
229 		rl->success = 1;
230 	}
231 	rl->indirect = rpcbproc == RPCBPROC_INDIRECT ? 1 : 0;
232 
233 	(void) rw_wrlock(&inf_lock);
234 	for (wrl = inf[rtype].rmtinfo; wrl != s; wrl = wrl->next) {
235 		if ((wrl->prog == prog) && (wrl->vers == vers) &&
236 		    (wrl->proc == proc) && (strcmp(wrl->netid, netid) == 0)) {
237 			(void) rw_unlock(&inf_lock);
238 
239 			free(rl);
240 
241 			if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers))
242 				atomic_add_int((uint_t *)&wrl->failure, 1);
243 			else
244 				atomic_add_int((uint_t *)&wrl->success, 1);
245 			if (rpcbproc == RPCBPROC_INDIRECT)
246 				atomic_add_int((uint_t *)&wrl->indirect, 1);
247 
248 			return;
249 		}
250 	}
251 
252 	rl->next = inf[rtype].rmtinfo;
253 	inf[rtype].rmtinfo = rl;
254 	(void) rw_unlock(&inf_lock);
255 }
256 
257 /* ARGSUSED */
258 bool_t
259 rpcbproc_getstat(void *argp, rpcb_stat_byvers **result)
260 {
261 	/*
262 	 * inf_lock is unlocked in xdr_rpcb_stat_byvers_ptr()
263 	 */
264 	(void) rw_rdlock(&inf_lock);
265 	*result = &inf;
266 	return (TRUE);
267 }
268 
269 bool_t
270 xdr_rpcb_stat_byvers_ptr(XDR *xdrs, rpcb_stat_byvers **objp)
271 {
272 	if (xdrs->x_op == XDR_FREE) {
273 		/*
274 		 * inf_lock is locked in rpcbproc_getstat()
275 		 */
276 		(void) rw_unlock(&inf_lock);
277 		return (TRUE);
278 	}
279 
280 	return (xdr_rpcb_stat_byvers(xdrs, (rpcb_stat *)*objp));
281 }
282