示例: TI-RPC 顶级服务 API
此代码示例说明了用于开发 TI-RPC 服务的顶级服务 API。
服务的开发在顶层更为复杂,因为它需要开发者编写调度例程。 在此级别,当服务请求进入时,将调用分派例程。 分派例程必须收集参数并调用正确的本地过程,捕获所有错误和结果,然后将该信息返回给客户机。 编写分派函数后,只需稍作修改即可轻松复制该函数并将其用于其他服务。
顶部,中间和专家层可以使用相同的分派功能而无需修改。 在以下示例中,分派函数与此文件中的其他本地函数捆绑在一起。 在服务运行之前,需要将这两个文件编译并链接在一起。 与其他层相比,顶级的优势在于能够将 NETTYPE 指定为字符串,而不是使用网络选择 API。 调用顶级 API 后,将创建服务,将其绑定到分派函数,并向 rpcbind 服务注册。
注: 通过使用代码示例,您同意 代码许可证和免责声明信息的条款。
#include <stdio.h>
#include <netconfig.h>
#include <rpc/rpc.h>
#include <errno.h>
#include "myapp.h"
int main(int argc, char *argv[]) {
int num_svc; /* return value for the svc_create() API */
/* unregister any existing copy of this service */
/* (void)svc_unreg(program, version) */
svc_unreg(PROGNUM, VERSNUM);
/* (int)svc_create(dispatch, prognum, versnum, nettype); */
num_svc = svc_create(myapp_dispatch, PROGNUM, VERSNUM, NETTYPE);
/* check for errors calling svc_create() */
if (num_svc == 0) {
/* print error messages and exit */
fprintf(stderr, "Error calling %s.\n", "svc_create");
fprintf(stderr, "PROG: %lu\nVERS: %lu\tNET: %s\n",
PROGNUM, VERSNUM, NETTYPE);
fprintf(stderr, "errno: %d\n", errno);
return 1;
}
/* this should loop indefinitely waiting for client connections */
svc_run();
/* if we get here, svc_run() returned */
fprintf(stderr, "svc_run() returned. ERROR has occurred.\n");
fprintf(stderr, "errno: %d\n", errno);
/* clean up by unregistering. then, exit */
svc_unreg(PROGNUM, VERSNUM);
return 1;
} /* end of main() *//* This is an example of the dispatch function */#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <pwd.h>
#include <rpc/rpc.h>
#include <time.h>
#include "myapp.h"
char * myapp_get_uid(char *in) {
u_int retval; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (u_int)-1;
}
else {
retval = (u_int)(sbuf.st_uid);
}
return (char *)&retval;
}
char *myapp_get_uid_string(char *in) {
char *retval; /* return value for this procedure() */
struct passwd *pbuf; /* return value for getpwuid() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (char *)NULL;
}
else {
pbuf = (struct passwd *)getpwuid((uid_t)(sbuf.st_uid));
if (pbuf == NULL) {
retval = (char *)NULL;
}
else {
retval = (char *)(pbuf->pw_name);
}
}
return (char *)&retval;
}
char * myapp_get_size(char *in) {
int retval; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (int)-1;
}
else {
retval = (int)(sbuf.st_size);
}
return (char *)&retval;
}
char * myapp_get_mtime(char *in) {
long retval; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (long)-1;
}
else {
retval = (long)(sbuf.st_mtime);
}
return (char *)&retval;
}
char *myapp_get_mtime_string(char *in) {
char *retval; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (char *)NULL;
}
else {
retval = (char *)ctime((time_t *)&(sbuf.st_mtime));
}
return (char *)&retval;
}
char * myapp_get_codepage(char *in) {
u_short retval; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (u_short)-1;
}
else {
retval = (u_short)(sbuf.st_codepage);
}
return (char *)&retval;
}
char *myapp_get_objtype(char *in) {
char *retval; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
retval = (char *)NULL;
}
else {
retval = (char *)(sbuf.st_objtype);
}
return (char *)&retval;
}
char *myapp_get_filetype(char *in) {
char *result = NULL; /* return value for this procedure() */
struct stat sbuf; /* data storage area for stat() */
int stat_ret; /* return value for stat() */
char *file = *(char **)in; /* input value for stat() */
/* (int)stat(filename, struct stat *) */
stat_ret = stat(file, &sbuf);
if (stat_ret == -1) {
return (char *)NULL;
}
if (S_ISDIR(sbuf.st_mode)) {
result = "Directory";
}
if (S_ISREG(sbuf.st_mode)) {
result = "Regulare File";
}
if (S_ISLNK(sbuf.st_mode)) {
result = "Symbolic Link";
}
if (S_ISSOCK(sbuf.st_mode)) {
result = "Socket";
}
if (S_ISNATIVE(sbuf.st_mode)) {
result = "System i Native Object";
}
if (S_ISFIFO(sbuf.st_mode)) {
result = "FIFO";
}
if (S_ISCHR(sbuf.st_mode)) {
result = "Character Special";
}
if (S_ISBLK(sbuf.st_mode)) {
result = "Block Special";
}
return (char *)&result;
}
char * myapp_end_server(char *empty) {
/* char *empty is not used */
/* function always returns NULL */
svc_unreg(PROGNUM, VERSNUM);
return (char *)NULL;
}
void myapp_dispatch(struct svc_req *request, SVCXPRT *svc) {
union {
/* all of the procedures take a string */
/* if there were other procedures, it */
/* might look like this: */
/* int set_codepage_arg */
char * filename_arg;
} argument;
char *result; /* pointer to returned data from proc */
xdrproc_t xdr_argument; /* decodes data from client call */
xdrproc_t xdr_result; /* encodes data to return to client */
char *(*proc)(char *); /* pointer to local procedure to call */
switch (request->rq_proc) {
case NULLPROC:
/* a special case. always return void */
(void)svc_sendreply((SVCXPRT *)svc,
(xdrproc_t)xdr_void,
(char *)NULL);
return;
case GET_UID:
/* takes a string argument (filename) */
/* returns an u_int (uid of file ownder) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_u_int;
proc = (char *(*)(char *))myapp_get_uid;
break;
case GET_UID_STRING:
/* takes a string argument (filename) */
/* returns a string (owner's name in string format) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_wrapstring;
proc = (char *(*)(char *))myapp_get_uid_string;
break;
case GET_SIZE:
/* takes a string argument (filename) */
/* returns an int (size of file in bytes) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_int;
proc = (char *(*)(char *))myapp_get_size;
break;
case GET_MTIME:
/* takes a string argument (filename) */
/* returns a long (time last modified) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_long;
proc = (char *(*)(char *))myapp_get_mtime;
break;
case GET_MTIME_STRING:
/* takes a string argument (filename) */
/* returns a string (time last modified, string format) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_wrapstring;
proc = (char *(*)(char *))myapp_get_mtime_string;
break;
case GET_CODEPAGE:
/* takes a string argument (filename) */
/* returns an u_short (codepage of file) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_u_short;
proc = (char *(*)(char *))myapp_get_codepage;
break;
case GET_OBJTYPE:
/* takes a string argument (filename) */
/* returns a string (object type) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_wrapstring;
proc = (char *(*)(char *))myapp_get_objtype;
break;
case GET_FILETYPE:
/* takes a string argument (filename) */
/* returns a string (file type) */
xdr_argument = xdr_wrapstring;
xdr_result = xdr_wrapstring;
proc = (char *(*)(char *))myapp_get_filetype;
break;
case END_SERVER:
/* takes no arguments */
/* returns no data */
/* unregisters service with local rpcbind daemon */
xdr_argument = (xdrproc_t)xdr_void;
xdr_result = (xdrproc_t)xdr_void;
proc = (char *(*)(char *))myapp_end_server;
break;
default:
/* fall through case. return error to client */
svcerr_noproc(svc);
return;
} /* end switch(request->rq_proc) */
/* clear the argument */
memset((char *)&argument, (int)0, sizeof(argument));
/* decode argument from client using xdr_argument() */
if (svc_getargs(svc, xdr_argument, (char *)&argument) == FALSE) {
/* if svc_getargs() fails, return RPC_CANTDECODEARGS to client */
svcerr_decode(svc);
return;
}
/* call local procedure, passing in pointer to argument */
result = (char *)(*proc)((char *)&argument);
/* check first that result isn't NULL */
/* try to send results back to client. check for failure */
if ((result != NULL) && (svc_sendreply(svc, xdr_result, result) == FALSE))
{
/* send error message back to client */
svcerr_systemerr(svc);
}
/* free the decoded argument's space */
if (svc_freeargs(svc, xdr_argument, (char *)&argument) == FALSE) {
/* if unable to free, print error and exit */
(void)fprintf(stderr, "unable to free arguments\n");
exit(1);
}
} /* end of myapp_dispatch() */