[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/svc_vc.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*      $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl 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 #if defined(LIBC_SCCS) && !defined(lint)
 33 static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
 34 static char *sccsid = "@(#)svc_tcp.c    2.2 88/08/01 4.0 RPCSRC";
 35 #endif
 36 #include <sys/cdefs.h>
 37 __FBSDID("$FreeBSD: src/sys/rpc/svc_vc.c,v 1.4 2008/11/03 10:38:00 dfr Exp $");
 38 
 39 /*
 40  * svc_vc.c, Server side for Connection Oriented based RPC. 
 41  *
 42  * Actually implements two flavors of transporter -
 43  * a tcp rendezvouser (a listner and connection establisher)
 44  * and a record/tcp stream.
 45  */
 46 
 47 #include <sys/param.h>
 48 #include <sys/lock.h>
 49 #include <sys/kernel.h>
 50 #include <sys/malloc.h>
 51 #include <sys/mbuf.h>
 52 #include <sys/mutex.h>
 53 #include <sys/protosw.h>
 54 #include <sys/queue.h>
 55 #include <sys/socket.h>
 56 #include <sys/socketvar.h>
 57 #include <sys/sx.h>
 58 #include <sys/systm.h>
 59 #include <sys/uio.h>
 60 #include <netinet/tcp.h>
 61 
 62 #include <rpc/rpc.h>
 63 
 64 #include <rpc/rpc_com.h>
 65 
 66 static bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
 67     struct sockaddr **, struct mbuf **);
 68 static enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
 69 static void svc_vc_rendezvous_destroy(SVCXPRT *);
 70 static bool_t svc_vc_null(void);
 71 static void svc_vc_destroy(SVCXPRT *);
 72 static enum xprt_stat svc_vc_stat(SVCXPRT *);
 73 static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
 74     struct sockaddr **, struct mbuf **);
 75 static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
 76     struct sockaddr *, struct mbuf *);
 77 static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
 78 static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
 79     void *in);
 80 static SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
 81     struct sockaddr *raddr);
 82 static int svc_vc_accept(struct socket *head, struct socket **sop);
 83 static void svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
 84 
 85 static struct xp_ops svc_vc_rendezvous_ops = {
 86         .xp_recv =      svc_vc_rendezvous_recv,
 87         .xp_stat =      svc_vc_rendezvous_stat,
 88         .xp_reply =     (bool_t (*)(SVCXPRT *, struct rpc_msg *,
 89                 struct sockaddr *, struct mbuf *))svc_vc_null,
 90         .xp_destroy =   svc_vc_rendezvous_destroy,
 91         .xp_control =   svc_vc_rendezvous_control
 92 };
 93 
 94 static struct xp_ops svc_vc_ops = {
 95         .xp_recv =      svc_vc_recv,
 96         .xp_stat =      svc_vc_stat,
 97         .xp_reply =     svc_vc_reply,
 98         .xp_destroy =   svc_vc_destroy,
 99         .xp_control =   svc_vc_control
100 };
101 
102 struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
103         enum xprt_stat strm_stat;
104         struct mbuf *mpending;  /* unparsed data read from the socket */
105         struct mbuf *mreq;      /* current record being built from mpending */
106         uint32_t resid;         /* number of bytes needed for fragment */
107         bool_t eor;             /* reading last fragment of current record */
108 };
109 
110 /*
111  * Usage:
112  *      xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
113  *
114  * Creates, registers, and returns a (rpc) tcp based transporter.
115  * Once *xprt is initialized, it is registered as a transporter
116  * see (svc.h, xprt_register).  This routine returns
117  * a NULL if a problem occurred.
118  *
119  * The filedescriptor passed in is expected to refer to a bound, but
120  * not yet connected socket.
121  *
122  * Since streams do buffered io similar to stdio, the caller can specify
123  * how big the send and receive buffers are via the second and third parms;
124  * 0 => use the system default.
125  */
126 SVCXPRT *
127 svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
128     size_t recvsize)
129 {
130         SVCXPRT *xprt;
131         struct sockaddr* sa;
132         int error;
133 
134         if (so->so_state & SS_ISCONNECTED) {
135                 error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
136                 if (error)
137                         return (NULL);
138                 xprt = svc_vc_create_conn(pool, so, sa);
139                 free(sa, M_SONAME);
140                 return (xprt);
141         }
142 
143         xprt = svc_xprt_alloc();
144         sx_init(&xprt->xp_lock, "xprt->xp_lock");
145         xprt->xp_pool = pool;
146         xprt->xp_socket = so;
147         xprt->xp_p1 = NULL;
148         xprt->xp_p2 = NULL;
149         xprt->xp_ops = &svc_vc_rendezvous_ops;
150 
151         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
152         if (error)
153                 goto cleanup_svc_vc_create;
154 
155         memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
156         free(sa, M_SONAME);
157 
158         xprt_register(xprt);
159 
160         solisten(so, SOMAXCONN, curthread);
161 
162         SOCKBUF_LOCK(&so->so_rcv);
163         so->so_upcallarg = xprt;
164         so->so_upcall = svc_vc_soupcall;
165         so->so_rcv.sb_flags |= SB_UPCALL;
166         SOCKBUF_UNLOCK(&so->so_rcv);
167 
168         return (xprt);
169 cleanup_svc_vc_create:
170         if (xprt)
171                 svc_xprt_free(xprt);
172         return (NULL);
173 }
174 
175 /*
176  * Create a new transport for a socket optained via soaccept().
177  */
178 SVCXPRT *
179 svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
180 {
181         SVCXPRT *xprt = NULL;
182         struct cf_conn *cd = NULL;
183         struct sockaddr* sa = NULL;
184         struct sockopt opt;
185         int one = 1;
186         int error;
187 
188         bzero(&opt, sizeof(struct sockopt));
189         opt.sopt_dir = SOPT_SET;
190         opt.sopt_level = SOL_SOCKET;
191         opt.sopt_name = SO_KEEPALIVE;
192         opt.sopt_val = &one;
193         opt.sopt_valsize = sizeof(one);
194         error = sosetopt(so, &opt);
195         if (error)
196                 return (NULL);
197 
198         if (so->so_proto->pr_protocol == IPPROTO_TCP) {
199                 bzero(&opt, sizeof(struct sockopt));
200                 opt.sopt_dir = SOPT_SET;
201                 opt.sopt_level = IPPROTO_TCP;
202                 opt.sopt_name = TCP_NODELAY;
203                 opt.sopt_val = &one;
204                 opt.sopt_valsize = sizeof(one);
205                 error = sosetopt(so, &opt);
206                 if (error)
207                         return (NULL);
208         }
209 
210         cd = mem_alloc(sizeof(*cd));
211         cd->strm_stat = XPRT_IDLE;
212 
213         xprt = svc_xprt_alloc();
214         sx_init(&xprt->xp_lock, "xprt->xp_lock");
215         xprt->xp_pool = pool;
216         xprt->xp_socket = so;
217         xprt->xp_p1 = cd;
218         xprt->xp_p2 = NULL;
219         xprt->xp_ops = &svc_vc_ops;
220 
221         /*
222          * See http://www.connectathon.org/talks96/nfstcp.pdf - client
223          * has a 5 minute timer, server has a 6 minute timer.
224          */
225         xprt->xp_idletimeout = 6 * 60;
226 
227         memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
228 
229         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
230         if (error)
231                 goto cleanup_svc_vc_create;
232 
233         memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
234         free(sa, M_SONAME);
235 
236         xprt_register(xprt);
237 
238         SOCKBUF_LOCK(&so->so_rcv);
239         so->so_upcallarg = xprt;
240         so->so_upcall = svc_vc_soupcall;
241         so->so_rcv.sb_flags |= SB_UPCALL;
242         SOCKBUF_UNLOCK(&so->so_rcv);
243 
244         /*
245          * Throw the transport into the active list in case it already
246          * has some data buffered.
247          */
248         sx_xlock(&xprt->xp_lock);
249         xprt_active(xprt);
250         sx_xunlock(&xprt->xp_lock);
251 
252         return (xprt);
253 cleanup_svc_vc_create:
254         if (xprt) {
255                 mem_free(xprt, sizeof(*xprt));
256         }
257         if (cd)
258                 mem_free(cd, sizeof(*cd));
259         return (NULL);
260 }
261 
262 /*
263  * This does all of the accept except the final call to soaccept. The
264  * caller will call soaccept after dropping its locks (soaccept may
265  * call malloc).
266  */
267 int
268 svc_vc_accept(struct socket *head, struct socket **sop)
269 {
270         int error = 0;
271         struct socket *so;
272 
273         if ((head->so_options & SO_ACCEPTCONN) == 0) {
274                 error = EINVAL;
275                 goto done;
276         }
277 #ifdef MAC
278         SOCK_LOCK(head);
279         error = mac_socket_check_accept(td->td_ucred, head);
280         SOCK_UNLOCK(head);
281         if (error != 0)
282                 goto done;
283 #endif
284         ACCEPT_LOCK();
285         if (TAILQ_EMPTY(&head->so_comp)) {
286                 ACCEPT_UNLOCK();
287                 error = EWOULDBLOCK;
288                 goto done;
289         }
290         so = TAILQ_FIRST(&head->so_comp);
291         KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
292         KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
293 
294         /*
295          * Before changing the flags on the socket, we have to bump the
296          * reference count.  Otherwise, if the protocol calls sofree(),
297          * the socket will be released due to a zero refcount.
298          * XXX might not need soref() since this is simpler than kern_accept.
299          */
300         SOCK_LOCK(so);                  /* soref() and so_state update */
301         soref(so);                      /* file descriptor reference */
302 
303         TAILQ_REMOVE(&head->so_comp, so, so_list);
304         head->so_qlen--;
305         so->so_state |= (head->so_state & SS_NBIO);
306         so->so_qstate &= ~SQ_COMP;
307         so->so_head = NULL;
308 
309         SOCK_UNLOCK(so);
310         ACCEPT_UNLOCK();
311 
312         *sop = so;
313 
314         /* connection has been removed from the listen queue */
315         KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
316 done:
317         return (error);
318 }
319 
320 /*ARGSUSED*/
321 static bool_t
322 svc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
323     struct sockaddr **addrp, struct mbuf **mp)
324 {
325         struct socket *so = NULL;
326         struct sockaddr *sa = NULL;
327         int error;
328 
329         /*
330          * The socket upcall calls xprt_active() which will eventually
331          * cause the server to call us here. We attempt to accept a
332          * connection from the socket and turn it into a new
333          * transport. If the accept fails, we have drained all pending
334          * connections so we call xprt_inactive().
335          */
336         sx_xlock(&xprt->xp_lock);
337 
338         error = svc_vc_accept(xprt->xp_socket, &so);
339 
340         if (error == EWOULDBLOCK) {
341                 /*
342                  * We must re-test for new connections after taking
343                  * the lock to protect us in the case where a new
344                  * connection arrives after our call to accept fails
345                  * with EWOULDBLOCK. The pool lock protects us from
346                  * racing the upcall after our TAILQ_EMPTY() call
347                  * returns false.
348                  */
349                 ACCEPT_LOCK();
350                 mtx_lock(&xprt->xp_pool->sp_lock);
351                 if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
352                         xprt_inactive_locked(xprt);
353                 mtx_unlock(&xprt->xp_pool->sp_lock);
354                 ACCEPT_UNLOCK();
355                 sx_xunlock(&xprt->xp_lock);
356                 return (FALSE);
357         }
358 
359         if (error) {
360                 SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
361                 xprt->xp_socket->so_upcallarg = NULL;
362                 xprt->xp_socket->so_upcall = NULL;
363                 xprt->xp_socket->so_rcv.sb_flags &= ~SB_UPCALL;
364                 SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
365                 xprt_inactive(xprt);
366                 sx_xunlock(&xprt->xp_lock);
367                 return (FALSE);
368         }
369 
370         sx_xunlock(&xprt->xp_lock);
371 
372         sa = 0;
373         error = soaccept(so, &sa);
374 
375         if (error) {
376                 /*
377                  * XXX not sure if I need to call sofree or soclose here.
378                  */
379                 if (sa)
380                         free(sa, M_SONAME);
381                 return (FALSE);
382         }
383 
384         /*
385          * svc_vc_create_conn will call xprt_register - we don't need
386          * to do anything with the new connection.
387          */
388         if (!svc_vc_create_conn(xprt->xp_pool, so, sa))
389                 soclose(so);
390 
391         free(sa, M_SONAME);
392 
393         return (FALSE); /* there is never an rpc msg to be processed */
394 }
395 
396 /*ARGSUSED*/
397 static enum xprt_stat
398 svc_vc_rendezvous_stat(SVCXPRT *xprt)
399 {
400 
401         return (XPRT_IDLE);
402 }
403 
404 static void
405 svc_vc_destroy_common(SVCXPRT *xprt)
406 {
407         SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
408         xprt->xp_socket->so_upcallarg = NULL;
409         xprt->xp_socket->so_upcall = NULL;
410         xprt->xp_socket->so_rcv.sb_flags &= ~SB_UPCALL;
411         SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
412 
413         sx_destroy(&xprt->xp_lock);
414         if (xprt->xp_socket)
415                 (void)soclose(xprt->xp_socket);
416 
417         if (xprt->xp_netid)
418                 (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
419         svc_xprt_free(xprt);
420 }
421 
422 static void
423 svc_vc_rendezvous_destroy(SVCXPRT *xprt)
424 {
425 
426         svc_vc_destroy_common(xprt);
427 }
428 
429 static void
430 svc_vc_destroy(SVCXPRT *xprt)
431 {
432         struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
433 
434         svc_vc_destroy_common(xprt);
435 
436         if (cd->mreq)
437                 m_freem(cd->mreq);
438         if (cd->mpending)
439                 m_freem(cd->mpending);
440         mem_free(cd, sizeof(*cd));
441 }
442 
443 /*ARGSUSED*/
444 static bool_t
445 svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
446 {
447         return (FALSE);
448 }
449 
450 static bool_t
451 svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
452 {
453 
454         return (FALSE);
455 }
456 
457 static enum xprt_stat
458 svc_vc_stat(SVCXPRT *xprt)
459 {
460         struct cf_conn *cd;
461         struct mbuf *m;
462         size_t n;
463 
464         cd = (struct cf_conn *)(xprt->xp_p1);
465 
466         if (cd->strm_stat == XPRT_DIED)
467                 return (XPRT_DIED);
468 
469         /*
470          * Return XPRT_MOREREQS if we have buffered data and we are
471          * mid-record or if we have enough data for a record
472          * marker. Since this is only a hint, we read mpending and
473          * resid outside the lock. We do need to take the lock if we
474          * have to traverse the mbuf chain.
475          */
476         if (cd->mpending) {
477                 if (cd->resid)
478                         return (XPRT_MOREREQS);
479                 n = 0;
480                 sx_xlock(&xprt->xp_lock);
481                 m = cd->mpending;
482                 while (m && n < sizeof(uint32_t)) {
483                         n += m->m_len;
484                         m = m->m_next;
485                 }
486                 sx_xunlock(&xprt->xp_lock);
487                 if (n >= sizeof(uint32_t))
488                         return (XPRT_MOREREQS);
489         }
490 
491         if (soreadable(xprt->xp_socket))
492                 return (XPRT_MOREREQS);
493 
494         return (XPRT_IDLE);
495 }
496 
497 static bool_t
498 svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
499     struct sockaddr **addrp, struct mbuf **mp)
500 {
501         struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
502         struct uio uio;
503         struct mbuf *m;
504         XDR xdrs;
505         int error, rcvflag;
506 
507         /*
508          * Serialise access to the socket and our own record parsing
509          * state.
510          */
511         sx_xlock(&xprt->xp_lock);
512 
513         for (;;) {
514                 /*
515                  * If we have an mbuf chain in cd->mpending, try to parse a
516                  * record from it, leaving the result in cd->mreq. If we don't
517                  * have a complete record, leave the partial result in
518                  * cd->mreq and try to read more from the socket.
519                  */
520                 if (cd->mpending) {
521                         /*
522                          * If cd->resid is non-zero, we have part of the
523                          * record already, otherwise we are expecting a record
524                          * marker.
525                          */
526                         if (!cd->resid) {
527                                 /*
528                                  * See if there is enough data buffered to
529                                  * make up a record marker. Make sure we can
530                                  * handle the case where the record marker is
531                                  * split across more than one mbuf.
532                                  */
533                                 size_t n = 0;
534                                 uint32_t header;
535 
536                                 m = cd->mpending;
537                                 while (n < sizeof(uint32_t) && m) {
538                                         n += m->m_len;
539                                         m = m->m_next;
540                                 }
541                                 if (n < sizeof(uint32_t))
542                                         goto readmore;
543                                 if (cd->mpending->m_len < sizeof(uint32_t))
544                                         cd->mpending = m_pullup(cd->mpending,
545                                             sizeof(uint32_t));
546                                 memcpy(&header, mtod(cd->mpending, uint32_t *),
547                                     sizeof(header));
548                                 header = ntohl(header);
549                                 cd->eor = (header & 0x80000000) != 0;
550                                 cd->resid = header & 0x7fffffff;
551                                 m_adj(cd->mpending, sizeof(uint32_t));
552                         }
553 
554                         /*
555                          * Start pulling off mbufs from cd->mpending
556                          * until we either have a complete record or
557                          * we run out of data. We use m_split to pull
558                          * data - it will pull as much as possible and
559                          * split the last mbuf if necessary.
560                          */
561                         while (cd->mpending && cd->resid) {
562                                 m = cd->mpending;
563                                 if (cd->mpending->m_next
564                                     || cd->mpending->m_len > cd->resid)
565                                         cd->mpending = m_split(cd->mpending,
566                                             cd->resid, M_WAIT);
567                                 else
568                                         cd->mpending = NULL;
569                                 if (cd->mreq)
570                                         m_last(cd->mreq)->m_next = m;
571                                 else
572                                         cd->mreq = m;
573                                 while (m) {
574                                         cd->resid -= m->m_len;
575                                         m = m->m_next;
576                                 }
577                         }
578 
579                         /*
580                          * If cd->resid is zero now, we have managed to
581                          * receive a record fragment from the stream. Check
582                          * for the end-of-record mark to see if we need more.
583                          */
584                         if (cd->resid == 0) {
585                                 if (!cd->eor)
586                                         continue;
587 
588                                 /*
589                                  * Success - we have a complete record in
590                                  * cd->mreq.
591                                  */
592                                 xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
593                                 cd->mreq = NULL;
594                                 sx_xunlock(&xprt->xp_lock);
595 
596                                 if (! xdr_callmsg(&xdrs, msg)) {
597                                         XDR_DESTROY(&xdrs);
598                                         return (FALSE);
599                                 }
600 
601                                 *addrp = NULL;
602                                 *mp = xdrmbuf_getall(&xdrs);
603                                 XDR_DESTROY(&xdrs);
604 
605                                 return (TRUE);
606                         }
607                 }
608 
609         readmore:
610                 /*
611                  * The socket upcall calls xprt_active() which will eventually
612                  * cause the server to call us here. We attempt to
613                  * read as much as possible from the socket and put
614                  * the result in cd->mpending. If the read fails,
615                  * we have drained both cd->mpending and the socket so
616                  * we can call xprt_inactive().
617                  */
618                 uio.uio_resid = 1000000000;
619                 uio.uio_td = curthread;
620                 m = NULL;
621                 rcvflag = MSG_DONTWAIT;
622                 error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL,
623                     &rcvflag);
624 
625                 if (error == EWOULDBLOCK) {
626                         /*
627                          * We must re-test for readability after
628                          * taking the lock to protect us in the case
629                          * where a new packet arrives on the socket
630                          * after our call to soreceive fails with
631                          * EWOULDBLOCK. The pool lock protects us from
632                          * racing the upcall after our soreadable()
633                          * call returns false.
634                          */
635                         mtx_lock(&xprt->xp_pool->sp_lock);
636                         if (!soreadable(xprt->xp_socket))
637                                 xprt_inactive_locked(xprt);
638                         mtx_unlock(&xprt->xp_pool->sp_lock);
639                         sx_xunlock(&xprt->xp_lock);
640                         return (FALSE);
641                 }
642 
643                 if (error) {
644                         SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
645                         xprt->xp_socket->so_upcallarg = NULL;
646                         xprt->xp_socket->so_upcall = NULL;
647                         xprt->xp_socket->so_rcv.sb_flags &= ~SB_UPCALL;
648                         SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
649                         xprt_inactive(xprt);
650                         cd->strm_stat = XPRT_DIED;
651                         sx_xunlock(&xprt->xp_lock);
652                         return (FALSE);
653                 }
654 
655                 if (!m) {
656                         /*
657                          * EOF - the other end has closed the socket.
658                          */
659                         xprt_inactive(xprt);
660                         cd->strm_stat = XPRT_DIED;
661                         sx_xunlock(&xprt->xp_lock);
662                         return (FALSE);
663                 }
664 
665                 if (cd->mpending)
666                         m_last(cd->mpending)->m_next = m;
667                 else
668                         cd->mpending = m;
669         }
670 }
671 
672 static bool_t
673 svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
674     struct sockaddr *addr, struct mbuf *m)
675 {
676         XDR xdrs;
677         struct mbuf *mrep;
678         bool_t stat = TRUE;
679         int error;
680 
681         /*
682          * Leave space for record mark.
683          */
684         MGETHDR(mrep, M_WAIT, MT_DATA);
685         mrep->m_len = 0;
686         mrep->m_data += sizeof(uint32_t);
687 
688         xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
689 
690         if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
691             msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
692                 if (!xdr_replymsg(&xdrs, msg))
693                         stat = FALSE;
694                 else
695                         xdrmbuf_append(&xdrs, m);
696         } else {
697                 stat = xdr_replymsg(&xdrs, msg);
698         }
699 
700         if (stat) {
701                 m_fixhdr(mrep);
702 
703                 /*
704                  * Prepend a record marker containing the reply length.
705                  */
706                 M_PREPEND(mrep, sizeof(uint32_t), M_WAIT);
707                 *mtod(mrep, uint32_t *) =
708                         htonl(0x80000000 | (mrep->m_pkthdr.len
709                                 - sizeof(uint32_t)));
710                 error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
711                     0, curthread);
712                 if (!error) {
713                         stat = TRUE;
714                 }
715         } else {
716                 m_freem(mrep);
717         }
718 
719         XDR_DESTROY(&xdrs);
720         xprt->xp_p2 = NULL;
721 
722         return (stat);
723 }
724 
725 static bool_t
726 svc_vc_null()
727 {
728 
729         return (FALSE);
730 }
731 
732 static void
733 svc_vc_soupcall(struct socket *so, void *arg, int waitflag)
734 {
735         SVCXPRT *xprt = (SVCXPRT *) arg;
736 
737         xprt_active(xprt);
738 }
739 
740 #if 0
741 /*
742  * Get the effective UID of the sending process. Used by rpcbind, keyserv
743  * and rpc.yppasswdd on AF_LOCAL.
744  */
745 int
746 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
747         int sock, ret;
748         gid_t egid;
749         uid_t euid;
750         struct sockaddr *sa;
751 
752         sock = transp->xp_fd;
753         sa = (struct sockaddr *)transp->xp_rtaddr;
754         if (sa->sa_family == AF_LOCAL) {
755                 ret = getpeereid(sock, &euid, &egid);
756                 if (ret == 0)
757                         *uid = euid;
758                 return (ret);
759         } else
760                 return (-1);
761 }
762 #endif
763 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.