int rresvport(int *alport ) { struct sockaddr_in sin; int s; bzero(&sin, sizeof sin); sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return (-1); #if 0 /* compat_exact_traditional_rresvport_semantics */ sin.sin_port = htons((u_short)*alport); if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) return (s); if (errno != EADDRINUSE) { (void)close(s); return (-1); } #endif sin.sin_port = 0; if (bindresvport(s, &sin) == -1) { (void)close(s); return (-1); } *alport = (int)ntohs(sin.sin_port); return (s); }
/* * Usage: * xprt = svctcp_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. * * If sock<0 then a socket is created, else sock is used. * If the socket, sock is not bound to a port then svctcp_create * binds it to an arbitrary port. The routine then starts a tcp * listener on the socket's associated port. In any (successful) case, * xprt->xp_sock is the registered socket number and xprt->xp_port is the * associated port number. * * Since tcp 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 * svctcp_create (int sock, u_int sendsize, u_int recvsize) { bool_t madesock = FALSE; SVCXPRT *xprt; struct tcp_rendezvous *r; struct sockaddr_in addr; socklen_t len = sizeof (struct sockaddr_in); if (sock == RPC_ANYSOCK) { if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror (_("svc_tcp.c - tcp socket creation problem")); return (SVCXPRT *) NULL; } madesock = TRUE; } bzero ((char *) &addr, sizeof (addr)); addr.sin_family = AF_INET; if (bindresvport (sock, &addr)) { addr.sin_port = 0; (void) bind (sock, (struct sockaddr *) &addr, len); } if ((getsockname (sock, (struct sockaddr *) &addr, &len) != 0) || (listen (sock, 2) != 0)) { perror (_("svc_tcp.c - cannot getsockname or listen")); if (madesock) (void) close (sock); return (SVCXPRT *) NULL; } r = (struct tcp_rendezvous *) mem_alloc (sizeof (*r)); xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT)); if (r == NULL || xprt == NULL) { #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) __fwprintf (stderr, L"%s", _("svctcp_create: out of memory\n")); else #endif (void) fputs (_("svctcp_create: out of memory\n"), stderr); mem_free (r, sizeof (*r)); mem_free (xprt, sizeof (SVCXPRT)); return NULL; } r->sendsize = sendsize; r->recvsize = recvsize; xprt->xp_p2 = NULL; xprt->xp_p1 = (caddr_t) r; xprt->xp_verf = _null_auth; xprt->xp_ops = &svctcp_rendezvous_op; xprt->xp_port = ntohs (addr.sin_port); xprt->xp_sock = sock; xprt_register (xprt); return xprt; }
/* * A common server create routine */ static SVCXPRT * svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid) { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; struct sockaddr_in sccsin; _DIAGASSERT(netid != NULL); if ((nconf = __rpc_getconfip(netid)) == NULL) { (void) syslog(LOG_ERR, "Could not get %s transport", netid); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) { (void) freenetconfigent(nconf); (void) syslog(LOG_ERR, "svc%s_create: could not open connection", netid); return (NULL); } madefd = TRUE; } memset(&sccsin, 0, sizeof sccsin); sccsin.sin_family = AF_INET; (void)bindresvport(fd, &sccsin); switch (nconf->nc_semantics) { case NC_TPI_COTS: case NC_TPI_COTS_ORD: if (listen(fd, SOMAXCONN) == -1) { (void) syslog(LOG_ERR, "svc%s_create: listen(2) failed: %s", netid, strerror(errno)); (void) freenetconfigent(nconf); goto out; } break; default: break; } svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); (void) freenetconfigent(nconf); if (svc == NULL) goto out; port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); svc->xp_port = ntohs(port); return svc; out: if (madefd) (void) close(fd); return NULL; }
/* * Usage: * xprt = svcudp_create(sock); * * If sock<0 then a socket is created, else sock is used. * If the socket, sock is not bound to a port then svcudp_create * binds it to an arbitrary port. In any (successful) case, * xprt->xp_sock is the registered socket number and xprt->xp_port is the * associated port number. * Once *xprt is initialized, it is registered as a transporter; * see (svc.h, xprt_register). * The routines returns NULL if a problem occurred. */ SVCXPRT * svcudp_bufcreate( register int sock, unsigned sendsz, unsigned recvsz) { bool_t madesock = FALSE; register SVCXPRT *xprt; register struct svcudp_data *su; struct sockaddr_in addr; socklen_t len = sizeof(struct sockaddr_in); if (sock == RPC_ANYSOCK) { if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("svcudp_create: socket creation problem"); return ((SVCXPRT *)NULL); } madesock = TRUE; } bzero((char *)&addr, sizeof (addr)); addr.sin_family = AF_INET; if (bindresvport(sock, &addr)) { addr.sin_port = 0; (void)bind(sock, (struct sockaddr *)&addr, len); } if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { perror("svcudp_create - cannot getsockname"); if (madesock) (void)close(sock); return ((SVCXPRT *)NULL); } xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); if (xprt == NULL) { (void)fprintf(stderr, "svcudp_create: out of memory\n"); return (NULL); } su = (struct svcudp_data *)mem_alloc(sizeof(*su)); if (su == NULL) { (void)fprintf(stderr, "svcudp_create: out of memory\n"); return (NULL); } su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) { (void)fprintf(stderr, "svcudp_create: out of memory\n"); return (NULL); } xdrmem_create( &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_p2 = (char*)su; xprt->xp_verf.oa_base = su->su_verfbody; xprt->xp_ops = &svcudp_op; xprt->xp_port = ntohs(addr.sin_port); xprt->xp_sock = sock; xprt_register(xprt); return (xprt); }
struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags) { struct client *clnt = malloc(sizeof(*clnt)); struct sockaddr_in addr; int sock; if (clnt == NULL) { perror("malloc"); goto bail; } memset(clnt, 0, sizeof(*clnt)); if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("socket"); goto bail; } if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) { perror("bindresvport"); goto bail; } else { struct sockaddr_in me; me.sin_family = AF_INET; me.sin_port = 0; me.sin_addr.s_addr = INADDR_ANY; if (0 && bind(sock, (struct sockaddr *)&me, sizeof(me)) == -1) { perror("bind"); goto bail; } } clnt->sock = sock; clnt->call_stub = rpc_call_udp; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = server; if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { perror("connect"); goto bail; } goto done; bail: if (clnt) { free(clnt); clnt = NULL; } done: return clnt; }
/* * Usage: * xprt = svctcp_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. * * If sock<0 then a socket is created, else sock is used. * If the socket, sock is not bound to a port then svctcp_create * binds it to an arbitrary port. The routine then starts a tcp * listener on the socket's associated port. In any (successful) case, * xprt->xp_sock is the registered socket number and xprt->xp_port is the * associated port number. * * Since tcp 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 * svctcp_create( register int sock, unsigned sendsize, unsigned recvsize) { bool_t madesock = FALSE; register SVCXPRT *xprt; register struct tcp_rendezvous *r; struct sockaddr_in addr; socklen_t len = (socklen_t)sizeof(struct sockaddr_in); if (sock == RPC_ANYSOCK) { if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("svctcp_.c - udp socket creation problem"); return ((SVCXPRT *)NULL); } madesock = TRUE; } bzero((char *)&addr, sizeof (addr)); addr.sin_family = AF_INET; if (bindresvport(sock, &addr)) { addr.sin_port = 0; (void)bind(sock, (struct sockaddr *)&addr, len); } if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || (listen(sock, 2) != 0)) { perror("svctcp_.c - cannot getsockname or listen"); if (madesock) (void)close(sock); return ((SVCXPRT *)NULL); } r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); if (r == NULL) { (void) fprintf(stderr, "svctcp_create: out of memory\n"); return (NULL); } r->sendsize = sendsize; r->recvsize = recvsize; xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); if (xprt == NULL) { (void) fprintf(stderr, "svctcp_create: out of memory\n"); return (NULL); } xprt->xp_p2 = NULL; xprt->xp_p1 = (char*)r; xprt->xp_verf = _null_auth; xprt->xp_ops = &svctcp_rendezvous_op; xprt->xp_port = ntohs(addr.sin_port); xprt->xp_sock = sock; xprt_register(xprt); return (xprt); }
SVCXPRT *Svctcp_create(register int sock, u_int sendsize, u_int recvsize) { bool_t madesock = FALSE; register SVCXPRT *xprt; register struct tcp_rendezvous *r; struct sockaddr_in addr; unsigned long len = sizeof(struct sockaddr_in); if(sock == RPC_ANYSOCK) { if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("svctcp_.c - udp socket creation problem"); return ((SVCXPRT *) NULL); } madesock = TRUE; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if(bindresvport(sock, &addr)) { addr.sin_port = 0; (void)bind(sock, (struct sockaddr *)&addr, len); } if((getsockname(sock, (struct sockaddr *)&addr, (socklen_t *) & len) != 0) || (listen(sock, SOMAXCONN) != 0)) { perror("svctcp_.c - cannot getsockname or listen"); if(madesock) (void)close(sock); return ((SVCXPRT *) NULL); } r = (struct tcp_rendezvous *)Mem_Alloc(sizeof(*r)); if(r == NULL) { return (NULL); } r->sendsize = sendsize; r->recvsize = recvsize; xprt = (SVCXPRT *) Mem_Alloc(sizeof(SVCXPRT)); if(xprt == NULL) { return (NULL); } xprt->xp_p2 = NULL; xprt->xp_p1 = (caddr_t) r; xprt->xp_verf = _null_auth; xprt->xp_ops = &Svctcp_rendezvous_op; xprt->xp_port = ntohs(addr.sin_port); xprt->XP_SOCK = sock; Xprt_register(xprt); return (xprt); }
/* * A common server create routine */ static SVCXPRT * svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid) { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; struct sockaddr_in sin; if ((nconf = __rpc_getconfip(netid)) == NULL) { (void) syslog(LOG_ERR, "Could not get %s transport", netid); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) { (void) freenetconfigent(nconf); (void) syslog(LOG_ERR, "svc%s_create: could not open connection", netid); return (NULL); } madefd = TRUE; } memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; bindresvport(fd, &sin); _listen(fd, SOMAXCONN); svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); (void) freenetconfigent(nconf); if (svc == NULL) { if (madefd) (void)_close(fd); return (NULL); } port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); svc->xp_port = ntohs(port); return (svc); }
/* * Initialize socket used to notify lockd of peer reboots. * * Returns the file descriptor of the new socket if successful; * otherwise returns -1 and logs an error. * * Lockd rejects such requests if the source port is not privileged. * statd_get_socket() must be invoked while statd still holds root * privileges in order for the socket to acquire a privileged source * port. */ int statd_get_socket(void) { struct sockaddr_in sin; struct servent *se; int loopcnt = 100; if (sockfd >= 0) return sockfd; while (loopcnt-- > 0) { if (sockfd >= 0) close(sockfd); if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { xlog(L_ERROR, "%s: Can't create socket: %m", __func__); return -1; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bindresvport(sockfd, &sin) < 0) { xlog(D_GENERAL, "%s: can't bind to reserved port", __func__); break; } se = getservbyport(sin.sin_port, "udp"); if (se == NULL) break; /* rather not use that port, try again */ } FD_SET(sockfd, &SVC_FDSET); return sockfd; }
static struct conn_t *conn_new(struct sockaddr_in *raddr, struct sockaddr_in *laddr) { struct conn_t *c; int lsize, errnosave; struct sockaddr_in tmp; c = smalloc(sizeof(*c)); memset(c, 0, sizeof(*c)); c->state = CONN_NEW; INIT_LIST_HEAD(&c->reqs); if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { errnosave = errno; syslog(LOG_ERR, "socket: %s", strerror(errno)); free(c); errno = errnosave; return 0; } /* If this is not the first connection, do a non-blocking connect */ if (!list_empty(&clist)) set_non_block(c->fd); tmp = *laddr; /* use a temp here because * bindresvport writes it. */ if (laddr->sin_port || bindresvport(c->fd, &tmp) == -1) { syslog(LOG_ERR, "bindresvport: %s (ignoring)", strerror(errno)); /* If we specified a port or failed to bind to a reserved * port for some reason, try a normal bind. */ if (bind(c->fd, (struct sockaddr *) laddr, sizeof(*laddr)) == -1) { errnosave = errno; syslog(LOG_ERR, "bind(%s:%d): %s (ignoring)", inet_ntoa(laddr->sin_addr), ntohs(laddr->sin_port), strerror(errno)); close(c->fd); free(c); errno = errnosave; return 0; } } if (verbose) syslog(LOG_INFO, "Connecting to %s:%d...", inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port)); if (connect(c->fd, (struct sockaddr *) raddr, sizeof(*raddr)) == -1) { if (errno != EINPROGRESS) { errnosave = errno; syslog(LOG_ERR, "connect(%s:%d): %s", inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port), strerror(errno)); close(c->fd); free(c); errno = errnosave; return 0; } } /* Make note of our local address */ lsize = sizeof(c->laddr); getsockname(c->fd, (struct sockaddr *)&c->laddr, &lsize); c->raddr = *raddr; /* Prime output buffer with version information and cookie */ conn_send_version(c); set_keep_alive(c->fd); set_no_delay(c->fd); set_non_block(c->fd); /* Append to list of connections */ list_add_tail(&c->list, &clist); return c; }
// NB: mp->xxx fields may be trashed on exit static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts) { CLIENT *mclient; char *hostname; char *pathname; char *mounthost; struct nfs_mount_data data; char *opt; struct hostent *hp; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; int msock, fsock; union { struct fhstatus nfsv2; struct mountres3 nfsv3; } status; int daemonized; char *s; int port; int mountport; int proto; int bg; int soft; int intr; int posix; int nocto; int noac; int nolock; int retry; int tcp; int mountprog; int mountvers; int nfsprog; int nfsvers; int retval; find_kernel_nfs_mount_version(); daemonized = 0; mounthost = NULL; retval = ETIMEDOUT; msock = fsock = -1; mclient = NULL; /* NB: hostname, mounthost, filteropts must be free()d prior to return */ filteropts = xstrdup(filteropts); /* going to trash it later... */ hostname = xstrdup(mp->mnt_fsname); /* mount_main() guarantees that ':' is there */ s = strchr(hostname, ':'); pathname = s + 1; *s = '\0'; /* Ignore all but first hostname in replicated mounts until they can be fully supported. ([email protected]) */ s = strchr(hostname, ','); if (s) { *s = '\0'; bb_error_msg("warning: multiple hostnames not supported"); } server_addr.sin_family = AF_INET; if (!inet_aton(hostname, &server_addr.sin_addr)) { hp = gethostbyname(hostname); if (hp == NULL) { bb_herror_msg("%s", hostname); goto fail; } if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length"); hp->h_length = sizeof(struct in_addr); } memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); } memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr)); /* add IP address to mtab options for use when unmounting */ if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */ mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr)); } else { char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts, mp->mnt_opts[0] ? "," : "", inet_ntoa(server_addr.sin_addr)); free(mp->mnt_opts); mp->mnt_opts = tmp; } /* Set default options. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to * let the kernel decide. * timeo is filled in after we know whether it'll be TCP or UDP. */ memset(&data, 0, sizeof(data)); data.retrans = 3; data.acregmin = 3; data.acregmax = 60; data.acdirmin = 30; data.acdirmax = 60; data.namlen = NAME_MAX; bg = 0; soft = 0; intr = 0; posix = 0; nocto = 0; nolock = 0; noac = 0; retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 0; mountprog = MOUNTPROG; mountvers = 0; port = 0; mountport = 0; nfsprog = 100003; nfsvers = 0; /* parse options */ if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { char *opteq = strchr(opt, '='); if (opteq) { static const char *const options[] = { /* 0 */ "rsize", /* 1 */ "wsize", /* 2 */ "timeo", /* 3 */ "retrans", /* 4 */ "acregmin", /* 5 */ "acregmax", /* 6 */ "acdirmin", /* 7 */ "acdirmax", /* 8 */ "actimeo", /* 9 */ "retry", /* 10 */ "port", /* 11 */ "mountport", /* 12 */ "mounthost", /* 13 */ "mountprog", /* 14 */ "mountvers", /* 15 */ "nfsprog", /* 16 */ "nfsvers", /* 17 */ "vers", /* 18 */ "proto", /* 19 */ "namlen", /* 20 */ "addr", NULL }; int val = xatoi_u(opteq + 1); *opteq = '\0'; switch (index_in_str_array(options, opt)) { case 0: // "rsize" data.rsize = val; break; case 1: // "wsize" data.wsize = val; break; case 2: // "timeo" data.timeo = val; break; case 3: // "retrans" data.retrans = val; break; case 4: // "acregmin" data.acregmin = val; break; case 5: // "acregmax" data.acregmax = val; break; case 6: // "acdirmin" data.acdirmin = val; break; case 7: // "acdirmax" data.acdirmax = val; break; case 8: // "actimeo" data.acregmin = val; data.acregmax = val; data.acdirmin = val; data.acdirmax = val; break; case 9: // "retry" retry = val; break; case 10: // "port" port = val; break; case 11: // "mountport" mountport = val; break; case 12: // "mounthost" mounthost = xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,")); break; case 13: // "mountprog" mountprog = val; break; case 14: // "mountvers" mountvers = val; break; case 15: // "nfsprog" nfsprog = val; break; case 16: // "nfsvers" case 17: // "vers" nfsvers = val; break; case 18: // "proto" if (!strncmp(opteq+1, "tcp", 3)) tcp = 1; else if (!strncmp(opteq+1, "udp", 3)) tcp = 0; else bb_error_msg("warning: unrecognized proto= option"); break; case 19: // "namlen" if (nfs_mount_version >= 2) data.namlen = val; else bb_error_msg("warning: option namlen is not supported\n"); break; case 20: // "addr" - ignore break; default: bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val); goto fail; } } else { static const char *const options[] = { "bg", "fg", "soft", "hard", "intr", "posix", "cto", "ac", "tcp", "udp", "lock", NULL }; int val = 1; if (!strncmp(opt, "no", 2)) { val = 0; opt += 2; } switch (index_in_str_array(options, opt)) { case 0: // "bg" bg = val; break; case 1: // "fg" bg = !val; break; case 2: // "soft" soft = val; break; case 3: // "hard" soft = !val; break; case 4: // "intr" intr = val; break; case 5: // "posix" posix = val; break; case 6: // "cto" nocto = !val; break; case 7: // "ac" noac = !val; break; case 8: // "tcp" tcp = val; break; case 9: // "udp" tcp = !val; break; case 10: // "lock" if (nfs_mount_version >= 3) nolock = !val; else bb_error_msg("warning: option nolock is not supported"); break; default: bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); goto fail; } } } proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; data.flags = (soft ? NFS_MOUNT_SOFT : 0) | (intr ? NFS_MOUNT_INTR : 0) | (posix ? NFS_MOUNT_POSIX : 0) | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0); if (nfs_mount_version >= 2) data.flags |= (tcp ? NFS_MOUNT_TCP : 0); if (nfs_mount_version >= 3) data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) { bb_error_msg("NFSv%d not supported", nfsvers); goto fail; } if (nfsvers && !mountvers) mountvers = (nfsvers < 3) ? 1 : nfsvers; if (nfsvers && nfsvers < mountvers) { mountvers = nfsvers; } /* Adjust options if none specified */ if (!data.timeo) data.timeo = tcp ? 70 : 7; data.version = nfs_mount_version; if (vfsflags & MS_REMOUNT) goto do_mount; /* * If the previous mount operation on the same host was * backgrounded, and the "bg" for this mount is also set, * give up immediately, to avoid the initial timeout. */ if (bg && we_saw_this_host_before(hostname)) { daemonized = daemonize(); /* parent or error */ if (daemonized <= 0) { /* parent or error */ retval = -daemonized; goto ret; } } /* create mount daemon client */ /* See if the nfs host = mount host. */ if (mounthost) { if (mounthost[0] >= '0' && mounthost[0] <= '9') { mount_server_addr.sin_family = AF_INET; mount_server_addr.sin_addr.s_addr = inet_addr(hostname); } else { hp = gethostbyname(mounthost); if (hp == NULL) { bb_herror_msg("%s", mounthost); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length?"); hp->h_length = sizeof(struct in_addr); } mount_server_addr.sin_family = AF_INET; memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length); } } } /* * The following loop implements the mount retries. When the mount * times out, and the "bg" option is set, we background ourself * and continue trying. * * The case where the mount point is not present and the "bg" * option is set, is treated as a timeout. This is done to * support nested mounts. * * The "retry" count specified by the user is the number of * minutes to retry before giving up. */ { struct timeval total_timeout; struct timeval retry_timeout; struct pmap* pm_mnt; time_t t; time_t prevt; time_t timeout; retry_timeout.tv_sec = 3; retry_timeout.tv_usec = 0; total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; timeout = time(NULL) + 60 * retry; prevt = 0; t = 30; retry: /* be careful not to use too many CPU cycles */ if (t - prevt < 30) sleep(30); pm_mnt = get_mountport(&mount_server_addr, mountprog, mountvers, proto, mountport); nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; /* contact the mount daemon via TCP */ mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; switch (pm_mnt->pm_prot) { case IPPROTO_UDP: mclient = clntudp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, retry_timeout, &msock); if (mclient) break; mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; case IPPROTO_TCP: mclient = clnttcp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, &msock, 0, 0); break; default: mclient = 0; } if (!mclient) { if (!daemonized && prevt == 0) error_msg_rpc(clnt_spcreateerror(" ")); } else { enum clnt_stat clnt_stat; /* try to mount hostname:pathname */ mclient->cl_auth = authunix_create_default(); /* make pointers in xdr_mountres3 NULL so * that xdr_array allocates memory for us */ memset(&status, 0, sizeof(status)); if (pm_mnt->pm_vers == 3) clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_mountres3, (caddr_t) &status, total_timeout); else clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_fhstatus, (caddr_t) &status, total_timeout); if (clnt_stat == RPC_SUCCESS) goto prepare_kernel_data; /* we're done */ if (errno != ECONNREFUSED) { error_msg_rpc(clnt_sperror(mclient, " ")); goto fail; /* don't retry */ } /* Connection refused */ if (!daemonized && prevt == 0) /* print just once */ error_msg_rpc(clnt_sperror(mclient, " ")); auth_destroy(mclient->cl_auth); clnt_destroy(mclient); mclient = 0; close(msock); } /* Timeout. We are going to retry... maybe */ if (!bg) goto fail; if (!daemonized) { daemonized = daemonize(); if (daemonized <= 0) { /* parent or error */ retval = -daemonized; goto ret; } } prevt = t; t = time(NULL); if (t >= timeout) /* TODO error message */ goto fail; goto retry; } prepare_kernel_data: if (nfsvers == 2) { if (status.nfsv2.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv2.fhs_status)); goto fail; } memcpy(data.root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); data.root.size = NFS_FHSIZE; memcpy(data.old_root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); } else { fhandle3 *my_fhandle; if (status.nfsv3.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv3.fhs_status)); goto fail; } my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; memset(data.old_root.data, 0, NFS_FHSIZE); memset(&data.root, 0, sizeof(data.root)); data.root.size = my_fhandle->fhandle3_len; memcpy(data.root.data, (char *) my_fhandle->fhandle3_val, my_fhandle->fhandle3_len); data.flags |= NFS_MOUNT_VER3; } /* create nfs socket for kernel */ if (tcp) { if (nfs_mount_version < 3) { bb_error_msg("NFS over TCP is not supported"); goto fail; } fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { bb_perror_msg("nfs socket"); goto fail; } if (bindresvport(fsock, 0) < 0) { bb_perror_msg("nfs bindresvport"); goto fail; } if (port == 0) { server_addr.sin_port = PMAPPORT; port = pmap_getport(&server_addr, nfsprog, nfsvers, tcp ? IPPROTO_TCP : IPPROTO_UDP); if (port == 0) port = NFS_PORT; } server_addr.sin_port = htons(port); /* prepare data structure for kernel */ data.fd = fsock; memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); strncpy(data.hostname, hostname, sizeof(data.hostname)); /* clean up */ auth_destroy(mclient->cl_auth); clnt_destroy(mclient); close(msock); if (bg) { /* We must wait until mount directory is available */ struct stat statbuf; int delay = 1; while (stat(mp->mnt_dir, &statbuf) == -1) { if (!daemonized) { daemonized = daemonize(); if (daemonized <= 0) { /* parent or error */ retval = -daemonized; goto ret; } } sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */ delay *= 2; if (delay > 30) delay = 30; } } do_mount: /* perform actual mount */ mp->mnt_type = (char*)"nfs"; retval = mount_it_now(mp, vfsflags, (char*)&data); goto ret; fail: /* abort */ if (msock != -1) { if (mclient) { auth_destroy(mclient->cl_auth); clnt_destroy(mclient); } close(msock); } if (fsock != -1) close(fsock); ret: free(hostname); free(mounthost); free(filteropts); return retval; }
/* * 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); }
int main(int argc, char **argv) { int sock, ch, rc, retval = EXIT_FAILURE; int port = SERVERPORT; char *server = BOSSNODE; struct sockaddr_in sin; whoami_t whoami; while ((ch = getopt(argc, argv, "ds:p:")) != -1) switch(ch) { case 's': server = optarg; break; case 'p': port = atoi(optarg); break; case 'd': debug++; break; case 'h': case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); if (strlen(argv[0]) >= sizeof(whoami.name)) fprintf(stderr, "Name too long: %s\n", argv[0]); if (getuid() != 0) fprintf(stderr, "Must be run as root\n"); memset(&whoami, 0, sizeof(whoami)); strcpy(whoami.name, argv[0]); whoami.portnum = -1; if (!mygethostbyname(&sin, server, port)) fprintf(stderr, "Bad server name: %s\n", server); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket"); else if (bindresvport(sock, NULL) < 0) perror("bindresvport"); else if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) perror("connect"); else if (write(sock, &whoami, sizeof(whoami)) != sizeof(whoami)) perror("write"); else if ((rc = read(sock, &port, sizeof(port))) != sizeof(port)) perror("read"); else { printf("%d\n", port); retval = EXIT_SUCCESS; } close(sock); return retval; }
/* * Set the date in the machines controlled by timedaemons by communicating the * new date to the local timedaemon. If the timedaemon is in the master state, * it performs the correction on all slaves. If it is in the slave state, it * notifies the master that a correction is needed. * Returns 0 on success. Returns > 0 on failure, setting retval to 2; */ int netsettime(time_t tval) { struct timeval tout; struct servent *sp; struct tsp msg; struct sockaddr_in sin, dest, from; int fdsn; fd_set *fdsp = NULL; long waittime; int s, timed_ack, found, error; socklen_t length; char hostname[MAXHOSTNAMELEN]; if ((sp = getservbyname("timed", "udp")) == NULL) { warnx("udp/timed: unknown service"); return (retval = 2); } memset(&dest, 0, sizeof(dest)); dest.sin_len = sizeof(struct sockaddr_in); dest.sin_family = AF_INET; dest.sin_port = sp->s_port; dest.sin_addr.s_addr = htonl(INADDR_ANY); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { if (errno != EPROTONOSUPPORT) warn("timed"); return (retval = 2); } memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; if (bindresvport(s, &sin) < 0) { warnx("all ports in use"); goto bad; } msg.tsp_type = TSP_SETDATE; msg.tsp_vers = TSPVERSION; if (gethostname(hostname, sizeof(hostname))) { warn("gethostname"); goto bad; } (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); msg.tsp_seq = htons((u_short)0); msg.tsp_time.tv_sec = htonl((u_long)tval); msg.tsp_time.tv_usec = htonl((u_long)0); length = sizeof(struct sockaddr_in); if (connect(s, (struct sockaddr *)&dest, length) < 0) { warn("connect"); goto bad; } if (send(s, &msg, sizeof(struct tsp), 0) < 0) { if (errno != ECONNREFUSED) warn("send"); goto bad; } timed_ack = -1; waittime = WAITACK; fdsn = howmany(s+1, NFDBITS) * sizeof(fd_mask); if ((fdsp = malloc(fdsn)) == NULL) err(1, "malloc"); loop: tout.tv_sec = waittime; tout.tv_usec = 0; memset(fdsp, 0, fdsn); FD_SET(s, fdsp); found = select(s+1, fdsp, NULL, NULL, &tout); length = sizeof(error); if (!getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &length) && error) { if (error != ECONNREFUSED) warn("send (delayed error)"); goto bad; } if (found > 0 && FD_ISSET(s, fdsp)) { length = sizeof(struct sockaddr_in); if (recvfrom(s, &msg, sizeof(struct tsp), 0, (struct sockaddr *)&from, &length) < 0) { if (errno != ECONNREFUSED) warn("recvfrom"); goto bad; } msg.tsp_seq = ntohs(msg.tsp_seq); msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); switch (msg.tsp_type) { case TSP_ACK: timed_ack = TSP_ACK; waittime = WAITDATEACK; goto loop; case TSP_DATEACK: (void)close(s); free(fdsp); return (0); default: warnx("wrong ack received from timed: %s", tsptype[msg.tsp_type]); timed_ack = -1; break; } } if (timed_ack == -1) warnx("can't reach time daemon, time set locally"); bad: if (fdsp) free(fdsp); (void)close(s); return (retval = 2); }
/* * Create a client handle for a tcp/ip connection. * If *sockp<0, *sockp is set to a newly created TCP socket and it is * connected to raddr. If *sockp non-negative then * raddr is ignored. The rpc/tcp package does buffering * similar to stdio, so the client must pick send and receive buffer sizes,]; * 0 => use the default. * If raddr->sin_port is 0, then a binder on the remote machine is * consulted for the right port number. * NB: *sockp is copied into a private area. * NB: It is the client's responsibility to close *sockp, unless * clnttcp_create() was called with *sockp = -1 (so it created * the socket), and CLNT_DESTROY() is used. * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this * something more useful. */ CLIENT * clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct = NULL; struct timeval now; struct rpc_msg call_msg; h = (CLIENT *)mem_alloc(sizeof(*h)); if (h == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } ct = (struct ct_data *)mem_alloc(sizeof(*ct)); if (ct == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } /* * If no port number given ask the pmap for one */ if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { mem_free((caddr_t)ct, sizeof(struct ct_data)); mem_free((caddr_t)h, sizeof(CLIENT)); return (NULL); } raddr->sin_port = htons(port); } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); (void)bindresvport(*sockp, NULL); if ((*sockp < 0) || (connect(*sockp, (struct sockaddr *)raddr, sizeof(*raddr)) < 0)) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; if (*sockp != -1) (void)close(*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ (void)gettimeofday(&now, NULL); call_msg.rm_xid = arc4random(); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void)close(*sockp); } 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. */ xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, (int(*)(caddr_t, caddr_t, int))writetcp); h->cl_ops = &tcp_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create(); if (h->cl_auth == NULL) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; goto fooy; } return (h); fooy: /* * Something goofed, free stuff and barf */ if (ct) mem_free((caddr_t)ct, sizeof(struct ct_data)); if (h) mem_free((caddr_t)h, sizeof(CLIENT)); return (NULL); }
CLIENT * clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *h; struct ct_data *ct; struct rpc_msg call_msg; h = (CLIENT *) mem_alloc (sizeof (*h)); ct = (struct ct_data *) mem_alloc (sizeof (*ct)); if (h == NULL || ct == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("clnttcp_create: out of memory\n")); else #endif (void) fputs (_("clnttcp_create: out of memory\n"), stderr); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } /* * If no port number given ask the pmap for one */ if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0) { mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return ((CLIENT *) NULL); } raddr->sin_port = htons (port); } /* * If no socket given, open one */ if (*sockp < 0) { *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); (void) bindresvport (*sockp, (struct sockaddr_in *) 0); if ((*sockp < 0) || (connect (*sockp, (struct sockaddr *) raddr, sizeof (*raddr)) < 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; if (*sockp >= 0) (void) close (*sockp); goto fooy; } ct->ct_closeit = TRUE; } else { ct->ct_closeit = FALSE; } /* * Set up private data struct */ ct->ct_sock = *sockp; ct->ct_wait.tv_usec = 0; ct->ct_waitset = FALSE; ct->ct_addr = *raddr; /* * Initialize call message */ call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; /* * pre-serialize the static part of the call msg and stash it away */ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg)) { if (ct->ct_closeit) { (void) close (*sockp); } 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. */ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz, (caddr_t) ct, readtcp, writetcp); h->cl_ops = &tcp_ops; h->cl_private = (caddr_t) ct; h->cl_auth = authnone_create (); return h; fooy: /* * Something goofed, free stuff and barf */ mem_free ((caddr_t) ct, sizeof (struct ct_data)); mem_free ((caddr_t) h, sizeof (CLIENT)); return ((CLIENT *) NULL); }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmission occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT * __libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz, int flags) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); (void) __fxprintf (NULL, "%s: %s", "clntudp_create", _("out of memory\n")); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = (struct clnt_ops *) &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 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)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { #ifdef SOCK_NONBLOCK # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec >= 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags, IPPROTO_UDP); # ifndef __ASSUME_SOCK_CLOEXEC if (__have_sock_cloexec == 0) __have_sock_cloexec = *sockp >= 0 || errno != EINVAL ? 1 : -1; # endif } #endif #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { *sockp = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); # ifdef SOCK_CLOEXEC if (flags & SOCK_CLOEXEC) __fcntl (*sockp, F_SETFD, FD_CLOEXEC); # endif } #endif if (__builtin_expect (*sockp < 0, 0)) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); #ifndef __ASSUME_SOCK_CLOEXEC # ifdef SOCK_CLOEXEC if (__have_sock_cloexec < 0) # endif { /* the sockets rpc controls are non-blocking */ int dontblock = 1; (void) __ioctl (*sockp, FIONBIO, (char *) &dontblock); } #endif #ifdef IP_RECVERR { int on = 1; __setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
int openrm( char *host, /* I */ unsigned int port) /* I (optional,0=DEFAULT) */ { int stream; int rc; int retries = 0; static unsigned int gotport = 0; if (port == 0) { if (gotport == 0) { gotport = get_svrport((char *)PBS_MANAGER_SERVICE_NAME, (char *)"tcp", PBS_MANAGER_SERVICE_PORT); } /* END if (gotport == 0) */ port = gotport; } if ((stream = socket(AF_INET, SOCK_STREAM, 0)) != -1) { struct sockaddr_in addr; struct addrinfo *addr_info; if (pbs_getaddrinfo(host, NULL, &addr_info) != 0) { DBPRT(("host %s not found\n", host)) close(stream); return(ENOENT * -1); } memset(&addr, '\0', sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); while (retries++ < MAX_RETRIES) { rc = bindresvport(stream, &addr); if (rc != 0) { if (retries >= MAX_RETRIES) { close(stream); return(-1*errno); } sleep(1); } else break; } memset(&addr, '\0', sizeof(addr)); addr.sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr; addr.sin_family = AF_INET; addr.sin_port = htons((unsigned short)port); if (connect(stream, (struct sockaddr *)&addr, sizeof(addr)) == -1) { close(stream); return(-1 * errno); } } /* END if ((stream = socket(AF_INET,SOCK_STREAM,0)) != -1) */ if (stream < 0) { return(-1 * errno); } if (addrm(stream) == -1) { close(stream); return(-1 * errno); } return(stream); } /* END openrm() */
static int nd_init(vnode_t *dumpvp, TIUSER **tiptr) { int error; if (*tiptr) return (0); /* * If dump info hasn't yet been initialized (because dump * device was chosen at user-level, rather than at boot time * in nfs_swapvp) fill it in now. */ if (nfsdump_maxcount == 0) { nfsdump_version = VTOMI(dumpvp)->mi_vers; switch (nfsdump_version) { case NFS_VERSION: nfsdump_fhandle2 = *VTOFH(dumpvp); break; case NFS_V3: nfsdump_fhandle3 = *VTOFH3(dumpvp); break; default: return (EIO); } nfsdump_maxcount = (int)dumpvp_size; nfsdump_addr = VTOMI(dumpvp)->mi_curr_serv->sv_addr; nfsdump_cf = *(VTOMI(dumpvp)->mi_curr_serv->sv_knconf); if (nfsdump_cf.knc_semantics != NC_TPI_CLTS) { int v6 = 1; nd_log("nfs_dump: not connectionless!\n"); if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) || ((v6 = strcmp(nfsdump_cf.knc_protofmly, NC_INET6))\ == 0)) { major_t clone_maj; nfsdump_cf.knc_proto = NC_UDP; nfsdump_cf.knc_semantics = NC_TPI_CLTS; nd_log("nfs_dump: grabbing UDP major number\n"); clone_maj = ddi_name_to_major("clone"); nd_log("nfs_dump: making UDP device\n"); nfsdump_cf.knc_rdev = makedevice(clone_maj, ddi_name_to_major(v6?"udp":"udp6")); } else { error = EIO; nfs_perror(error, "\nnfs_dump: cannot dump over" " protocol %s: %m\n", nfsdump_cf.knc_proto); return (error); } } } nd_log("nfs_dump: calling t_kopen\n"); if (error = t_kopen(NULL, nfsdump_cf.knc_rdev, FREAD|FWRITE|FNDELAY, tiptr, CRED())) { nfs_perror(error, "\nnfs_dump: t_kopen failed: %m\n"); return (EIO); } if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) || (strcmp(nfsdump_cf.knc_protofmly, NC_INET6) == 0)) { nd_log("nfs_dump: calling bindresvport\n"); if (error = bindresvport(*tiptr, NULL, NULL, FALSE)) { nfs_perror(error, "\nnfs_dump: bindresvport failed: %m\n"); return (EIO); } } else { nd_log("nfs_dump: calling t_kbind\n"); if ((error = t_kbind(*tiptr, NULL, NULL)) != 0) { nfs_perror(error, "\nnfs_dump: t_kbind failed: %m\n"); return (EIO); } } return (0); }
static enum clnt_stat clnt_reconnect_connect(CLIENT *cl) { struct thread *td = curthread; struct rc_data *rc = (struct rc_data *)cl->cl_private; struct socket *so; enum clnt_stat stat; int error; int one = 1; struct ucred *oldcred; CLIENT *newclient = NULL; mtx_lock(&rc->rc_lock); while (rc->rc_connecting) { error = msleep(rc, &rc->rc_lock, rc->rc_intr ? PCATCH : 0, "rpcrecon", 0); if (error) { mtx_unlock(&rc->rc_lock); return (RPC_INTR); } } if (rc->rc_closed) { mtx_unlock(&rc->rc_lock); return (RPC_CANTSEND); } if (rc->rc_client) { mtx_unlock(&rc->rc_lock); return (RPC_SUCCESS); } /* * My turn to attempt a connect. The rc_connecting variable * serializes the following code sequence, so it is guaranteed * that rc_client will still be NULL after it is re-locked below, * since that is the only place it is set non-NULL. */ rc->rc_connecting = TRUE; mtx_unlock(&rc->rc_lock); oldcred = td->td_ucred; td->td_ucred = rc->rc_ucred; so = __rpc_nconf2socket(rc->rc_nconf); if (!so) { stat = rpc_createerr.cf_stat = RPC_TLIERROR; rpc_createerr.cf_error.re_errno = 0; td->td_ucred = oldcred; goto out; } if (rc->rc_privport) bindresvport(so, NULL); if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS) newclient = clnt_dg_create(so, (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, rc->rc_sendsz, rc->rc_recvsz); else newclient = clnt_vc_create(so, (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr); td->td_ucred = oldcred; if (!newclient) { soclose(so); rc->rc_err = rpc_createerr.cf_error; stat = rpc_createerr.cf_stat; goto out; } CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0); CLNT_CONTROL(newclient, CLSET_CONNECT, &one); CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout); CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry); CLNT_CONTROL(newclient, CLSET_WAITCHAN, rc->rc_waitchan); CLNT_CONTROL(newclient, CLSET_INTERRUPTIBLE, &rc->rc_intr); if (rc->rc_backchannel != NULL) CLNT_CONTROL(newclient, CLSET_BACKCHANNEL, rc->rc_backchannel); stat = RPC_SUCCESS; out: mtx_lock(&rc->rc_lock); KASSERT(rc->rc_client == NULL, ("rc_client not null")); if (!rc->rc_closed) { rc->rc_client = newclient; newclient = NULL; } rc->rc_connecting = FALSE; wakeup(rc); mtx_unlock(&rc->rc_lock); if (newclient) { /* * It has been closed, so discard the new client. * nb: clnt_[dg|vc]_close()/clnt_[dg|vc]_destroy() cannot * be called with the rc_lock mutex held, since they may * msleep() while holding a different mutex. */ CLNT_CLOSE(newclient); CLNT_RELEASE(newclient); } return (stat); }
/* * Usage: * xprt = svcudp_create(sock); * * If sock<0 then a socket is created, else sock is used. * If the socket, sock is not bound to a port then svcudp_create * binds it to an arbitrary port. In any (successful) case, * xprt->xp_sock is the registered socket number and xprt->xp_port is the * associated port number. * Once *xprt is initialized, it is registered as a transporter; * see (svc.h, xprt_register). * The routines returns NULL if a problem occurred. */ SVCXPRT * svcudp_bufcreate (int sock, u_int sendsz, u_int recvsz) { bool_t madesock = FALSE; SVCXPRT *xprt; struct svcudp_data *su; struct sockaddr_in addr; socklen_t len = sizeof (struct sockaddr_in); int pad; void *buf; if (sock == RPC_ANYSOCK) { if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror (_("svcudp_create: socket creation problem")); return (SVCXPRT *) NULL; } madesock = TRUE; } memset ((char *) &addr, 0, sizeof (addr)); addr.sin_family = AF_INET; if (bindresvport (sock, &addr)) { addr.sin_port = 0; (void) bind (sock, (struct sockaddr *) &addr, len); } if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0) { perror (_("svcudp_create - cannot getsockname")); if (madesock) (void) close (sock); return (SVCXPRT *) NULL; } xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT)); su = (struct svcudp_data *) mem_alloc (sizeof (*su)); buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4); if (xprt == NULL || su == NULL || buf == NULL) { #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("svcudp_create: out of memory\n")); else #endif (void) fputs (_("svcudp_create: out of memory\n"), stderr); mem_free (xprt, sizeof (SVCXPRT)); mem_free (su, sizeof (*su)); mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4); return NULL; } su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4; rpc_buffer (xprt) = buf; xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE); su->su_cache = NULL; xprt->xp_p2 = (caddr_t) su; xprt->xp_verf.oa_base = su->su_verfbody; xprt->xp_ops = &svcudp_op; xprt->xp_port = ntohs (addr.sin_port); xprt->xp_sock = sock; #ifdef IP_PKTINFO if ((sizeof (struct iovec) + sizeof (struct msghdr) + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo)) > sizeof (xprt->xp_pad)) { # ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("svcudp_create: xp_pad is too small for IP_PKTINFO\n")); else # endif (void) fputs (_("svcudp_create: xp_pad is too small for IP_PKTINFO\n"), stderr); return NULL; } pad = 1; if (setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad, sizeof (pad)) == 0) /* Set the padding to all 1s. */ pad = 0xff; else #endif /* Clear the padding. */ pad = 0; memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad)); xprt_register (xprt); return xprt; }
/* * A common clnt create routine */ static CLIENT * clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp, u_int sendsz, u_int recvsz, const char *tp) { CLIENT *cl; int madefd = FALSE; int fd; struct netconfig *nconf; struct netbuf bindaddr; _DIAGASSERT(raddr != NULL); _DIAGASSERT(sockp != NULL); _DIAGASSERT(tp != NULL); fd = *sockp; mutex_lock(&rpcsoc_lock); if ((nconf = __rpc_getconfip(tp)) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; mutex_unlock(&rpcsoc_lock); return (NULL); } if (fd == RPC_ANYSOCK) { fd = __rpc_nconf2fd(nconf); if (fd == -1) goto syserror; madefd = TRUE; } if (raddr->sin_port == 0) { u_int proto; u_short sport; mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, proto); if (sport == 0) { goto err; } raddr->sin_port = htons(sport); mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ } /* Transform sockaddr_in to netbuf */ bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); bindaddr.buf = raddr; (void)bindresvport(fd, NULL); cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, sendsz, recvsz); if (cl) { if (madefd == TRUE) { /* * The fd should be closed while destroying the handle. */ (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); *sockp = fd; } (void) freenetconfigent(nconf); mutex_unlock(&rpcsoc_lock); return (cl); } goto err; syserror: rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; err: if (madefd == TRUE) (void) close(fd); (void) freenetconfigent(nconf); mutex_unlock(&rpcsoc_lock); return (NULL); }
/* libc_hidden_proto(clntudp_bufcreate) */ CLIENT * clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz) { CLIENT *cl; struct cu_data *cu = NULL; struct rpc_msg call_msg; cl = (CLIENT *) mem_alloc (sizeof (CLIENT)); sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz); if (cl == NULL || cu == NULL) { struct rpc_createerr *ce = &get_rpc_createerr (); #ifdef USE_IN_LIBIO if (_IO_fwide (stderr, 0) > 0) (void) fwprintf (stderr, L"%s", _("clntudp_create: out of memory\n")); else #endif (void) fputs (_("clntudp_create: out of memory\n"), stderr); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = ENOMEM; goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; if (raddr->sin_port == 0) { u_short port; if ((port = pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons (port); } cl->cl_ops = &udp_ops; cl->cl_private = (caddr_t) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof (cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = _create_xid (); call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 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)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs)); if (*sockp < 0) { int dontblock = 1; *sockp = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sockp < 0) { struct rpc_createerr *ce = &get_rpc_createerr (); ce->cf_stat = RPC_SYSTEMERROR; ce->cf_error.re_errno = errno; goto fooy; } /* attempt to bind to prov port */ (void) bindresvport (*sockp, (struct sockaddr_in *) 0); /* the sockets rpc controls are non-blocking */ (void) ioctl (*sockp, FIONBIO, (char *) &dontblock); #ifdef IP_RECVERR { int on = 1; setsockopt(*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on)); } #endif cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create (); return cl; fooy: if (cu) mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz); if (cl) mem_free ((caddr_t) cl, sizeof (CLIENT)); return (CLIENT *) NULL; }
/* * Create a UDP based client handle. * If *sockp<0, *sockp is set to a newly created UPD socket. * If raddr->sin_port is 0 a binder on the remote machine * is consulted for the correct port number. * NB: It is the clients responsibility to close *sockp. * NB: The rpch->cl_auth is initialized to null authentication. * Caller may wish to set this something more useful. * * wait is the amount of time used between retransmitting a call if * no response has been heard; retransmition occurs until the actual * rpc call times out. * * sendsz and recvsz are the maximum allowable packet sizes that can be * sent and received. */ CLIENT *clntudp_bufcreate(struct sockaddr_in *raddr, unsigned long program, unsigned long version, struct timeval wait, int *sockp, unsigned int sendsz, unsigned int recvsz) { CLIENT *cl; register struct cu_data *cu = NULL; struct timeval now; struct rpc_msg call_msg; static uintptr_t disrupt = 0; cl = (CLIENT *) sys_malloc (sizeof(CLIENT)); if (cl == NULL) { fprintf(stderr, "rpc : clntudp_create: out of memory\n"); goto fooy; } sendsz = ((sendsz + 3) / 4) * 4; recvsz = ((recvsz + 3) / 4) * 4; cu = (struct cu_data *) sys_malloc (sizeof(*cu) + sendsz + recvsz); if (cu == NULL) { fprintf(stderr, "rpc : clntudp_create: out of memory\n"); goto fooy; } cu->cu_outbuf = &cu->cu_inbuf[recvsz]; (void)gettimeofday(&now, (struct timezone *)0); if (raddr->sin_port == 0) { unsigned short port; if ((port = pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { goto fooy; } raddr->sin_port = htons(port); } cl->cl_ops = &udp_ops; cl->cl_private = (char*) cu; cu->cu_raddr = *raddr; cu->cu_rlen = sizeof(cu->cu_raddr); cu->cu_wait = wait; cu->cu_total.tv_sec = -1; cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 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)) { goto fooy; } cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); if (*sockp < 0) { int dontblock = 1; *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sockp < 0) { fprintf(stderr, "rpc : create socket error\n"); goto fooy; } /* attempt to bind to prov port */ (void)bindresvport(*sockp, (struct sockaddr_in *)0); cu->cu_closeit = TRUE; } else { cu->cu_closeit = FALSE; } cu->cu_sock = *sockp; cl->cl_auth = authnone_create(); /* sylixos fix this bug new socket must set timeout argments 2012.03.10 */ clnt_control(cl, CLSET_TIMEOUT, (char*)&wait); return (cl); fooy: if (cu) sys_free(cu); if (cl) sys_free(cl); return ((CLIENT *) NULL); }
int socket_get_tcp_priv() { int priv_port = 0, local_socket = 0; int cntr = 0; #ifdef HAVE_RRESVPORT int on = 1; struct linger l_delay; #endif int rc = PBSE_NONE; struct sockaddr_in local; int flags; memset(&local, 0, sizeof(struct sockaddr_in)); local.sin_family = AF_INET; /* If any of the following 2 succeed (negative conditions) jump to else below * else run the default */ #ifdef HAVE_RRESVPORT memset(&l_delay, 0, sizeof(struct linger)); l_delay.l_onoff = 0; if ((local_socket = rresvport(&priv_port)) != -1) { if (setsockopt(local_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) == -1) { rc = PBSE_SOCKET_FAULT; } else if (setsockopt(local_socket, SOL_SOCKET, SO_LINGER, &l_delay, sizeof(struct linger)) == -1) { rc = PBSE_SOCKET_FAULT; } } if (rc == PBSE_NONE) { /* Success case */ priv_port = local_socket; } else if ((local_socket = socket_get_tcp()) > 0) #else #ifdef HAVE_BINDRESVPORT if ((local_socket = socket_get_tcp()) > 0) { if ((rc = bindresvport(local_socket, &local)) == 0) { /* Success case */ priv_port = ntohs(local.sin_port); } else { rc = PBSE_SOCKET_FAULT; } } else rc = PBSE_SOCKET_FAULT; if (rc != PBSE_NONE) #else /* Default */ if ((local_socket = socket_get_tcp()) > 0) #endif #endif { /* According to the notes in the previous code: * bindresvport seems to cause connect() failures in some odd corner case * when talking to a local daemon. So we'll only try this once and * fallback to the slow loop around bind() if connect() fails * with EADDRINUSE or EADDRNOTAVAIL. * http://www.supercluster.org/pipermail/torqueusers/2006-June/003740.html */ flags = fcntl(local_socket, F_GETFL); flags |= O_NONBLOCK; fcntl(local_socket, F_SETFL, flags); priv_port = get_random_reserved_port(); while (cntr < RES_PORT_RETRY) { if (++priv_port >= RES_PORT_END) priv_port = RES_PORT_START; local.sin_port = htons(priv_port); if (((rc = bind(local_socket, (struct sockaddr *)&local, sizeof(struct sockaddr))) < 0) && ((rc == EADDRINUSE) || (errno == EADDRNOTAVAIL) || (errno == EINVAL) || (rc == EINPROGRESS))) { cntr++; } else { rc = PBSE_NONE; break; } } if (cntr >= RES_PORT_RETRY) { close(local_socket); rc = PBSE_SOCKET_FAULT; errno = PBSE_SOCKET_FAULT; local_socket = -1; } } else { /* If something worked the first time you end up here */ rc = PBSE_NONE; } if (rc != PBSE_NONE) { local_socket = -1; } return local_socket; } /* END socket_get_tcp_priv() */
/* * Usage: * xprt = svctcp_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. * * If sock<0 then a socket is created, else sock is used. * If the socket, @var{sock}, is not bound to a port then svctcp_create * binds it to an arbitrary port. The routine then starts a tcp * listener on the socket's associated port. In any (successful) case, * xprt->xp_sock is the registered socket number and xprt->xp_port is the * associated port number. * * Since tcp 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 * svctcp_create_with_lock(int sock, u_int sendsize, u_int recvsize) { bool_t madesock; SVCXPRT *xprt; mtxprt_t *mtxprt; struct tcp_rendezvous *r; struct sockaddr_in addr; socklen_t len; int ret; int err; #ifdef DEBUG_BUFSIZE_8K if (sendsize == 0) { sendsize = 8192; // Magic number. For debugging only. } if (recvsize == 0) { recvsize = 8192; // Magic number. For debugging only. } #endif /* DEBUG_BUFSIZE_8K */ tprintf(2, "sock=%d, sendsize=%u, recvsize=%u\n", sock, sendsize, recvsize); madesock = FALSE; len = sizeof (struct sockaddr_in); if (sock == RPC_ANYSOCK) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); tprintf(2, "socket() => %d\n", sock); if (sock < 0) { svc_perror(errno, "svc_tcp.c - tcp socket creation problem"); return ((SVCXPRT *)NULL); } madesock = TRUE; } bzero((char *)&addr, sizeof (addr)); addr.sin_family = AF_INET; if (bindresvport(sock, &addr)) { addr.sin_port = 0; (void) bind(sock, (struct sockaddr *)&addr, len); } ret = getsockname(sock, (struct sockaddr *)&addr, &len); if (ret != 0) { err = errno; svc_perror(err, "svc_tcp.c - getsockname(...) failed"); } else { ret = listen(sock, SOMAXCONN); if (ret != 0) { err = errno; svc_perror(err, "svc_tcp.c - listen() failed"); } } if (ret != 0) { if (madesock) { (void) close(sock); } return ((SVCXPRT *)NULL); } r = (struct tcp_rendezvous *)guard_malloc(sizeof (*r)); xprt = alloc_xprt(); /* * Constructor for @type{SVCXPRT}, including the additional @type{mtxprt_t} * Order of construction is important. * We want to create a lock for each @type{SVCXPRT}. * The rest of the contructor should all be done while the lock is held. * Even if it is not _really_ necessary, it will keep Valgrind/Helgrind * happy. And they are our friends. * Second step is to initialize the "magic" value, so that other * helper functions that validate it will be happy. */ mtxprt = xprt_to_mtxprt_nocheck(xprt); if (pthread_mutex_init(&(mtxprt->mtxp_lock), NULL) != 0) { abort(); } if (pthread_mutex_init(&(mtxprt->mtxp_progress_lock), NULL) != 0) { abort(); } if (pthread_mutex_init(&(mtxprt->mtxp_mtready), NULL) != 0) { abort(); } // Start off locked. svctcp_getargs() will unlock it. if (pthread_mutex_lock(&(mtxprt->mtxp_mtready)) != 0) { abort(); } /* * Do not use xprt_lock(xprt) here. * The constructor has not progressed far enough, yet. */ if (pthread_mutex_lock(&(mtxprt->mtxp_lock)) != 0) { abort(); } /* * Set "magic", right away. * Other functions validate it. Keep them happy. */ mtxprt->mtxp_magic = MTXPRT_MAGIC; r->sendsize = sendsize; r->recvsize = recvsize; mtxprt->mtxp_progress = 0; mtxprt->mtxp_busy = 0; xprt->xp_p2 = NULL; xprt->xp_p1 = (caddr_t)r; xprt->xp_verf = _null_auth; xprt->xp_ops = &svctcp_rendezvous_op; xprt->xp_port = ntohs(addr.sin_port); xprt->xp_sock = sock; mtxprt->mtxp_creator = pthread_self(); mtxprt->mtxp_id = XPRT_ID_INVALID; mtxprt->mtxp_clone = NULL; mtxprt->mtxp_parent = NO_PARENT; mtxprt->mtxp_refcnt = 0; #ifdef CHECK_CREDENTIALS memset(mtxprt->mtxp_cred, 0, sizeof (mtxprt->mtxp_cred)); #endif memcpy(mtxprt->mtxp_guard, MTXPRT_GUARD, sizeof (mtxprt->mtxp_guard)); xprt_unlock(xprt); xprt_register(xprt); return (xprt); }
CLIENT * get_client(struct sockaddr *host_addr, rpcvers_t vers) { CLIENT *client; struct timeval retry_time, time_now; int error, i; const char *netid; struct netconfig *nconf; char host[NI_MAXHOST]; uid_t old_euid; int clnt_fd; gettimeofday(&time_now, NULL); /* * Search for the given client in the cache, zapping any expired * entries that we happen to notice in passing. */ for (i = 0; i < CLIENT_CACHE_SIZE; i++) { client = clnt_cache_ptr[i]; if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) < time_now.tv_sec)) { /* Cache entry has expired. */ if (debug_level > 3) syslog(LOG_DEBUG, "Expired CLIENT* in cache"); clnt_cache_time[i] = 0L; clnt_destroy(client); clnt_cache_ptr[i] = NULL; client = NULL; } if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i], host_addr) && clnt_cache_vers[i] == vers) { /* Found it! */ if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache"); return (client); } } if (debug_level > 3) syslog(LOG_DEBUG, "CLIENT* not found in cache, creating"); /* Not found in cache. Free the next entry if it is in use. */ if (clnt_cache_ptr[clnt_cache_next_to_use]) { clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); clnt_cache_ptr[clnt_cache_next_to_use] = NULL; } /* * Need a host string for clnt_tp_create. Use NI_NUMERICHOST * to avoid DNS lookups. */ error = getnameinfo(host_addr, host_addr->sa_len, host, sizeof host, NULL, 0, NI_NUMERICHOST); if (error != 0) { syslog(LOG_ERR, "unable to get name string for caller: %s", gai_strerror(error)); return NULL; } #if 1 if (host_addr->sa_family == AF_INET6) netid = "udp6"; else netid = "udp"; #else if (host_addr->sa_family == AF_INET6) netid = "tcp6"; else netid = "tcp"; #endif nconf = getnetconfigent(netid); if (nconf == NULL) { syslog(LOG_ERR, "could not get netconfig info for '%s': " "no /etc/netconfig file?", netid); return NULL; } client = clnt_tp_create(host, NLM_PROG, vers, nconf); freenetconfigent(nconf); if (!client) { syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create")); syslog(LOG_ERR, "Unable to return result to %s", host); return NULL; } /* Get the FD of the client, for bindresvport. */ clnt_control(client, CLGET_FD, &clnt_fd); /* Regain root privileges, for bindresvport. */ old_euid = geteuid(); seteuid(0); /* * Bind the client FD to a reserved port. * Some NFS servers reject any NLM request from a non-reserved port. */ bindresvport(clnt_fd, NULL); /* Drop root privileges again. */ seteuid(old_euid); /* Success - update the cache entry */ clnt_cache_ptr[clnt_cache_next_to_use] = client; memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr, host_addr->sa_len); clnt_cache_vers[clnt_cache_next_to_use] = vers; clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE) clnt_cache_next_to_use = 0; /* * Disable the default timeout, so we can specify our own in calls * to clnt_call(). (Note that the timeout is a different concept * from the retry period set in clnt_udp_create() above.) */ retry_time.tv_sec = -1; retry_time.tv_usec = -1; clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); if (debug_level > 3) syslog(LOG_DEBUG, "Created CLIENT* for %s", host); return client; }
int nfsmount(const char *spec, const char *node, int *flags, char **extra_opts, char **mount_opts, int running_bg) { static char *prev_bg_host; char hostdir[1024]; CLIENT *mclient; char *hostname; char *pathname; char *old_opts; char *mounthost=NULL; char new_opts[1024]; struct timeval total_timeout; enum clnt_stat clnt_stat; static struct nfs_mount_data data; char *opt, *opteq; int val; struct hostent *hp; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; struct pmap* pm_mnt; int msock, fsock; struct timeval retry_timeout; union { struct fhstatus nfsv2; struct mountres3 nfsv3; } status; struct stat statbuf; char *s; int port; int mountport; int proto; int bg; int soft; int intr; int posix; int nocto; int noac; int nolock; int retry; int tcp; int mountprog; int mountvers; int nfsprog; int nfsvers; int retval; time_t t; time_t prevt; time_t timeout; find_kernel_nfs_mount_version(); retval = EX_FAIL; msock = fsock = -1; mclient = NULL; if (strlen(spec) >= sizeof(hostdir)) { bb_error_msg("excessively long host:dir argument"); goto fail; } strcpy(hostdir, spec); if ((s = strchr(hostdir, ':'))) { hostname = hostdir; pathname = s + 1; *s = '\0'; /* Ignore all but first hostname in replicated mounts until they can be fully supported. ([email protected]) */ if ((s = strchr(hostdir, ','))) { *s = '\0'; bb_error_msg("warning: multiple hostnames not supported"); } } else { bb_error_msg("directory to mount not in host:dir format"); goto fail; } server_addr.sin_family = AF_INET; #ifdef HAVE_inet_aton if (!inet_aton(hostname, &server_addr.sin_addr)) #endif { if ((hp = gethostbyname(hostname)) == NULL) { bb_herror_msg("%s", hostname); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length"); hp->h_length = sizeof(struct in_addr); } memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); } } memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); /* add IP address to mtab options for use when unmounting */ s = inet_ntoa(server_addr.sin_addr); old_opts = *extra_opts; if (!old_opts) old_opts = ""; if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { bb_error_msg("excessively long option argument"); goto fail; } sprintf(new_opts, "%s%saddr=%s", old_opts, *old_opts ? "," : "", s); *extra_opts = bb_xstrdup(new_opts); /* Set default options. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to * let the kernel decide. * timeo is filled in after we know whether it'll be TCP or UDP. */ memset(&data, 0, sizeof(data)); data.retrans = 3; data.acregmin = 3; data.acregmax = 60; data.acdirmin = 30; data.acdirmax = 60; #if NFS_MOUNT_VERSION >= 2 data.namlen = NAME_MAX; #endif bg = 0; soft = 0; intr = 0; posix = 0; nocto = 0; nolock = 0; noac = 0; retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 0; mountprog = MOUNTPROG; mountvers = 0; port = 0; mountport = 0; nfsprog = NFS_PROGRAM; nfsvers = 0; /* parse options */ for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { if ((opteq = strchr(opt, '='))) { val = atoi(opteq + 1); *opteq = '\0'; if (!strcmp(opt, "rsize")) data.rsize = val; else if (!strcmp(opt, "wsize")) data.wsize = val; else if (!strcmp(opt, "timeo")) data.timeo = val; else if (!strcmp(opt, "retrans")) data.retrans = val; else if (!strcmp(opt, "acregmin")) data.acregmin = val; else if (!strcmp(opt, "acregmax")) data.acregmax = val; else if (!strcmp(opt, "acdirmin")) data.acdirmin = val; else if (!strcmp(opt, "acdirmax")) data.acdirmax = val; else if (!strcmp(opt, "actimeo")) { data.acregmin = val; data.acregmax = val; data.acdirmin = val; data.acdirmax = val; } else if (!strcmp(opt, "retry")) retry = val; else if (!strcmp(opt, "port")) port = val; else if (!strcmp(opt, "mountport")) mountport = val; else if (!strcmp(opt, "mounthost")) mounthost=bb_xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,")); else if (!strcmp(opt, "mountprog")) mountprog = val; else if (!strcmp(opt, "mountvers")) mountvers = val; else if (!strcmp(opt, "nfsprog")) nfsprog = val; else if (!strcmp(opt, "nfsvers") || !strcmp(opt, "vers")) nfsvers = val; else if (!strcmp(opt, "proto")) { if (!strncmp(opteq+1, "tcp", 3)) tcp = 1; else if (!strncmp(opteq+1, "udp", 3)) tcp = 0; else printf(_("Warning: Unrecognized proto= option.\n")); } else if (!strcmp(opt, "namlen")) { #if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.namlen = val; else #endif printf(_("Warning: Option namlen is not supported.\n")); } else if (!strcmp(opt, "addr")) /* ignore */; else { printf(_("unknown nfs mount parameter: " "%s=%d\n"), opt, val); goto fail; } } else { val = 1; if (!strncmp(opt, "no", 2)) { val = 0; opt += 2; } if (!strcmp(opt, "bg")) bg = val; else if (!strcmp(opt, "fg")) bg = !val; else if (!strcmp(opt, "soft")) soft = val; else if (!strcmp(opt, "hard")) soft = !val; else if (!strcmp(opt, "intr")) intr = val; else if (!strcmp(opt, "posix")) posix = val; else if (!strcmp(opt, "cto")) nocto = !val; else if (!strcmp(opt, "ac")) noac = !val; else if (!strcmp(opt, "tcp")) tcp = val; else if (!strcmp(opt, "udp")) tcp = !val; else if (!strcmp(opt, "lock")) { if (nfs_mount_version >= 3) nolock = !val; else printf(_("Warning: option nolock is not supported.\n")); } else { printf(_("unknown nfs mount option: " "%s%s\n"), val ? "" : "no", opt); goto fail; } } } proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; data.flags = (soft ? NFS_MOUNT_SOFT : 0) | (intr ? NFS_MOUNT_INTR : 0) | (posix ? NFS_MOUNT_POSIX : 0) | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0); #if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.flags |= (tcp ? NFS_MOUNT_TCP : 0); #endif #if NFS_MOUNT_VERSION >= 3 if (nfs_mount_version >= 3) data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); #endif if (nfsvers > MAX_NFSPROT) { bb_error_msg("NFSv%d not supported!", nfsvers); return 0; } if (mountvers > MAX_NFSPROT) { bb_error_msg("NFSv%d not supported!", nfsvers); return 0; } if (nfsvers && !mountvers) mountvers = (nfsvers < 3) ? 1 : nfsvers; if (nfsvers && nfsvers < mountvers) { mountvers = nfsvers; } /* Adjust options if none specified */ if (!data.timeo) data.timeo = tcp ? 70 : 7; #ifdef NFS_MOUNT_DEBUG printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", data.rsize, data.wsize, data.timeo, data.retrans); printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", port, bg, retry, data.flags); printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", mountprog, mountvers, nfsprog, nfsvers); printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", (data.flags & NFS_MOUNT_SOFT) != 0, (data.flags & NFS_MOUNT_INTR) != 0, (data.flags & NFS_MOUNT_POSIX) != 0, (data.flags & NFS_MOUNT_NOCTO) != 0, (data.flags & NFS_MOUNT_NOAC) != 0); #if NFS_MOUNT_VERSION >= 2 printf("tcp = %d\n", (data.flags & NFS_MOUNT_TCP) != 0); #endif #endif data.version = nfs_mount_version; *mount_opts = (char *) &data; if (*flags & MS_REMOUNT) return 0; /* * If the previous mount operation on the same host was * backgrounded, and the "bg" for this mount is also set, * give up immediately, to avoid the initial timeout. */ if (bg && !running_bg && prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { if (retry > 0) retval = EX_BG; return retval; } /* create mount deamon client */ /* See if the nfs host = mount host. */ if (mounthost) { if (mounthost[0] >= '0' && mounthost[0] <= '9') { mount_server_addr.sin_family = AF_INET; mount_server_addr.sin_addr.s_addr = inet_addr(hostname); } else { if ((hp = gethostbyname(mounthost)) == NULL) { bb_herror_msg("%s", mounthost); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length?"); hp->h_length = sizeof(struct in_addr); } mount_server_addr.sin_family = AF_INET; memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length); } } } /* * The following loop implements the mount retries. On the first * call, "running_bg" is 0. When the mount times out, and the * "bg" option is set, the exit status EX_BG will be returned. * For a backgrounded mount, there will be a second call by the * child process with "running_bg" set to 1. * * The case where the mount point is not present and the "bg" * option is set, is treated as a timeout. This is done to * support nested mounts. * * The "retry" count specified by the user is the number of * minutes to retry before giving up. * * Only the first error message will be displayed. */ retry_timeout.tv_sec = 3; retry_timeout.tv_usec = 0; total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; timeout = time(NULL) + 60 * retry; prevt = 0; t = 30; val = 1; for (;;) { if (bg && stat(node, &statbuf) == -1) { if (running_bg) { sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ val *= 2; if (val > 30) val = 30; } } else { /* be careful not to use too many CPU cycles */ if (t - prevt < 30) sleep(30); pm_mnt = get_mountport(&mount_server_addr, mountprog, mountvers, proto, mountport); /* contact the mount daemon via TCP */ mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; switch (pm_mnt->pm_prot) { case IPPROTO_UDP: mclient = clntudp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, retry_timeout, &msock); if (mclient) break; mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; case IPPROTO_TCP: mclient = clnttcp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, &msock, 0, 0); break; default: mclient = 0; } if (mclient) { /* try to mount hostname:pathname */ mclient->cl_auth = authunix_create_default(); /* make pointers in xdr_mountres3 NULL so * that xdr_array allocates memory for us */ memset(&status, 0, sizeof(status)); if (pm_mnt->pm_vers == 3) clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_mountres3, (caddr_t) &status, total_timeout); else clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_fhstatus, (caddr_t) &status, total_timeout); if (clnt_stat == RPC_SUCCESS) break; /* we're done */ if (errno != ECONNREFUSED) { clnt_perror(mclient, "mount"); goto fail; /* don't retry */ } if (!running_bg && prevt == 0) clnt_perror(mclient, "mount"); auth_destroy(mclient->cl_auth); clnt_destroy(mclient); mclient = 0; close(msock); } else { if (!running_bg && prevt == 0) clnt_pcreateerror("mount"); } prevt = t; } if (!bg) goto fail; if (!running_bg) { prev_bg_host = bb_xstrdup(hostname); if (retry > 0) retval = EX_BG; goto fail; } t = time(NULL); if (t >= timeout) goto fail; } nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; if (nfsvers == 2) { if (status.nfsv2.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv2.fhs_status)); goto fail; } memcpy(data.root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); #if NFS_MOUNT_VERSION >= 4 data.root.size = NFS_FHSIZE; memcpy(data.old_root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); #endif } else { #if NFS_MOUNT_VERSION >= 4 fhandle3 *my_fhandle; if (status.nfsv3.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv3.fhs_status)); goto fail; } my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; memset(data.old_root.data, 0, NFS_FHSIZE); memset(&data.root, 0, sizeof(data.root)); data.root.size = my_fhandle->fhandle3_len; memcpy(data.root.data, (char *) my_fhandle->fhandle3_val, my_fhandle->fhandle3_len); data.flags |= NFS_MOUNT_VER3; #endif } /* create nfs socket for kernel */ if (tcp) { if (nfs_mount_version < 3) { printf(_("NFS over TCP is not supported.\n")); goto fail; } fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { perror(_("nfs socket")); goto fail; } if (bindresvport(fsock, 0) < 0) { perror(_("nfs bindresvport")); goto fail; } if (port == 0) { server_addr.sin_port = PMAPPORT; port = pmap_getport(&server_addr, nfsprog, nfsvers, tcp ? IPPROTO_TCP : IPPROTO_UDP); if (port == 0) port = NFS_PORT; #ifdef NFS_MOUNT_DEBUG else printf(_("used portmapper to find NFS port\n")); #endif } #ifdef NFS_MOUNT_DEBUG printf(_("using port %d for nfs deamon\n"), port); #endif server_addr.sin_port = htons(port); /* * connect() the socket for kernels 1.3.10 and below only, * to avoid problems with multihomed hosts. * --Swen */ if (get_kernel_revision() <= 66314 && connect(fsock, (struct sockaddr *) &server_addr, sizeof (server_addr)) < 0) { perror(_("nfs connect")); goto fail; } /* prepare data structure for kernel */ data.fd = fsock; memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); strncpy(data.hostname, hostname, sizeof(data.hostname)); /* clean up */ auth_destroy(mclient->cl_auth); clnt_destroy(mclient); close(msock); return 0; /* abort */ fail: if (msock != -1) { if (mclient) { auth_destroy(mclient->cl_auth); clnt_destroy(mclient); } close(msock); } if (fsock != -1) close(fsock); return retval; }
/* returns an initialised client, or NULL on error */ CLIENT *create_rpc_client(struct sockaddr_in *client_sock, struct addrinfo *hints, unsigned long prognum, unsigned long version, struct timeval timeout, struct sockaddr_in src_ip) { CLIENT *client = NULL; int sock; long unsigned protocol; /* for portmapper */ char src[INET_ADDRSTRLEN]; char dst[INET_ADDRSTRLEN]; struct sockaddr_in getaddr; /* for getsockname */ socklen_t len = sizeof(getaddr); /* Even if you specify a source address the portmapper will use the default one */ /* this applies to pmap_getport or clnt*_create */ /* so use our own get_rpc_port */ /* check if we need to use the portmapper, 0 = yes */ if (client_sock->sin_port == 0) { client_sock->sin_port = htons(PMAPPORT); /* 111 */ sock = socket(AF_INET, hints->ai_socktype, 0); if (sock < 0) { perror("create_rpc_client(socket)"); return NULL; } /* set the source address if specified */ if (src_ip.sin_addr.s_addr) { /* portmapper doesn't need a reserved port */ src_ip.sin_port = 0; if (bind(sock, (struct sockaddr *) &src_ip, sizeof(src_ip)) == -1) { perror("create_rpc_client(bind)"); return NULL; } } if (connect(sock, (struct sockaddr *)client_sock, sizeof(struct sockaddr)) == 0) { /* TCP */ if (hints->ai_socktype == SOCK_STREAM) { protocol = PMAP_IPPROTO_TCP; client = clnttcp_create(client_sock, PMAPPROG, PMAPVERS, &sock, 0, 0); if (client == NULL) { clnt_pcreateerror("clnttcp_create"); } /* UDP */ } else { protocol = PMAP_IPPROTO_UDP; client = clntudp_create(client_sock, PMAPPROG, PMAPVERS, timeout, &sock); if (client == NULL) { clnt_pcreateerror("clntudp_create"); } } } else { perror("create_rpc_client(connect)"); return NULL; } if (verbose) { if (getsockname(sock, (struct sockaddr *)&getaddr, &len) == -1) { perror("create_rpc_client(getsockname)"); /* this is just verbose output so don't return an error */ } else { inet_ntop(AF_INET, (struct sockaddr_in *)&getaddr.sin_addr, src, INET_ADDRSTRLEN); //inet_ntop(AF_INET, &(((struct sockaddr_in *)&client_sock)->sin_addr), dst, INET_ADDRSTRLEN); inet_ntop(AF_INET, &(client_sock->sin_addr), dst, INET_ADDRSTRLEN); debug("portmap request = %s:%u -> %s:%u\n", src, ntohs(getaddr.sin_port), dst, ntohs(client_sock->sin_port)); } } /* query the portmapper */ client_sock->sin_port = get_rpc_port(client, prognum, version, protocol); /* close the portmapper connection */ client = destroy_rpc_client(client); /* by this point we should know which port we're talking to */ debug("portmapper = %s:%u\n", dst, ntohs(client_sock->sin_port)); } /* now make the client connection */ /* by now we should have a port defined unless the program isn't registered */ if (client_sock->sin_port) { /* Make sure and make new sockets for each new connection */ /* clnttcp_create will happily reuse open sockets */ sock = socket(AF_INET, hints->ai_socktype, 0); if (sock < 0) { perror("create_rpc_client(socket)"); return NULL; } /* always try and bind to a low port first */ /* could check for root here but there are other mechanisms for allowing processes to bind to low ports */ if (bindresvport(sock, &src_ip) == -1) { /* permission denied, ie we aren't root */ if (errno == EACCES) { /* try an ephemeral port */ src_ip.sin_port = htons(0); } else { perror("create_rpc_client(bindresvport)"); return NULL; } } /* now we're bound to a local socket, try and connect to the server */ if (connect(sock, (struct sockaddr *)client_sock, sizeof(struct sockaddr)) == 0) { /* TCP */ if (hints->ai_socktype == SOCK_STREAM) { /* TODO set recvsz and sendsz to the NFS blocksize */ client = clnttcp_create(client_sock, prognum, version, &sock, 0, 0); if (client == NULL) { clnt_pcreateerror("clnttcp_create"); } /* UDP */ } else { client = clntudp_create(client_sock, prognum, version, timeout, &sock); if (client == NULL) { clnt_pcreateerror("clntudp_create"); } } } else { perror("create_rpc_client(connect)"); return NULL; } if (verbose) { if (getsockname(sock, (struct sockaddr *)&getaddr, &len) == -1) { perror("create_rpc_client(getsockname)"); /* this is just verbose output so don't return an error */ } else { inet_ntop(AF_INET, (struct sockaddr_in *)&getaddr.sin_addr, src, INET_ADDRSTRLEN); inet_ntop(AF_INET, &(client_sock->sin_addr), dst, INET_ADDRSTRLEN); debug("Connected = %s:%u -> %s:%u\n", src, ntohs(getaddr.sin_port), dst, ntohs(client_sock->sin_port)); } } } if (client) { /* TODO check return values */ /* use AUTH_NONE authentication by default */ client->cl_auth = authnone_create(); /* set the RPC timeout */ clnt_control(client, CLSET_TIMEOUT, (char *)&timeout); /* set the socket to close when the client is destroyed */ clnt_control(client, CLSET_FD_CLOSE, NULL); } return client; }
SVCXPRT *Svcudp_bufcreate(register int sock, u_int sendsz, u_int recvsz) { bool_t madesock = FALSE; register SVCXPRT *xprt; register struct Svcudp_data *su; struct sockaddr_in addr; unsigned long len = sizeof(struct sockaddr_in); if(sock == RPC_ANYSOCK) { if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("Svcudp_create: socket creation problem"); return ((SVCXPRT *) NULL); } madesock = TRUE; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if(bindresvport(sock, &addr)) { addr.sin_port = 0; (void)bind(sock, (struct sockaddr *)&addr, len); } if(getsockname(sock, (struct sockaddr *)&addr, (socklen_t *) & len) != 0) { perror("Svcudp_create - cannot getsockname"); if(madesock) (void)close(sock); return ((SVCXPRT *) NULL); } xprt = (SVCXPRT *) Mem_Alloc(sizeof(SVCXPRT)); if(xprt == NULL) { return (NULL); } su = (struct Svcudp_data *)Mem_Alloc(sizeof(*su)); if(su == NULL) { return (NULL); } su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; if((rpc_buffer(xprt) = Mem_Alloc(su->su_iosz)) == NULL) { return (NULL); } xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); xprt->xp_p2 = (caddr_t) su; xprt->xp_verf.oa_base = su->su_verfbody; xprt->xp_ops = &Svcudp_op; xprt->xp_port = ntohs(addr.sin_port); #ifdef _FREEBSD xprt->xp_fd = sock; #else xprt->xp_sock = sock; #endif Xprt_register(xprt); return (xprt); }