acl/lib_tls/attr/attr_clnt.c
2014-11-19 00:25:21 +08:00

213 lines
5.9 KiB
C

/*++
* NAME
* attr_clnt 3
* SUMMARY
* attribute query-reply client
* SYNOPSIS
* #include <attr_clnt.h>
*
* typedef int (*ATTR_CLNT_PRINT_FN) (VSTREAM *, int, va_list);
* typedef int (*ATTR_CLNT_SCAN_FN) (VSTREAM *, int, va_list);
*
* ATTR_CLNT *attr_clnt_create(server, timeout, max_idle, max_ttl)
* const char *server;
* int timeout;
* int max_idle;
* int max_ttl;
*
* int attr_clnt_request(client,
* send_flags, send_type, send_name, ..., ATTR_TYPE_END,
* recv_flags, recv_type, recv_name, ..., ATTR_TYPE_END)
* ATTR_CLNT *client;
* int send_flags;
* int send_type;
* const char *send_name;
* int recv_flags;
* int recv_type;
* const char *recv_name;
*
* void attr_clnt_free(client)
* ATTR_CLNT *client;
*
* void attr_clnt_control(client, name, value, ... ATTR_CLNT_CTL_END)
* ATTR_CLNT *client;
* int name;
* DESCRIPTION
* This module implements a client for a simple attribute-based
* protocol. The default protocol is described in attr_scan_plain(3).
*
* attr_clnt_create() creates a client handle. See auto_clnt(3) for
* a description of the arguments.
*
* attr_clnt_request() sends the specified request attributes and
* receives a reply. The reply argument specifies a name-value table.
* The other arguments are as described in attr_print_plain(3). The
* result is the number of attributes received or -1 in case of trouble.
*
* attr_clnt_free() destroys a client handle and closes its connection.
*
* attr_clnt_control() allows the user to fine tune the behavior of
* the specified client. The arguments are a list of (name, value)
* terminated with ATTR_CLNT_CTL_END.
* The following lists the names and the types of the corresponding
* value arguments.
* .IP "ATTR_CLNT_CTL_PROTO(ATTR_CLNT_PRINT_FN, ATTR_CLNT_SCAN_FN)"
* Specifies alternatives for the attr_plain_print() and
* attr_plain_scan() functions.
* DIAGNOSTICS
* Warnings: communication failure.
* SEE ALSO
* auto_clnt(3), client endpoint management
* attr_scan_plain(3), attribute protocol
* attr_print_plain(3), attribute protocol
* LICENSE
* .ad
* .fi
* The Secure Mailer license must be distributed with this software.
* AUTHOR(S)
* Wietse Venema
* IBM T.J. Watson Research
* P.O. Box 704
* Yorktown Heights, NY 10598, USA
*--*/
#include "StdAfx.h"
#ifdef ACL_UNIX
#include <unistd.h>
#endif
#include <errno.h>
#include "attr.h"
#include "auto_clnt.h"
#include "attr_clnt.h"
/* Application-specific. */
struct ATTR_CLNT {
AUTO_CLNT *auto_clnt;
ATTR_CLNT_PRINT_FN print;
ATTR_CLNT_SCAN_FN scan;
};
/* attr_clnt_free - destroy attribute client */
void attr_clnt_free(ATTR_CLNT *client)
{
auto_clnt_free(client->auto_clnt);
acl_myfree(client);
}
/* attr_clnt_create - create attribute client */
ATTR_CLNT *attr_clnt_create(ACL_EVENT *eventp, const char *service,
int timeout, int max_idle, int max_ttl)
{
ATTR_CLNT *client;
client = (ATTR_CLNT *) acl_mymalloc(sizeof(*client));
client->auto_clnt = auto_clnt_create(eventp, service,
timeout, max_idle, max_ttl);
client->scan = attr_vscan_plain;
client->print = attr_vprint_plain;
return (client);
}
/* attr_clnt_request - send query, receive reply */
int attr_clnt_request(ATTR_CLNT *client, int send_flags,...)
{
const char *myname = "attr_clnt_request";
ACL_VSTREAM *stream;
int count = 0;
va_list ap;
int type;
int recv_flags;
int err;
int ret;
/*
* XXX If the stream is readable before we send anything, then assume the
* remote end disconnected.
*
* XXX For some reason we can't simply call the scan routine after the print
* routine, that messes up the argument list.
*/
#define SKIP_ARG(ap, type) { \
(void) va_arg(ap, char *); \
(void) va_arg(ap, type); \
}
#define SKIP_ARG2(ap, t1, t2) { \
SKIP_ARG(ap, t1); \
(void) va_arg(ap, t2); \
}
for (;;) {
errno = 0;
if ((stream = auto_clnt_access(client->auto_clnt)) != 0
&& acl_readable(ACL_VSTREAM_SOCK(stream)) == 0) {
errno = 0;
va_start(ap, send_flags);
err = (client->print(stream, send_flags, ap) == ACL_VSTREAM_EOF
|| acl_vstream_fflush(stream) == ACL_VSTREAM_EOF);
va_end(ap);
if (err == 0) {
va_start(ap, send_flags);
while ((type = va_arg(ap, int)) != ATTR_TYPE_END) {
switch (type) {
case ATTR_TYPE_STR:
SKIP_ARG(ap, char *);
break;
case ATTR_TYPE_DATA:
SKIP_ARG2(ap, ssize_t, char *);
break;
case ATTR_TYPE_INT:
SKIP_ARG(ap, int);
break;
case ATTR_TYPE_LONG:
SKIP_ARG(ap, long);
break;
case ATTR_TYPE_HASH:
(void) va_arg(ap, ACL_HTABLE *);
break;
default:
acl_msg_panic("%s: unexpected attribute type %d", myname, type);
}
}
recv_flags = va_arg(ap, int);
ret = client->scan(stream, recv_flags, ap);
va_end(ap);
if (ret > 0)
return (ret);
}
}
if (++count >= 2 || acl_msg_verbose
|| (errno && errno != EPIPE && errno != ENOENT && errno != ACL_ECONNRESET))
acl_msg_warn("%s: problem talking to server %s: %s",
myname, auto_clnt_name(client->auto_clnt), acl_last_serror());
if (count >= 2)
return (-1);
sleep(1); /* XXX make configurable */
auto_clnt_recover(client->auto_clnt);
}
}
/* attr_clnt_control - fine control */
void attr_clnt_control(ATTR_CLNT *client, int name,...)
{
const char *myname = "attr_clnt_control";
va_list ap;
for (va_start(ap, name); name != ATTR_CLNT_CTL_END; name = va_arg(ap, int)) {
switch (name) {
case ATTR_CLNT_CTL_PROTO:
client->print = va_arg(ap, ATTR_CLNT_PRINT_FN);
client->scan = va_arg(ap, ATTR_CLNT_SCAN_FN);
break;
default:
acl_msg_panic("%s: bad name %d", myname, name);
}
}
va_end(ap);
}