1 /* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 32 /* 33 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 34 */ 35 36 #if defined(LIBC_SCCS) && !defined(lint) 37 #ident "@(#)svc_dg.c 1.17 94/04/24 SMI" 38 #endif 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 /* 43 * svc_dg.c, Server side for connectionless RPC. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/lock.h> 48 #include <sys/kernel.h> 49 #include <sys/malloc.h> 50 #include <sys/mbuf.h> 51 #include <sys/mutex.h> 52 #include <sys/protosw.h> 53 #include <sys/queue.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 #include <sys/systm.h> 57 #include <sys/uio.h> 58 59 #include <rpc/rpc.h> 60 61 #include <rpc/rpc_com.h> 62 63 static enum xprt_stat svc_dg_stat(SVCXPRT *); 64 static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *); 65 static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *); 66 static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *); 67 static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *); 68 static void svc_dg_destroy(SVCXPRT *); 69 static bool_t svc_dg_control(SVCXPRT *, const u_int, void *); 70 static void svc_dg_soupcall(struct socket *so, void *arg, int waitflag); 71 72 static struct xp_ops svc_dg_ops = { 73 .xp_recv = svc_dg_recv, 74 .xp_stat = svc_dg_stat, 75 .xp_getargs = svc_dg_getargs, 76 .xp_reply = svc_dg_reply, 77 .xp_freeargs = svc_dg_freeargs, 78 .xp_destroy = svc_dg_destroy, 79 .xp_control = svc_dg_control, 80 }; 81 82 /* 83 * Usage: 84 * xprt = svc_dg_create(sock, sendsize, recvsize); 85 * Does other connectionless specific initializations. 86 * Once *xprt is initialized, it is registered. 87 * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable 88 * system defaults are chosen. 89 * The routines returns NULL if a problem occurred. 90 */ 91 static const char svc_dg_str[] = "svc_dg_create: %s"; 92 static const char svc_dg_err1[] = "could not get transport information"; 93 static const char svc_dg_err2[] = "transport does not support data transfer"; 94 static const char __no_mem_str[] = "out of memory"; 95 96 SVCXPRT * 97 svc_dg_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 98 size_t recvsize) 99 { 100 SVCXPRT *xprt; 101 struct __rpc_sockinfo si; 102 struct sockaddr* sa; 103 int error; 104 105 if (!__rpc_socket2sockinfo(so, &si)) { 106 printf(svc_dg_str, svc_dg_err1); 107 return (NULL); 108 } 109 /* 110 * Find the receive and the send size 111 */ 112 sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 113 recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 114 if ((sendsize == 0) || (recvsize == 0)) { 115 printf(svc_dg_str, svc_dg_err2); 116 return (NULL); 117 } 118 119 xprt = mem_alloc(sizeof (SVCXPRT)); 120 memset(xprt, 0, sizeof (SVCXPRT)); 121 mtx_init(&xprt->xp_lock, "xprt->xp_lock", NULL, MTX_DEF); 122 xprt->xp_pool = pool; 123 xprt->xp_socket = so; 124 xprt->xp_p1 = NULL; 125 xprt->xp_p2 = NULL; 126 xprt->xp_ops = &svc_dg_ops; 127 128 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 129 if (error) 130 goto freedata; 131 132 xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); 133 xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage); 134 xprt->xp_ltaddr.len = sa->sa_len; 135 memcpy(xprt->xp_ltaddr.buf, sa, sa->sa_len); 136 free(sa, M_SONAME); 137 138 xprt->xp_rtaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); 139 xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 140 xprt->xp_rtaddr.len = 0; 141 142 xprt_register(xprt); 143 144 SOCKBUF_LOCK(&so->so_rcv); 145 so->so_upcallarg = xprt; 146 so->so_upcall = svc_dg_soupcall; 147 so->so_rcv.sb_flags |= SB_UPCALL; 148 SOCKBUF_UNLOCK(&so->so_rcv); 149 150 return (xprt); 151 freedata: 152 (void) printf(svc_dg_str, __no_mem_str); 153 if (xprt) { 154 (void) mem_free(xprt, sizeof (SVCXPRT)); 155 } 156 return (NULL); 157 } 158 159 /*ARGSUSED*/ 160 static enum xprt_stat 161 svc_dg_stat(SVCXPRT *xprt) 162 { 163 164 return (XPRT_IDLE); 165 } 166 167 static bool_t 168 svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg) 169 { 170 struct uio uio; 171 struct sockaddr *raddr; 172 struct mbuf *mreq; 173 int error, rcvflag; 174 175 /* 176 * The socket upcall calls xprt_active() which will eventually 177 * cause the server to call us here. We attempt to read a 178 * packet from the socket and process it. If the read fails, 179 * we have drained all pending requests so we call 180 * xprt_inactive(). 181 * 182 * The lock protects us in the case where a new packet arrives 183 * on the socket after our call to soreceive fails with 184 * EWOULDBLOCK - the call to xprt_active() in the upcall will 185 * happen only after our call to xprt_inactive() which ensures 186 * that we will remain active. It might be possible to use 187 * SOCKBUF_LOCK for this - its not clear to me what locks are 188 * held during the upcall. 189 */ 190 mtx_lock(&xprt->xp_lock); 191 192 uio.uio_resid = 1000000000; 193 uio.uio_td = curthread; 194 mreq = NULL; 195 rcvflag = MSG_DONTWAIT; 196 error = soreceive(xprt->xp_socket, &raddr, &uio, &mreq, NULL, &rcvflag); 197 198 if (error == EWOULDBLOCK) { 199 xprt_inactive(xprt); 200 mtx_unlock(&xprt->xp_lock); 201 return (FALSE); 202 } 203 204 if (error) { 205 SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 206 xprt->xp_socket->so_upcallarg = NULL; 207 xprt->xp_socket->so_upcall = NULL; 208 xprt->xp_socket->so_rcv.sb_flags &= ~SB_UPCALL; 209 SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 210 xprt_inactive(xprt); 211 mtx_unlock(&xprt->xp_lock); 212 return (FALSE); 213 } 214 215 mtx_unlock(&xprt->xp_lock); 216 217 KASSERT(raddr->sa_len < xprt->xp_rtaddr.maxlen, 218 ("Unexpected remote address length")); 219 memcpy(xprt->xp_rtaddr.buf, raddr, raddr->sa_len); 220 xprt->xp_rtaddr.len = raddr->sa_len; 221 free(raddr, M_SONAME); 222 223 xdrmbuf_create(&xprt->xp_xdrreq, mreq, XDR_DECODE); 224 if (! xdr_callmsg(&xprt->xp_xdrreq, msg)) { 225 XDR_DESTROY(&xprt->xp_xdrreq); 226 return (FALSE); 227 } 228 xprt->xp_xid = msg->rm_xid; 229 230 return (TRUE); 231 } 232 233 static bool_t 234 svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg) 235 { 236 struct mbuf *mrep; 237 bool_t stat = FALSE; 238 int error; 239 240 MGETHDR(mrep, M_WAIT, MT_DATA); 241 MCLGET(mrep, M_WAIT); 242 mrep->m_len = 0; 243 244 xdrmbuf_create(&xprt->xp_xdrrep, mrep, XDR_ENCODE); 245 msg->rm_xid = xprt->xp_xid; 246 if (xdr_replymsg(&xprt->xp_xdrrep, msg)) { 247 m_fixhdr(mrep); 248 error = sosend(xprt->xp_socket, 249 (struct sockaddr *) xprt->xp_rtaddr.buf, NULL, mrep, NULL, 250 0, curthread); 251 if (!error) { 252 stat = TRUE; 253 } 254 } else { 255 m_freem(mrep); 256 } 257 258 /* 259 * This frees the request mbuf chain as well. The reply mbuf 260 * chain was consumed by sosend. 261 */ 262 XDR_DESTROY(&xprt->xp_xdrreq); 263 XDR_DESTROY(&xprt->xp_xdrrep); 264 xprt->xp_p2 = NULL; 265 266 return (stat); 267 } 268 269 static bool_t 270 svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) 271 { 272 273 return (xdr_args(&xprt->xp_xdrreq, args_ptr)); 274 } 275 276 static bool_t 277 svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) 278 { 279 XDR xdrs; 280 281 /* 282 * Free the request mbuf here - this allows us to handle 283 * protocols where not all requests have replies 284 * (i.e. NLM). Note that xdrmbuf_destroy handles being called 285 * twice correctly - the mbuf will only be freed once. 286 */ 287 XDR_DESTROY(&xprt->xp_xdrreq); 288 289 xdrs.x_op = XDR_FREE; 290 return (xdr_args(&xdrs, args_ptr)); 291 } 292 293 static void 294 svc_dg_destroy(SVCXPRT *xprt) 295 { 296 SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 297 xprt->xp_socket->so_upcallarg = NULL; 298 xprt->xp_socket->so_upcall = NULL; 299 xprt->xp_socket->so_rcv.sb_flags &= ~SB_UPCALL; 300 SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 301 302 xprt_unregister(xprt); 303 304 mtx_destroy(&xprt->xp_lock); 305 if (xprt->xp_socket) 306 (void)soclose(xprt->xp_socket); 307 308 if (xprt->xp_rtaddr.buf) 309 (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 310 if (xprt->xp_ltaddr.buf) 311 (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 312 (void) mem_free(xprt, sizeof (SVCXPRT)); 313 } 314 315 static bool_t 316 /*ARGSUSED*/ 317 svc_dg_control(xprt, rq, in) 318 SVCXPRT *xprt; 319 const u_int rq; 320 void *in; 321 { 322 323 return (FALSE); 324 } 325 326 static void 327 svc_dg_soupcall(struct socket *so, void *arg, int waitflag) 328 { 329 SVCXPRT *xprt = (SVCXPRT *) arg; 330 331 mtx_lock(&xprt->xp_lock); 332 xprt_active(xprt); 333 mtx_unlock(&xprt->xp_lock); 334 } 335