Example 4–13 shows the server side of Example 4–12. It is called svcudp_create(). The server side uses svc_tli_create().
svc_tli_create() is used when the application needs a fine degree of control, particularly to:
Set the send and receive buffer sizes. The fd argument can be unbound when passed in. It is then bound to a given address, and the address is stored in a handle. If the bind address is set to NULL and the fd is initially unbound, it is bound to any suitable address.
Use rpcb_set() to register the service with rpcbind.
#include <stdio.h> #include <rpc/rpc.h> #include <netconfig.h> #include <netinet/in.h> SVCXPRT * svcudp_create(fd) register int fd; { struct netconfig *nconf; SVCXPRT *svc; int madefd = FALSE; int port; void *handlep; struct t_info tinfo; /* If no transports available */ if ((handlep = setnetconfig() ) == (void *) NULL) { nc_perror("server"); return((SVCXPRT *) NULL); } /* * Try all the transports until it gets one which is * connectionless, family is INET and, name is UDP */ while (nconf = getnetconfig( handlep)) { if ((nconf->nc_semantics == NC_TPI_CLTS) && (strcmp( nconf->nc_protofmly, NC_INET) == 0 )&& (strcmp( nconf->nc_proto, NC_UDP) == 0 )) break; } if (nconf == (struct netconfig *) NULL) { endnetconfig(handlep); return((SVCXPRT *) NULL); } if (fd == RPC_ANYFD) { fd = t_open(nconf->nc_device, O_RDWR, &tinfo); if (fd == -1) { (void) endnetconfig(); return((SVCXPRT *) NULL); } madefd = TRUE; } else t_getinfo(fd, &tinfo); svc = svc_tli_create(fd, nconf, (struct t_bind *) NULL, tinfo.tsdu, tinfo.tsdu); (void) endnetconfig(handlep); if (svc == (SVCXPRT *) NULL) { if (madefd) (void) t_close(fd); return((SVCXPRT *)NULL); } return (svc); }
The network selection here is accomplished similar to clntudp_create(). The file descriptor is not bound explicitly to a transport address because svc_tli_create() does that.
svcudp_create() can use an open fd. It opens one itself using the selected netconfig structure if none is provided.