/* * Usage: * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); * * Creates, registers, and returns a (rpc) tcp based transporter. * Once *xprt is initialized, it is registered as a transporter * see (svc.h, xprt_register). This routine returns * a NULL if a problem occurred. * * The filedescriptor passed in is expected to refer to a bound, but * not yet connected socket. * * Since streams do buffered io similar to stdio, the caller can specify * how big the send and receive buffers are via the second and third parms; * 0 => use the system default. */ SVCXPRT * svc_vc_create(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt = NULL; struct cf_rendezvous *r = NULL; struct __rpc_sockinfo si; struct sockaddr_storage sslocal; socklen_t slen; if (!__rpc_fd2sockinfo(fd, &si)) return NULL; r = mem_alloc(sizeof(*r)); if (r == NULL) { warnx("svc_vc_create: out of memory"); goto cleanup_svc_vc_create; } r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); r->maxrec = __svc_maxrec; xprt = mem_alloc(sizeof(SVCXPRT)); if (xprt == NULL) { warnx("svc_vc_create: out of memory"); goto cleanup_svc_vc_create; } xprt->xp_tp = NULL; xprt->xp_p1 = r; xprt->xp_p2 = NULL; xprt->xp_p3 = NULL; xprt->xp_verf = _null_auth; svc_vc_rendezvous_ops(xprt); xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ xprt->xp_fd = fd; slen = sizeof (struct sockaddr_storage); if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { warnx("svc_vc_create: could not retrieve local addr"); goto cleanup_svc_vc_create; } xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); if (xprt->xp_ltaddr.buf == NULL) { warnx("svc_vc_create: no mem for local addr"); goto cleanup_svc_vc_create; } memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); xprt_register(xprt); return (xprt); cleanup_svc_vc_create: if (xprt) mem_free(xprt, sizeof(*xprt)); if (r != NULL) mem_free(r, sizeof(*r)); return (NULL); }
static SVCXPRT * makefd_xprt(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct cf_conn *cd; const char *netid; struct __rpc_sockinfo si; assert(fd != -1); xprt = mem_alloc(sizeof(SVCXPRT)); if (xprt == NULL) { warnx("svc_vc: makefd_xprt: out of memory"); goto done; } memset(xprt, 0, sizeof *xprt); cd = mem_alloc(sizeof(struct cf_conn)); if (cd == NULL) { warnx("svc_tcp: makefd_xprt: out of memory"); mem_free(xprt, sizeof(SVCXPRT)); xprt = NULL; goto done; } cd->strm_stat = XPRT_IDLE; xdrrec_create(&(cd->xdrs), sendsize, recvsize, xprt, read_vc, write_vc); xprt->xp_p1 = cd; xprt->xp_verf.oa_base = cd->verf_body; svc_vc_ops(xprt); /* truely deals with calls */ xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ xprt->xp_fd = fd; if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) xprt->xp_netid = strdup(netid); xprt_register(xprt); done: return (xprt); }
/* * Create a client handle for a connection. * Default options are set, which the user can change using clnt_control()'s. * The rpc/vc package does buffering similar to stdio, so the client * must pick send and receive buffer sizes, 0 => use the default. * NB: fd is copied into a private area. * NB: The rpch->cl_auth is set null authentication. Caller may wish to * set this something more useful. * * fd should be an open socket * * fd - open file descriptor * raddr - servers address * prog - program number * vers - version number * sendsz - buffer send size * recvsz - buffer recv size */ CLIENT * clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog, const rpcvers_t vers, u_int sendsz, u_int recvsz) { CLIENT *cl; /* client handle */ struct ct_data *ct = NULL; /* client handle */ struct timeval now; struct rpc_msg call_msg; static u_int32_t disrupt; sigset_t mask; sigset_t newmask; struct sockaddr_storage ss; socklen_t slen; struct __rpc_sockinfo si; if (disrupt == 0) disrupt = (u_int32_t)(long)raddr; cl = (CLIENT *)mem_alloc(sizeof (*cl)); ct = (struct ct_data *)mem_alloc(sizeof (*ct)); if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { (void) syslog(LOG_ERR, clnt_vc_errstr, clnt_vc_str, __no_mem_str); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto err; } ct->ct_addr.buf = NULL; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); if (vc_fd_locks == (int *) NULL) { int cv_allocsz, fd_allocsz; int dtbsize = __rpc_dtbsize(); fd_allocsz = dtbsize * sizeof (int); vc_fd_locks = (int *) mem_alloc(fd_allocsz); if (vc_fd_locks == (int *) NULL) { mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } else memset(vc_fd_locks, '\0', fd_allocsz); assert(vc_cv == (cond_t *) NULL); cv_allocsz = dtbsize * sizeof (cond_t); vc_cv = (cond_t *) mem_alloc(cv_allocsz); if (vc_cv == (cond_t *) NULL) { mem_free(vc_fd_locks, fd_allocsz); vc_fd_locks = (int *) NULL; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } else { int i; for (i = 0; i < dtbsize; i++) cond_init(&vc_cv[i], 0, (void *) 0); } } else assert(vc_cv != (cond_t *) NULL); /* * XXX - fvdl connecting while holding a mutex? */ slen = sizeof ss; if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { if (errno != ENOTCONN) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); goto err; } } mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); if (!__rpc_fd2sockinfo(fd, &si)) goto err; ct->ct_closeit = FALSE; /* * Set up private data struct */ ct->ct_fd = fd; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr.buf = malloc(raddr->maxlen); if (ct->ct_addr.buf == NULL) goto err; memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); ct->ct_addr.len = raddr->len; ct->ct_addr.maxlen = raddr->maxlen; /* * Initialize call message */ (void)gettimeofday(&now, NULL); call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = (u_int32_t)prog; call_msg.rm_call.cb_vers = (u_int32_t)vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void)_close(fd); } goto err; } ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); XDR_DESTROY(&(ct->ct_xdrs)); assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ cl->cl_ops = clnt_vc_ops(); cl->cl_private = ct; cl->cl_auth = authnone_create(); sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, cl->cl_private, read_vc, write_vc); return (cl); err: if (ct) { if (ct->ct_addr.len) mem_free(ct->ct_addr.buf, ct->ct_addr.len); mem_free(ct, sizeof (struct ct_data)); } if (cl) mem_free(cl, sizeof (CLIENT)); return ((CLIENT *)NULL); }
SVCXPRT * svc_dg_ncreate(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct svc_dg_data *su = NULL; struct __rpc_sockinfo si; struct sockaddr_storage ss; socklen_t slen; uint32_t oflags; if (!__rpc_fd2sockinfo(fd, &si)) { __warnx(TIRPC_DEBUG_FLAG_SVC_DG, svc_dg_str, svc_dg_err1); return (NULL); } /* * Find the receive and the send size */ sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); if ((sendsize == 0) || (recvsize == 0)) { __warnx(TIRPC_DEBUG_FLAG_SVC_DG, svc_dg_str, svc_dg_err2); return (NULL); } xprt = mem_alloc(sizeof (SVCXPRT)); if (xprt == NULL) goto freedata; memset(xprt, 0, sizeof (SVCXPRT)); /* Init SVCXPRT locks, etc */ mutex_init(&xprt->xp_lock, NULL); mutex_init(&xprt->xp_auth_lock, NULL); su = mem_alloc(sizeof (*su)); if (su == NULL) goto freedata; su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) goto freedata; xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_flags = SVC_XPRT_FLAG_NONE; xprt->xp_refcnt = 1; xprt->xp_fd = fd; xprt->xp_p2 = su; svc_dg_ops(xprt); xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); slen = sizeof ss; if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) goto freedata; __rpc_set_netbuf(&xprt->xp_ltaddr, &ss, slen); switch (ss.ss_family) { case AF_INET: xprt->xp_port = ntohs(((struct sockaddr_in *) &ss)->sin_port); break; #ifdef INET6 case AF_INET6: xprt->xp_port = ntohs(((struct sockaddr_in6 *) &ss)->sin6_port); break; #endif case AF_LOCAL: /* no port */ break; default: break; } /* Enable reception of IP*_PKTINFO control msgs */ svc_dg_enable_pktinfo(fd, &si); /* Make reachable */ xprt->xp_p5 = rpc_dplx_lookup_rec(xprt->xp_fd, RPC_DPLX_FLAG_NONE, &oflags); /* ref+1 */ svc_rqst_init_xprt(xprt); /* Conditional xprt_register */ if (! (__svc_params->flags & SVC_FLAG_NOREG_XPRTS)) xprt_register(xprt); return (xprt); freedata: __warnx(TIRPC_DEBUG_FLAG_SVC_DG, svc_dg_str, __no_mem_str); if (xprt) { if (su) (void) mem_free(su, sizeof (*su)); svc_rqst_finalize_xprt(xprt, SVC_RQST_FLAG_NONE); (void) mem_free(xprt, sizeof (SVCXPRT)); } return (NULL); }
/* * Create a client handle for a connection. * Default options are set, which the user can change using clnt_control()'s. * The rpc/vc package does buffering similar to stdio, so the client * must pick send and receive buffer sizes, 0 => use the default. * NB: fd is copied into a private area. * NB: The rpch->cl_auth is set null authentication. Caller may wish to * set this something more useful. * * fd should be an open socket */ CLIENT * clnt_vc_create( int fd, const struct netbuf *raddr, rpcprog_t prog, rpcvers_t vers, u_int sendsz, u_int recvsz ) { CLIENT *h; struct ct_data *ct = NULL; struct rpc_msg call_msg; #ifdef _REENTRANT sigset_t mask; #endif sigset_t newmask; struct sockaddr_storage ss; socklen_t slen; struct __rpc_sockinfo si; _DIAGASSERT(raddr != NULL); h = mem_alloc(sizeof(*h)); if (h == NULL) { warnx("clnt_vc_create: out of memory"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } ct = mem_alloc(sizeof(*ct)); if (ct == NULL) { warnx("clnt_vc_create: out of memory"); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } __clnt_sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); #ifdef _REENTRANT mutex_lock(&clnt_fd_lock); if (vc_fd_locks == NULL) { size_t cv_allocsz, fd_allocsz; int dtbsize = __rpc_dtbsize(); fd_allocsz = dtbsize * sizeof (int); vc_fd_locks = mem_alloc(fd_allocsz); if (vc_fd_locks == NULL) { goto blooy; } else memset(vc_fd_locks, '\0', fd_allocsz); _DIAGASSERT(vc_cv == NULL); cv_allocsz = dtbsize * sizeof (cond_t); vc_cv = mem_alloc(cv_allocsz); if (vc_cv == NULL) { mem_free(vc_fd_locks, fd_allocsz); vc_fd_locks = NULL; goto blooy; } else { int i; for (i = 0; i < dtbsize; i++) cond_init(&vc_cv[i], 0, (void *) 0); } } else _DIAGASSERT(vc_cv != NULL); #endif /* * XXX - fvdl connecting while holding a mutex? */ slen = sizeof ss; if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { if (errno != ENOTCONN) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto blooy; } if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto blooy; } } mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); if (!__rpc_fd2sockinfo(fd, &si)) goto fooy; ct->ct_closeit = FALSE; /* * Set up private data struct */ ct->ct_fd = fd; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr.buf = malloc((size_t)raddr->maxlen); if (ct->ct_addr.buf == NULL) goto fooy; memcpy(ct->ct_addr.buf, raddr->buf, (size_t)raddr->len); ct->ct_addr.len = raddr->len; ct->ct_addr.maxlen = raddr->maxlen; /* * Initialize call message */ call_msg.rm_xid = __RPC_GETXID(); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = (u_int32_t)prog; call_msg.rm_call.cb_vers = (u_int32_t)vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void)close(fd); } goto fooy; } ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); XDR_DESTROY(&(ct->ct_xdrs)); /* * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ h->cl_ops = clnt_vc_ops(); h->cl_private = ct; h->cl_auth = authnone_create(); sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, h->cl_private, read_vc, write_vc); return (h); blooy: mutex_unlock(&clnt_fd_lock); thr_sigsetmask(SIG_SETMASK, &(mask), NULL); fooy: /* * Something goofed, free stuff and barf */ if (ct) mem_free(ct, sizeof(struct ct_data)); if (h) mem_free(h, sizeof(CLIENT)); return (NULL); }
/* * Generic client creation: returns client handle. * Default options are set, which the user can * change using the rpc equivalent of _ioctl()'s : clnt_control(). * If fd is RPC_ANYFD, it will be opened using nconf. * It will be bound if not so. * If sizes are 0; appropriate defaults will be chosen. */ CLIENT * clnt_tli_create(int fd, const struct netconfig *nconf, struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, uint sendsz, uint recvsz) { CLIENT *cl; /* client handle */ bool_t madefd = FALSE; /* whether fd opened here */ long servtype; int one = 1; struct __rpc_sockinfo si; extern int __rpc_minfd; if (fd == RPC_ANYFD) { if (nconf == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } fd = __rpc_nconf2fd(nconf); if (fd == -1) goto err; if (fd < __rpc_minfd) fd = __rpc_raise_fd(fd); madefd = TRUE; servtype = nconf->nc_semantics; if (!__rpc_fd2sockinfo(fd, &si)) goto err; bindresvport(fd, NULL); } else { if (!__rpc_fd2sockinfo(fd, &si)) goto err; servtype = __rpc_socktype2seman(si.si_socktype); if (servtype == -1) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } } if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ goto err1; } switch (servtype) { case NC_TPI_COTS: cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); break; case NC_TPI_COTS_ORD: if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0) || (strcmp(nconf->nc_protofmly, "inet6") == 0))) { setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof (one)); } cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); break; case NC_TPI_CLTS: cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); break; default: goto err; } if (cl == NULL) goto err1; /* borrow errors from clnt_dg/vc creates */ if (nconf) { cl->cl_netid = strdup(nconf->nc_netid); cl->cl_tp = strdup(nconf->nc_device); } else { cl->cl_netid = ""; cl->cl_tp = ""; } if (madefd) { (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ }; return (cl); err: rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; err1: if (madefd) (void)close(fd); return (NULL); }
/* * Connection less client creation returns with client handle parameters. * Default options are set, which the user can change using clnt_control(). * fd should be open and bound. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. Normally they are the same, but they can be * changed to improve the program efficiency and buffer allocation. * If they are 0, use the transport default. * * If svcaddr is NULL, returns NULL. */ CLIENT * clnt_dg_ncreate(int fd, /* open file descriptor */ const struct netbuf *svcaddr, /* servers address */ rpcprog_t program, /* program number */ rpcvers_t version, /* version number */ u_int sendsz, /* buffer recv size */ u_int recvsz /* buffer send size */) { CLIENT *clnt = NULL; /* client handle */ struct cx_data *cx = NULL; /* private data */ struct cu_data *cu = NULL; struct timespec now; struct rpc_msg call_msg; struct __rpc_sockinfo si; uint32_t oflags; int one = 1; if (svcaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } if (!__rpc_fd2sockinfo(fd, &si)) { rpc_createerr.cf_stat = RPC_TLIERROR; rpc_createerr.cf_error.re_errno = 0; return (NULL); } /* * Find the receive and the send size */ sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); if ((sendsz == 0) || (recvsz == 0)) { rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ rpc_createerr.cf_error.re_errno = 0; return (NULL); } clnt = mem_alloc(sizeof(CLIENT)); if (clnt == NULL) goto err1; mutex_init(&clnt->cl_lock, NULL); clnt->cl_flags = CLNT_FLAG_NONE; /* * Should be multiple of 4 for XDR. */ sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cx = alloc_cx_data(CX_DG_DATA, sendsz, recvsz); if (cx == NULL) goto err1; cu = CU_DATA(cx); (void)memcpy(&cu->cu_raddr, svcaddr->buf, (size_t) svcaddr->len); cu->cu_rlen = svcaddr->len; /* Other values can also be set through clnt_control() */ cu->cu_wait.tv_sec = 15; /* heuristically chosen */ cu->cu_wait.tv_usec = 0; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; cu->cu_async = false; cu->cu_connect = false; cu->cu_connected = false; (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now); call_msg.rm_xid = __RPC_GETXID(&now); /* XXX? */ call_msg.rm_call.cb_prog = program; call_msg.rm_call.cb_vers = version; xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ rpc_createerr.cf_error.re_errno = 0; goto err2; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); /* XXX fvdl - do we still want this? */ #if 0 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); #endif #ifdef IP_RECVERR { int on = 1; (void) setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif ioctl(fd, FIONBIO, (char *)(void *)&one); /* * By default, closeit is always false. It is users responsibility * to do a close on it, else the user may use clnt_control * to let clnt_destroy do it for him/her. */ cu->cu_closeit = false; cu->cu_fd = fd; clnt->cl_ops = clnt_dg_ops(); clnt->cl_p1 = cx; clnt->cl_p2 = rpc_dplx_lookup_rec(fd, RPC_DPLX_LKP_FLAG_NONE, &oflags); /* ref+1 */ clnt->cl_tp = NULL; clnt->cl_netid = NULL; return (clnt); err1: __warnx(TIRPC_DEBUG_FLAG_CLNT_DG, mem_err_clnt_dg); rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; err2: if (clnt) { mem_free(clnt, sizeof(CLIENT)); if (cx) free_cx_data(cx); } return (NULL); }
SVCXPRT * svc_dg_ncreatef(const int fd, const u_int sendsz, const u_int recvsz, const uint32_t flags) { SVCXPRT *xprt; struct rpc_dplx_rec *rec; struct svc_dg_xprt *su; struct __rpc_sockinfo si; u_int recvsize; u_int sendsize; u_int xp_flags; int rc; /* atomically find or create shared fd state; ref+1; locked */ xprt = svc_xprt_lookup(fd, svc_dg_xprt_setup); if (!xprt) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: fd %d svc_xprt_lookup failed", __func__, fd); return (NULL); } rec = REC_XPRT(xprt); xp_flags = atomic_postset_uint16_t_bits(&xprt->xp_flags, flags | SVC_XPRT_FLAG_INITIALIZED); if ((xp_flags & SVC_XPRT_FLAG_INITIALIZED)) { rpc_dplx_rui(rec); XPRT_TRACE(xprt, __func__, __func__, __LINE__); return (xprt); } if (!__rpc_fd2sockinfo(fd, &si)) { atomic_clear_uint16_t_bits(&xprt->xp_flags, SVC_XPRT_FLAG_INITIALIZED); rpc_dplx_rui(rec); __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: fd %d could not get transport information", __func__, fd); return (NULL); } /* * Find the receive and the send size */ sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); if ((sendsize == 0) || (recvsize == 0)) { atomic_clear_uint16_t_bits(&xprt->xp_flags, SVC_XPRT_FLAG_INITIALIZED); rpc_dplx_rui(rec); __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: fd %d transport does not support data transfer", __func__, fd); return (NULL); } __rpc_address_setup(&xprt->xp_local); rc = getsockname(fd, xprt->xp_local.nb.buf, &xprt->xp_local.nb.len); if (rc < 0) { atomic_clear_uint16_t_bits(&xprt->xp_flags, SVC_XPRT_FLAG_INITIALIZED); rpc_dplx_rui(rec); __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: fd %d getsockname failed (%d)", __func__, fd, rc); return (NULL); } /* * Should be multiple of 4 for XDR. */ su = DG_DR(rec); su->su_dr.sendsz = ((sendsize + 3) / 4) * 4; su->su_dr.recvsz = ((recvsize + 3) / 4) * 4; su->su_dr.maxrec = ((MAX(sendsize, recvsize) + 3) / 4) * 4; /* duplex streams are not used by the rendezvous transport */ xdrmem_create(su->su_dr.ioq.xdrs, NULL, 0, XDR_ENCODE); svc_dg_rendezvous_ops(xprt); /* Enable reception of IP*_PKTINFO control msgs */ svc_dg_enable_pktinfo(fd, &si); /* Conditional register */ if ((!(__svc_params->flags & SVC_FLAG_NOREG_XPRTS) && !(flags & SVC_CREATE_FLAG_XPRT_NOREG)) || (flags & SVC_CREATE_FLAG_XPRT_DOREG)) svc_rqst_evchan_reg(__svc_params->ev_u.evchan.id, xprt, SVC_RQST_FLAG_LOCKED | SVC_RQST_FLAG_CHAN_AFFINITY); /* release */ rpc_dplx_rui(rec); XPRT_TRACE(xprt, __func__, __func__, __LINE__); #if defined(HAVE_BLKIN) __rpc_set_blkin_endpoint(xprt, "svc_dg"); #endif return (xprt); }
/* * For simplified, easy to use kind of rpc interfaces. * nettype indicates the type of transport on which the service will be * listening. Used for conservation of the system resource. Only one * handle is created for all the services (actually one of each netid) * and same xdrbuf is used for same netid. The size of the arguments * is also limited by the recvsize for that transport, even if it is * a COTS transport. This may be wrong, but for cases like these, they * should not use the simplified interfaces like this. * * prognum - program number * versnum - version number * procnum - procedure number * progname - Server routine * inproc, outproc - in/out XDR procedures * nettype - nettype */ int rpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum, char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc, char *nettype) { struct netconfig *nconf; int done = FALSE; void *handle; if (procnum == NULLPROC) { warnx("%s can't reassign procedure number %u", rpc_reg_msg, NULLPROC); return (-1); } if (nettype == NULL) nettype = "netpath"; /* The default behavior */ if ((handle = __rpc_setconf(nettype)) == NULL) { warnx(rpc_reg_err, rpc_reg_msg, __reg_err1); return (-1); } /* VARIABLES PROTECTED BY proglst_lock: proglst */ mutex_lock(&proglst_lock); while ((nconf = __rpc_getconf(handle)) != NULL) { struct proglst *pl; SVCXPRT *svcxprt; int madenow; u_int recvsz; char *xdrbuf; char *netid; madenow = FALSE; svcxprt = NULL; recvsz = 0; xdrbuf = netid = NULL; for (pl = proglst; pl; pl = pl->p_nxt) { if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { svcxprt = pl->p_transp; xdrbuf = pl->p_xdrbuf; recvsz = pl->p_recvsz; netid = pl->p_netid; break; } } if (svcxprt == NULL) { struct __rpc_sockinfo si; svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); if (svcxprt == NULL) continue; if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) { warnx(rpc_reg_err, rpc_reg_msg, __reg_err2); SVC_DESTROY(svcxprt); continue; } recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0); if (recvsz == 0) { warnx(rpc_reg_err, rpc_reg_msg, __reg_err3); SVC_DESTROY(svcxprt); continue; } if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || ((netid = strdup(nconf->nc_netid)) == NULL)) { warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); free(xdrbuf); free(netid); SVC_DESTROY(svcxprt); break; } madenow = TRUE; } /* * Check if this (program, version, netid) had already been * registered. The check may save a few RPC calls to rpcbind */ for (pl = proglst; pl; pl = pl->p_nxt) if ((pl->p_prognum == prognum) && (pl->p_versnum == versnum) && (strcmp(pl->p_netid, netid) == 0)) break; if (pl == NULL) { /* Not yet */ (void) rpcb_unset(prognum, versnum, nconf); } else { /* so that svc_reg does not call rpcb_set() */ nconf = NULL; } if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { warnx("%s couldn't register prog %u vers %u for %s", rpc_reg_msg, (unsigned)prognum, (unsigned)versnum, netid); if (madenow) { SVC_DESTROY(svcxprt); free(xdrbuf); free(netid); } continue; } pl = malloc(sizeof (struct proglst)); if (pl == NULL) { warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); if (madenow) { SVC_DESTROY(svcxprt); free(xdrbuf); free(netid); } break; } pl->p_progname = progname; pl->p_prognum = prognum; pl->p_versnum = versnum; pl->p_procnum = procnum; pl->p_inproc = inproc; pl->p_outproc = outproc; pl->p_transp = svcxprt; pl->p_xdrbuf = xdrbuf; pl->p_recvsz = recvsz; pl->p_netid = netid; pl->p_nxt = proglst; proglst = pl; done = TRUE; } __rpc_endconf(handle); mutex_unlock(&proglst_lock); if (done == FALSE) { warnx("%s can't find suitable transport for %s", rpc_reg_msg, nettype); return (-1); } return (0); }
SVCXPRT * svc_dg_create(int fd, u_int sendsize, u_int recvsize) { SVCXPRT *xprt; struct svc_dg_data *su = NULL; struct __rpc_sockinfo si; struct sockaddr_storage ss; socklen_t slen; if (!__rpc_fd2sockinfo(fd, &si)) { warnx(svc_dg_str, svc_dg_err1); return (NULL); } /* * Find the receive and the send size */ sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); if ((sendsize == 0) || (recvsize == 0)) { warnx(svc_dg_str, svc_dg_err2); return (NULL); } xprt = mem_alloc(sizeof (SVCXPRT)); if (xprt == NULL) goto freedata; memset(xprt, 0, sizeof (SVCXPRT)); su = mem_alloc(sizeof (*su)); if (su == NULL) goto freedata; su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL) goto freedata; _DIAGASSERT(__type_fit(u_int, su->su_iosz)); xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), (u_int)su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_fd = fd; xprt->xp_p2 = (caddr_t)(void *)su; xprt->xp_verf.oa_base = su->su_verfbody; svc_dg_ops(xprt); xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); slen = sizeof ss; if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) goto freedata; xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage); xprt->xp_ltaddr.len = slen; memcpy(xprt->xp_ltaddr.buf, &ss, slen); xprt_register(xprt); return (xprt); freedata: (void) warnx(svc_dg_str, __no_mem_str); if (xprt) { if (su) (void) mem_free(su, sizeof (*su)); (void) mem_free(xprt, sizeof (SVCXPRT)); } return (NULL); }
/** * _9p_create_socket: create the accept socket for 9P * * This function create the accept socket for the 9p dispatcher thread. * * @return socket fd or -1 if failed. * */ int _9p_create_socket(void) { int sock = -1; int one = 1; int centvingt = 120; int neuf = 9; struct sockaddr_in6 sinaddr_tcp6; struct netbuf netbuf_tcp6; struct t_bind bindaddr_tcp6; struct __rpc_sockinfo si_tcp6; sock = socket(P_FAMILY, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) goto bad_socket; if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, ¢vingt, sizeof(centvingt)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, ¢vingt, sizeof(centvingt)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &neuf, sizeof(neuf)) == -1)) goto bad_socket; socket_setoptions(sock); memset(&sinaddr_tcp6, 0, sizeof(sinaddr_tcp6)); sinaddr_tcp6.sin6_family = AF_INET6; /* All the interfaces on the machine are used */ sinaddr_tcp6.sin6_addr = in6addr_any; sinaddr_tcp6.sin6_port = htons(_9p_param._9p_tcp_port); netbuf_tcp6.maxlen = sizeof(sinaddr_tcp6); netbuf_tcp6.len = sizeof(sinaddr_tcp6); netbuf_tcp6.buf = &sinaddr_tcp6; bindaddr_tcp6.qlen = SOMAXCONN; bindaddr_tcp6.addr = netbuf_tcp6; if (!__rpc_fd2sockinfo(sock, &si_tcp6)) { LogFatal(COMPONENT_DISPATCH, "Cannot get 9p socket info for tcp6 socket errno=%d (%s)", errno, strerror(errno)); return -1; } if (bind(sock, (struct sockaddr *)bindaddr_tcp6.addr.buf, (socklen_t) si_tcp6.si_alen) == -1) { LogFatal(COMPONENT_DISPATCH, "Cannot bind 9p tcp6 socket, error %d (%s)", errno, strerror(errno)); return -1; } if (listen(sock, 20) == -1) { LogFatal(COMPONENT_DISPATCH, "Cannot bind 9p tcp6 socket, error %d (%s)", errno, strerror(errno)); return -1; } return sock; bad_socket: LogFatal(COMPONENT_9P_DISPATCH, "Bad socket option 9p, error %d (%s)", errno, strerror(errno)); return -1; } /* _9p_create_socket */
/* * Adds the entry into the rpcbind database. * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also * Returns 0 if succeeds, else fails */ static int init_transport(struct netconfig *nconf) { int fd = -1; struct t_bind taddr; struct addrinfo hints, *res; struct __rpc_sockinfo si; SVCXPRT *my_xprt = NULL; int status; /* bound checking ? */ int aicode; int addrlen = 0; int nhostsbak; int checkbind; struct sockaddr *sa = NULL; u_int32_t host_addr[4]; /* IPv4 or IPv6 */ struct sockaddr_un sun; mode_t oldmask; res = NULL; if ((nconf->nc_semantics != NC_TPI_CLTS) && (nconf->nc_semantics != NC_TPI_COTS) && (nconf->nc_semantics != NC_TPI_COTS_ORD)) return (1); /* not my type */ #ifdef RPCBIND_DEBUG if (debugging) { int i; char **s; (void) fprintf(stderr, "%s: %ld lookup routines :\n", nconf->nc_netid, nconf->nc_nlookups); for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; i++, s++) fprintf(stderr, "[%d] - %s\n", i, *s); } #endif /* * XXX - using RPC library internal functions. For NC_TPI_CLTS * we call this later, for each socket we like to bind. */ if (nconf->nc_semantics != NC_TPI_CLTS) { if ((fd = __rpc_nconf2fd(nconf)) < 0) { syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); return (1); } } if (!__rpc_nconf2sockinfo(nconf, &si)) { syslog(LOG_ERR, "cannot get information for %s", nconf->nc_netid); return (1); } if ((strcmp(nconf->nc_netid, "local") == 0) || (strcmp(nconf->nc_netid, "unix") == 0)) { memset(&sun, 0, sizeof sun); sun.sun_family = AF_LOCAL; unlink(_PATH_RPCBINDSOCK); strcpy(sun.sun_path, _PATH_RPCBINDSOCK); addrlen = SUN_LEN(&sun); sa = (struct sockaddr *)&sun; } else { /* Get rpcbind's address on this transport */ memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; } if (nconf->nc_semantics == NC_TPI_CLTS) { /* * If no hosts were specified, just bind to INADDR_ANY. Otherwise * make sure 127.0.0.1 is added to the list. */ nhostsbak = nhosts; nhostsbak++; hosts = realloc(hosts, nhostsbak * sizeof(char *)); if (nhostsbak == 1) hosts[0] = "*"; else { if (hints.ai_family == AF_INET) { hosts[nhostsbak - 1] = "127.0.0.1"; } else if (hints.ai_family == AF_INET6) { hosts[nhostsbak - 1] = "::1"; } else return 1; } /* * Bind to specific IPs if asked to */ checkbind = 0; while (nhostsbak > 0) { --nhostsbak; /* * XXX - using RPC library internal functions. */ if ((fd = __rpc_nconf2fd(nconf)) < 0) { syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); return (1); } switch (hints.ai_family) { case AF_INET: if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { hints.ai_flags &= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET6 adress. */ if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) continue; } break; case AF_INET6: if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { hints.ai_flags &= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET adress. */ if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) continue; } break; default: break; } /* * If no hosts were specified, just bind to INADDR_ANY */ if (strcmp("*", hosts[nhostsbak]) == 0) hosts[nhostsbak] = NULL; if ((aicode = getaddrinfo(hosts[nhostsbak], servname, &hints, &res)) != 0) { if ((aicode = getaddrinfo(hosts[nhostsbak], "portmapper", &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); continue; } } addrlen = res->ai_addrlen; sa = (struct sockaddr *)res->ai_addr; oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); if (bind(fd, sa, addrlen) != 0) { syslog(LOG_ERR, "cannot bind %s on %s: %m", (hosts[nhostsbak] == NULL) ? "*" : hosts[nhostsbak], nconf->nc_netid); if (res != NULL) freeaddrinfo(res); continue; } else checkbind++; (void) umask(oldmask); /* Copy the address */ taddr.addr.maxlen = taddr.addr.len = addrlen; taddr.addr.buf = malloc(addrlen); if (taddr.addr.buf == NULL) { syslog(LOG_ERR, "cannot allocate memory for %s address", nconf->nc_netid); if (res != NULL) freeaddrinfo(res); return 1; } memcpy(taddr.addr.buf, sa, addrlen); #ifdef RPCBIND_DEBUG if (debugging) { /* * for debugging print out our universal * address */ char *uaddr; struct netbuf nb; int sa_size = 0; nb.buf = sa; switch( sa->sa_family){ case AF_INET: sa_size = sizeof (struct sockaddr_in); break; case AF_INET6: sa_size = sizeof (struct sockaddr_in6); break; } nb.len = nb.maxlen = sa_size; uaddr = taddr2uaddr(nconf, &nb); (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); (void) free(uaddr); } #endif my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (my_xprt == (SVCXPRT *)NULL) { syslog(LOG_ERR, "%s: could not create service", nconf->nc_netid); goto error; } } if (!checkbind) return 1; } else { /* NC_TPI_COTS */ if ((strcmp(nconf->nc_netid, "local") != 0) && (strcmp(nconf->nc_netid, "unix") != 0)) { if ((aicode = getaddrinfo(NULL, servname, &hints, &res))!= 0) { if ((aicode = getaddrinfo(NULL, "portmapper", &hints, &res))!= 0) { printf("cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); return 1; } } addrlen = res->ai_addrlen; sa = (struct sockaddr *)res->ai_addr; } oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); __rpc_fd2sockinfo(fd, &si); if (bind(fd, sa, addrlen) < 0) { syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); if (res != NULL) freeaddrinfo(res); return 1; } (void) umask(oldmask); /* Copy the address */ taddr.addr.len = taddr.addr.maxlen = addrlen; taddr.addr.buf = malloc(addrlen); if (taddr.addr.buf == NULL) { syslog(LOG_ERR, "cannot allocate memory for %s address", nconf->nc_netid); if (res != NULL) freeaddrinfo(res); return 1; } memcpy(taddr.addr.buf, sa, addrlen); #ifdef RPCBIND_DEBUG if (debugging) { /* for debugging print out our universal address */ char *uaddr; struct netbuf nb; int sa_size2 = 0; nb.buf = sa; switch( sa->sa_family){ case AF_INET: sa_size2 = sizeof (struct sockaddr_in); break; case AF_INET6: sa_size2 = sizeof (struct sockaddr_in6); break; } nb.len = nb.maxlen = sa_size2; uaddr = taddr2uaddr(nconf, &nb); (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); (void) free(uaddr); } #endif listen(fd, SOMAXCONN); my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (my_xprt == (SVCXPRT *)NULL) { syslog(LOG_ERR, "%s: could not create service", nconf->nc_netid); goto error; } } #ifdef PORTMAP /* * Register both the versions for tcp/ip, udp/ip. */ if (si.si_af == AF_INET && (si.si_proto == IPPROTO_TCP || si.si_proto == IPPROTO_UDP)) { struct pmaplist *pml; pml = malloc(sizeof (struct pmaplist)); if (pml == NULL) { syslog(LOG_ERR, "no memory!"); exit(1); } pml->pml_map.pm_prog = PMAPPROG; pml->pml_map.pm_vers = PMAPVERS; pml->pml_map.pm_port = PMAPPORT; pml->pml_map.pm_prot = si.si_proto; switch (si.si_proto) { case IPPROTO_TCP: tcptrans = strdup(nconf->nc_netid); break; case IPPROTO_UDP: udptrans = strdup(nconf->nc_netid); break; } pml->pml_next = list_pml; list_pml = pml; /* Add version 3 information */ pml = malloc(sizeof (struct pmaplist)); if (pml == NULL) { syslog(LOG_ERR, "no memory!"); exit(1); } pml->pml_map = list_pml->pml_map; pml->pml_map.pm_vers = RPCBVERS; pml->pml_next = list_pml; list_pml = pml; /* Add version 4 information */ pml = malloc (sizeof (struct pmaplist)); if (pml == NULL) { syslog(LOG_ERR, "no memory!"); exit(1); } pml->pml_map = list_pml->pml_map; pml->pml_map.pm_vers = RPCBVERS4; pml->pml_next = list_pml; list_pml = pml; /* Also add version 2 stuff to rpcbind list */ rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); } /* We need to support portmap over IPv4. It makes sense to * support it over AF_LOCAL as well, because that allows * rpcbind to identify the owner of a socket much better * than by relying on privileged ports to tell root from * non-root users. */ if (si.si_af == AF_INET || si.si_af == AF_LOCAL) { if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, pmap_service, 0)) { syslog(LOG_ERR, "could not register on %s", nconf->nc_netid); goto error; } } #endif /* version 3 registration */ if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { syslog(LOG_ERR, "could not register %s version 3", nconf->nc_netid); goto error; } rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); /* version 4 registration */ if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { syslog(LOG_ERR, "could not register %s version 4", nconf->nc_netid); goto error; } rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); /* decide if bound checking works for this transport */ status = add_bndlist(nconf, &taddr.addr); #ifdef RPCBIND_DEBUG if (debugging) { if (status < 0) { fprintf(stderr, "Error in finding bind status for %s\n", nconf->nc_netid); } else if (status == 0) { fprintf(stderr, "check binding for %s\n", nconf->nc_netid); } else if (status > 0) { fprintf(stderr, "No check binding for %s\n", nconf->nc_netid); } } #endif /* * rmtcall only supported on CLTS transports for now. */ if (nconf->nc_semantics == NC_TPI_CLTS) { status = create_rmtcall_fd(nconf); #ifdef RPCBIND_DEBUG if (debugging) { if (status < 0) { fprintf(stderr, "Could not create rmtcall fd for %s\n", nconf->nc_netid); } else { fprintf(stderr, "rmtcall fd for %s is %d\n", nconf->nc_netid, status); } } #endif } return (0); error: close(fd); return (1); }
/** * _9p_create_socket_V4 : create the socket and bind for 9P using * the available V4 interfaces on the host. This is not the default * for ganesha. We expect _9p_create_socket_V6 to be called first * and succeed. Only when the V6 function returns failure is this * function expected to be called. See _9p_create_socket(). * * @return socket fd or -1 in case of failure * */ static int _9p_create_socket_V4(void) { int sock = -1; int one = 1; int centvingt = 120; int neuf = 9; struct netbuf netbuf_tcp; struct t_bind bindaddr_tcp; struct __rpc_sockinfo si_tcp; struct sockaddr_in sinaddr_tcp; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { LogWarn(COMPONENT_9P_DISPATCH, "Error creating 9p V4 socket, error %d(%s)", errno, strerror(errno)); return -1; } if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, ¢vingt, sizeof(centvingt)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, ¢vingt, sizeof(centvingt)) == -1) || (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &neuf, sizeof(neuf)) == -1)) { LogWarn(COMPONENT_9P_DISPATCH, "Error setting 9p V4 socket option, error %d(%s)", errno, strerror(errno)); goto err; } socket_setoptions(sock); memset(&sinaddr_tcp, 0, sizeof(sinaddr_tcp)); sinaddr_tcp.sin_family = AF_INET; /* All the interfaces on the machine are used */ sinaddr_tcp.sin_addr.s_addr = htonl(INADDR_ANY); sinaddr_tcp.sin_port = htons(_9p_param._9p_tcp_port); netbuf_tcp.maxlen = sizeof(sinaddr_tcp); netbuf_tcp.len = sizeof(sinaddr_tcp); netbuf_tcp.buf = &sinaddr_tcp; bindaddr_tcp.qlen = SOMAXCONN; bindaddr_tcp.addr = netbuf_tcp; if (!__rpc_fd2sockinfo(sock, &si_tcp)) { LogWarn(COMPONENT_9P_DISPATCH, "Cannot get 9p socket info for tcp V4 socket error %d(%s)", errno, strerror(errno)); goto err; } if (bind(sock, (struct sockaddr *)bindaddr_tcp.addr.buf, (socklen_t) si_tcp.si_alen) == -1) { LogWarn(COMPONENT_9P_DISPATCH, "Cannot bind 9p tcp V4 socket, error %d(%s)", errno, strerror(errno)); goto err; } if (listen(sock, 20) == -1) { LogWarn(COMPONENT_9P_DISPATCH, "Cannot bind 9p tcp V4 socket, error %d(%s)", errno, strerror(errno)); goto err; } return sock; err: close(sock); return -1; }
/*ARGSUSED*/ static bool_t rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg) { int sock, flags; struct cf_rendezvous *r; struct cf_conn *cd; struct sockaddr_storage addr; socklen_t len; struct __rpc_sockinfo si; SVCXPRT *newxprt; fd_set cleanfds; assert(xprt != NULL); assert(msg != NULL); r = (struct cf_rendezvous *)xprt->xp_p1; again: len = sizeof addr; if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, &len)) < 0) { if (errno == EINTR) goto again; /* * Clean out the most idle file descriptor when we're * running out. */ if (errno == EMFILE || errno == ENFILE) { cleanfds = svc_fdset; __svc_clean_idle(&cleanfds, 0, FALSE); goto again; } return (FALSE); } /* * make a new transporter (re-uses xprt) */ newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); newxprt->xp_rtaddr.buf = mem_alloc(len); if (newxprt->xp_rtaddr.buf == NULL) return (FALSE); memcpy(newxprt->xp_rtaddr.buf, &addr, len); newxprt->xp_rtaddr.len = len; #ifdef PORTMAP if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; newxprt->xp_addrlen = sizeof (struct sockaddr_in); } #endif /* PORTMAP */ if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { len = 1; /* XXX fvdl - is this useful? */ _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); } cd = (struct cf_conn *)newxprt->xp_p1; cd->recvsize = r->recvsize; cd->sendsize = r->sendsize; cd->maxrec = r->maxrec; if (cd->maxrec != 0) { flags = _fcntl(sock, F_GETFL, 0); if (flags == -1) return (FALSE); if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) return (FALSE); if (cd->recvsize > cd->maxrec) cd->recvsize = cd->maxrec; cd->nonblock = TRUE; __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); } else cd->nonblock = FALSE; gettimeofday(&cd->last_recv_time, NULL); return (FALSE); /* there is never an rpc msg to be processed */ }