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.