455 lines
14 KiB
HTML
455 lines
14 KiB
HTML
|
<?xml version="1.0" encoding="UTF-8"?>
|
||
|
<!DOCTYPE html
|
||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
|
<html lang="en-us" xml:lang="en-us">
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
<meta name="security" content="public" />
|
||
|
<meta name="Robots" content="index,follow" />
|
||
|
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))' />
|
||
|
<meta name="DC.Type" content="reference" />
|
||
|
<meta name="DC.Title" content="Example: TI-RPC top-level service API" />
|
||
|
<meta name="abstract" content="This code example illustrates a top-level service API used in developing TI-RPC services." />
|
||
|
<meta name="description" content="This code example illustrates a top-level service API used in developing TI-RPC services." />
|
||
|
<meta name="DC.Relation" scheme="URI" content="rzahpservicecode.htm" />
|
||
|
<meta name="copyright" content="(C) Copyright IBM Corporation 1998, 2006" />
|
||
|
<meta name="DC.Rights.Owner" content="(C) Copyright IBM Corporation 1998, 2006" />
|
||
|
<meta name="DC.Format" content="XHTML" />
|
||
|
<meta name="DC.Identifier" content="rzahptopservice" />
|
||
|
<meta name="DC.Language" content="en-us" />
|
||
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
||
|
<!-- US Government Users Restricted Rights -->
|
||
|
<!-- Use, duplication or disclosure restricted by -->
|
||
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
||
|
<link rel="stylesheet" type="text/css" href="./ibmdita.css" />
|
||
|
<link rel="stylesheet" type="text/css" href="./ic.css" />
|
||
|
<title>Example: TI-RPC top-level service API</title>
|
||
|
</head>
|
||
|
<body id="rzahptopservice"><a name="rzahptopservice"><!-- --></a>
|
||
|
<!-- Java sync-link --><script language="Javascript" src="../rzahg/synch.js" type="text/javascript"></script>
|
||
|
<h1 class="topictitle1">Example: TI-RPC top-level service API</h1>
|
||
|
<div><p>This code example illustrates a top-level service API used in developing
|
||
|
TI-RPC services.</p>
|
||
|
<div class="section"><p>The development of a service is more complicated at the top level,
|
||
|
because it requires the developer to write a dispatch routine. At this level,
|
||
|
when a service request comes in, a dispatch routine is called. The dispatch
|
||
|
routine must collect the arguments and call the correct local procedure, catch
|
||
|
all errors and results, and return that information to the client. After dispatch
|
||
|
function is written, it can be readily copied and used in other services with
|
||
|
only slight modifications.</p>
|
||
|
<p>The top, intermediate, and
|
||
|
expert layers can use the same dispatch function without modification. In
|
||
|
the following example, the dispatch function is bundled with the other local
|
||
|
functions in this file. Both files need to be compiled and linked together
|
||
|
before the service runs. The advantage of the top level over the other layers
|
||
|
is the ability to specify the NETTYPE as a string, instead of using the network
|
||
|
selection APIs. After calling the top-level API, the service
|
||
|
is created, bound to the dispatch function, and registered with the rpcbind
|
||
|
service.</p>
|
||
|
<div class="note"><span class="notetitle">Note:</span> By using the code examples, you agree to the terms of the <a href="codedisclaimer.htm">Code license and disclaimer information</a>.</div>
|
||
|
<pre>#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() */</pre>
|
||
|
<pre>/* This is an example of the dispatch function */</pre>
|
||
|
<pre>#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 = "AS/400 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() */</pre>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div>
|
||
|
<div class="familylinks">
|
||
|
<div class="parentlink"><strong>Parent topic:</strong> <a href="rzahpservicecode.htm" title="Transport independent remote procedure call (TI-RPC) programming provides an effective method for developing distributed client-server based applications on i5/OS.">Examples: Develop service applications based on TI-RPC code</a></div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</body>
|
||
|
</html>
|