1/*++ 2/* NAME 3/* attr_clnt 3 4/* SUMMARY 5/* attribute query-reply client 6/* SYNOPSIS 7/* #include <attr_clnt.h> 8/* 9/* typedef int (*ATTR_CLNT_PRINT_FN) (VSTREAM *, int, va_list); 10/* typedef int (*ATTR_CLNT_SCAN_FN) (VSTREAM *, int, va_list); 11/* 12/* ATTR_CLNT *attr_clnt_create(server, timeout, max_idle, max_ttl) 13/* const char *server; 14/* int timeout; 15/* int max_idle; 16/* int max_ttl; 17/* 18/* int attr_clnt_request(client, 19/* send_flags, send_type, send_name, ..., ATTR_TYPE_END, 20/* recv_flags, recv_type, recv_name, ..., ATTR_TYPE_END) 21/* ATTR_CLNT *client; 22/* int send_flags; 23/* int send_type; 24/* const char *send_name; 25/* int recv_flags; 26/* int recv_type; 27/* const char *recv_name; 28/* 29/* void attr_clnt_free(client) 30/* ATTR_CLNT *client; 31/* 32/* void attr_clnt_control(client, name, value, ... ATTR_CLNT_CTL_END) 33/* ATTR_CLNT *client; 34/* int name; 35/* DESCRIPTION 36/* This module implements a client for a simple attribute-based 37/* protocol. The default protocol is described in attr_scan_plain(3). 38/* 39/* attr_clnt_create() creates a client handle. See auto_clnt(3) for 40/* a description of the arguments. 41/* 42/* attr_clnt_request() sends the specified request attributes and 43/* receives a reply. The reply argument specifies a name-value table. 44/* The other arguments are as described in attr_print_plain(3). The 45/* result is the number of attributes received or -1 in case of trouble. 46/* 47/* attr_clnt_free() destroys a client handle and closes its connection. 48/* 49/* attr_clnt_control() allows the user to fine tune the behavior of 50/* the specified client. The arguments are a list of (name, value) 51/* terminated with ATTR_CLNT_CTL_END. 52/* The following lists the names and the types of the corresponding 53/* value arguments. 54/* .IP "ATTR_CLNT_CTL_PROTO(ATTR_CLNT_PRINT_FN, ATTR_CLNT_SCAN_FN)" 55/* Specifies alternatives for the attr_plain_print() and 56/* attr_plain_scan() functions. 57/* DIAGNOSTICS 58/* Warnings: communication failure. 59/* SEE ALSO 60/* auto_clnt(3), client endpoint management 61/* attr_scan_plain(3), attribute protocol 62/* attr_print_plain(3), attribute protocol 63/* LICENSE 64/* .ad 65/* .fi 66/* The Secure Mailer license must be distributed with this software. 67/* AUTHOR(S) 68/* Wietse Venema 69/* IBM T.J. Watson Research 70/* P.O. Box 704 71/* Yorktown Heights, NY 10598, USA 72/*--*/ 73 74/* System library. */ 75 76#include <sys_defs.h> 77#include <unistd.h> 78#include <errno.h> 79 80/* Utility library. */ 81 82#include <msg.h> 83#include <mymalloc.h> 84#include <vstream.h> 85#include <htable.h> 86#include <attr.h> 87#include <iostuff.h> 88#include <compat_va_copy.h> 89#include <auto_clnt.h> 90#include <attr_clnt.h> 91 92/* Application-specific. */ 93 94struct ATTR_CLNT { 95 AUTO_CLNT *auto_clnt; 96 ATTR_CLNT_PRINT_FN print; 97 ATTR_CLNT_SCAN_FN scan; 98}; 99 100/* attr_clnt_free - destroy attribute client */ 101 102void attr_clnt_free(ATTR_CLNT *client) 103{ 104 auto_clnt_free(client->auto_clnt); 105 myfree((char *) client); 106} 107 108/* attr_clnt_create - create attribute client */ 109 110ATTR_CLNT *attr_clnt_create(const char *service, int timeout, 111 int max_idle, int max_ttl) 112{ 113 ATTR_CLNT *client; 114 115 client = (ATTR_CLNT *) mymalloc(sizeof(*client)); 116 client->auto_clnt = auto_clnt_create(service, timeout, max_idle, max_ttl); 117 client->scan = attr_vscan_plain; 118 client->print = attr_vprint_plain; 119 return (client); 120} 121 122/* attr_clnt_request - send query, receive reply */ 123 124int attr_clnt_request(ATTR_CLNT *client, int send_flags,...) 125{ 126 const char *myname = "attr_clnt_request"; 127 VSTREAM *stream; 128 int count = 0; 129 va_list saved_ap; 130 va_list ap; 131 int type; 132 int recv_flags; 133 int err; 134 int ret; 135 136 /* 137 * XXX If the stream is readable before we send anything, then assume the 138 * remote end disconnected. 139 * 140 * XXX For some reason we can't simply call the scan routine after the print 141 * routine, that messes up the argument list. 142 */ 143#define SKIP_ARG(ap, type) { \ 144 (void) va_arg(ap, char *); \ 145 (void) va_arg(ap, type); \ 146 } 147#define SKIP_ARG2(ap, t1, t2) { \ 148 SKIP_ARG(ap, t1); \ 149 (void) va_arg(ap, t2); \ 150 } 151 152 /* Finalize argument lists before returning. */ 153 va_start(saved_ap, send_flags); 154 for (;;) { 155 errno = 0; 156 if ((stream = auto_clnt_access(client->auto_clnt)) != 0 157 && readable(vstream_fileno(stream)) == 0) { 158 errno = 0; 159 VA_COPY(ap, saved_ap); 160 err = (client->print(stream, send_flags, ap) != 0 161 || vstream_fflush(stream) != 0); 162 va_end(ap); 163 if (err == 0) { 164 VA_COPY(ap, saved_ap); 165 while ((type = va_arg(ap, int)) != ATTR_TYPE_END) { 166 switch (type) { 167 case ATTR_TYPE_STR: 168 SKIP_ARG(ap, char *); 169 break; 170 case ATTR_TYPE_DATA: 171 SKIP_ARG2(ap, ssize_t, char *); 172 break; 173 case ATTR_TYPE_INT: 174 SKIP_ARG(ap, int); 175 break; 176 case ATTR_TYPE_LONG: 177 SKIP_ARG(ap, long); 178 break; 179 case ATTR_TYPE_HASH: 180 (void) va_arg(ap, HTABLE *); 181 break; 182 default: 183 msg_panic("%s: unexpected attribute type %d", 184 myname, type); 185 } 186 } 187 recv_flags = va_arg(ap, int); 188 ret = client->scan(stream, recv_flags, ap); 189 va_end(ap); 190 /* Finalize argument lists before returning. */ 191 if (ret > 0) 192 break; 193 } 194 } 195 if (++count >= 2 196 || msg_verbose 197 || (errno && errno != EPIPE && errno != ENOENT && errno != ECONNRESET)) 198 msg_warn("problem talking to server %s: %m", 199 auto_clnt_name(client->auto_clnt)); 200 /* Finalize argument lists before returning. */ 201 if (count >= 2) { 202 ret = -1; 203 break; 204 } 205 sleep(1); /* XXX make configurable */ 206 auto_clnt_recover(client->auto_clnt); 207 } 208 /* Finalize argument lists before returning. */ 209 va_end(saved_ap); 210 return (ret); 211} 212 213/* attr_clnt_control - fine control */ 214 215void attr_clnt_control(ATTR_CLNT *client, int name,...) 216{ 217 const char *myname = "attr_clnt_control"; 218 va_list ap; 219 220 for (va_start(ap, name); name != ATTR_CLNT_CTL_END; name = va_arg(ap, int)) { 221 switch (name) { 222 case ATTR_CLNT_CTL_PROTO: 223 client->print = va_arg(ap, ATTR_CLNT_PRINT_FN); 224 client->scan = va_arg(ap, ATTR_CLNT_SCAN_FN); 225 break; 226 default: 227 msg_panic("%s: bad name %d", myname, name); 228 } 229 } 230 va_end(ap); 231} 232