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