2 * Copyright (C) 1995-2006, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: yaz-illclient.c,v 1.1 2007-04-16 15:33:51 heikki Exp $
8 /* NOTE - This is work in progress - not at all ready */
10 /** \file yaz-illclient.c
11 * \brief client for ILL requests (ISO 10161-1)
13 * This is a test client for handling ISO 10161-1 ILL requests.
14 * Those are not directly Z39.50, but the protocol is quite similar
15 * and yaz already provides the APDUS for it.
17 * This is not an interactive client like yaz-client, but driven by command-
18 * line arguments. Its output is a return code, and possibly some text on
21 * Exit codes (note, the program exits as soon as it finds a good reason)
23 * 1 errors in arguments
24 * 2 Internal errors in creating objects (comstack, odr...)
25 * mostly programming errors.
27 * 4 could not send request
28 * 5 No reponse received
29 * 6 Error decoding response packet
30 * 7 Server returned an error (see log or stdout)
51 #include <yaz/yaz-util.h>
52 #include <yaz/proto.h>
53 #include <yaz/comstack.h>
54 #include <yaz/tcpip.h>
60 /* A structure for storing all the arguments */
66 /* Call-back to be called for every field in the ill-request */
67 /* It can set values to any field, perhaps from the prog_args */
68 const char *get_ill_element(void *clientData, const char *element) {
69 struct prog_args *args = clientData;
71 if (!strcmp(element,"foo")) {
73 } else if (!strcmp(element,"ill,protocol-version-num")) {
75 } else if (!strcmp(element,"ill,transaction-id,initial-requester-id,person-or-institution-symbol,institution")) {
78 yaz_log(YLOG_DEBUG,"get_ill_element: '%s' -> '%s' ", element, ret );
83 /* * * * * * * * * * * * * * * * * */
84 /** \brief Parse program arguments */
85 void parseargs( int argc, char * argv[], struct prog_args *args) {
89 char *version="$Id: yaz-illclient.c,v 1.1 2007-04-16 15:33:51 heikki Exp $"; /* from cvs */
91 args->host=0; /* not known (yet) */
93 while ((ret = options("k:c:q:a:b:m:v:p:u:t:Vxd:", argv, argc, &arg)) != -2)
100 args->host = xstrdup (arg);
104 fprintf(stderr, "%s: Specify most one server address\n",
110 yaz_log_init(yaz_log_mask_str(arg), "", 0);
113 printf("%s %s",prog, version );
116 fprintf (stderr, "Usage: %s "
126 /* * * * * * * * * * * */
127 /** \brief Validate the arguments make sense */
128 void validateargs( struct prog_args *args) {
130 fprintf(stderr, "Specify a connection address, "
131 "as in 'bagel.indexdata.dk:210' \n");
137 /* * * * * * * * * * * * * * * */
138 /** \brief Connect to the target */
139 COMSTACK connect_to( char *hostaddr ){
141 void *server_address_ip;
144 yaz_log(YLOG_DEBUG,"Connecting to '%s'", hostaddr);
145 stack = cs_create_host(hostaddr, 1, &server_address_ip );
147 yaz_log(YLOG_FATAL,"Error in creating the comstack '%s' ",
152 yaz_log(YLOG_DEBUG,"Created stack ok ");
154 status = cs_connect(stack, server_address_ip);
156 yaz_log(YLOG_FATAL|YLOG_ERRNO,"Can not connect '%s' ",
160 yaz_log(YLOG_DEBUG,"Connected OK to '%s'", hostaddr);
164 /* * * * * * * * * * * * * * * */
165 ILL_APDU *createrequest( struct prog_args *args, ODR out_odr) {
166 struct ill_get_ctl ctl;
171 ctl.clientData = & args;
172 ctl.f = get_ill_element;
173 apdu = odr_malloc( out_odr, sizeof(*apdu) );
174 apdu->which=ILL_APDU_ILL_Request;
175 req = ill_get_ILLRequest(&ctl, "ill", 0);
176 apdu->u.illRequest=req;
178 yaz_log(YLOG_FATAL,"Could not create ill request");
183 } /* createrequest */
186 /* * * * * * * * * * * * * * * */
187 /** \brief Send the request */
188 void sendrequest(ILL_APDU *apdu, ODR out_odr, COMSTACK stack ) {
192 if (!ill_APDU (out_odr, &apdu, 0, 0)) {
193 yaz_log(YLOG_FATAL,"ill_Apdu failed");
196 buf_out = odr_getbuf(out_odr, &len_out, 0);
198 yaz_log(YLOG_DEBUG,"Request PDU Dump");
199 odr_dumpBER(yaz_log_file(), buf_out, len_out);
202 yaz_log(YLOG_FATAL,"Encoding failed. Len=%d", len_out);
203 odr_perror(out_odr, "encoding failed");
206 yaz_log(YLOG_DEBUG,"About to send the request. Len=%d", len_out);
207 res = cs_put(stack, buf_out, len_out);
209 yaz_log(YLOG_FATAL,"Could not send packet. code %d",res );
214 /* * * * * * * * * * * * * * * */
215 /** \brief Get a response */
216 ILL_APDU *getresponse( COMSTACK stack, ODR in_odr ){
221 yaz_log(YLOG_DEBUG,"About to wait for a response");
222 res = cs_get(stack, &buf_in, &len_in);
223 yaz_log(YLOG_DEBUG,"Got a response of %d bytes at %x. res=%d", len_in,buf_in, res);
225 yaz_log(YLOG_FATAL,"Could not receive packet. code %d",res );
226 yaz_log(YLOG_DEBUG,"%02x %02x %02x %02x %02x %02x %02x %02x ...",
227 buf_in[0], buf_in[1], buf_in[2], buf_in[3],
228 buf_in[4], buf_in[5], buf_in[6], buf_in[7] );
229 yaz_log(YLOG_DEBUG,"PDU Dump:");
230 odr_dumpBER(yaz_log_file(), buf_in, len_in);
233 odr_setbuf(in_odr, buf_in, res, 0);
234 if (!ill_APDU (in_odr, &resp, 0, 0))
237 int err = odr_geterrorx(in_odr, &x);
239 const char *element = odr_getelement(in_odr);
240 sprintf(msg, "ODR code %d:%d element=%-20s",
241 err, x, element ? element : "<unknown>");
242 yaz_log(YLOG_FATAL,"Error decoding incoming packet: %s",msg);
243 yaz_log(YLOG_DEBUG,"%02x %02x %02x %02x %02x %02x %02x %02x ...",
244 buf_in[0], buf_in[1], buf_in[2], buf_in[3],
245 buf_in[4], buf_in[5], buf_in[6], buf_in[7] );
246 yaz_log(YLOG_DEBUG,"PDU Dump:");
247 odr_dumpBER(yaz_log_file(), buf_in, len_in);
248 yaz_log(YLOG_FATAL,"Error decoding incoming packet: %s",msg);
255 /** \brief Dump a apdu */
256 void dumpapdu( ILL_APDU *apdu) {
257 ODR print_odr = odr_createmem(ODR_PRINT);
258 ill_APDU (print_odr, &apdu, 0, 0);
259 odr_destroy(print_odr);
262 /** \brief Check apdu type and extract the status_or_error */
263 ILL_Status_Or_Error_Report *getstaterr( ILL_APDU *resp, ODR in_odr ) {
264 if (resp->which != ILL_APDU_Status_Or_Error_Report ) {
265 const char *element = odr_getelement(in_odr);
268 printf("Server returned wrong packet type: %d\n", resp->which);
269 yaz_log(YLOG_FATAL,"Server returned a (%d) and "
270 "not a 'Status_Or_Error_Report' (%d) ",
271 resp->which, ILL_APDU_Status_Or_Error_Report);
274 return resp->u.Status_Or_Error_Report;
277 /** \brief Return a printable string from an ILL_String */
278 char *getillstring( ILL_String *s) {
279 if (s->which == ILL_String_GeneralString )
280 return s->u.GeneralString;
281 else if (s->which == ILL_String_EDIFACTString )
282 return s->u.EDIFACTString;
284 yaz_log(YLOG_FATAL,"Invalid ILL_String ");
289 /** \brief Check if the status was an error packet */
290 /* The presence of an error_report indicates it was an error */
291 /* Then the problem is to find the right message. We dig around */
292 /* until we find the first message, print that, and exit the program */
293 void checkerr( ILL_Status_Or_Error_Report *staterr ) {
294 yaz_log(YLOG_DEBUG, "err= %x ",staterr->error_report );
295 if (staterr->error_report) {
296 ILL_Error_Report *err= staterr->error_report;
297 if ( err->user_error_report) {
298 ILL_User_Error_Report *uerr= err->user_error_report;
299 switch( uerr->which ) {
300 case ILL_User_Error_Report_already_forwarded:
301 printf("Already forwarded: \n");
303 case ILL_User_Error_Report_intermediary_problem:
304 printf("Intermediary problem: %d\n",
305 uerr->u.intermediary_problem);
307 case ILL_User_Error_Report_security_problem:
308 printf("Security problem: %s\n",
309 getillstring(uerr->u.security_problem));
311 case ILL_User_Error_Report_unable_to_perform:
312 printf("Unable to perform: %d\n",
313 uerr->u.unable_to_perform);
316 printf("Unknown problem");
320 if ( err->provider_error_report) {
321 ILL_Provider_Error_Report *perr= err->provider_error_report;
322 switch( perr->which ) {
323 case ILL_Provider_Error_Report_general_problem:
324 printf("General Problem: %d\n",
325 perr->u.general_problem);
327 case ILL_Provider_Error_Report_transaction_id_problem:
328 printf("Transaction Id Problem: %d\n",
329 perr->u.general_problem);
331 case ILL_Provider_Error_Report_state_transition_prohibited:
332 printf("State Transition prohibited \n");
339 printf("%s", getillstring(staterr->note));
341 printf("Unknown error type");
348 /* * * * * * * * * * * * * * * */
350 /** \brief Main program
354 * Establish connection
362 int main (int argc, char * argv[]) {
363 struct prog_args args;
365 ODR out_odr = odr_createmem(ODR_ENCODE);
366 ODR in_odr = odr_createmem(ODR_DECODE);
369 ILL_Status_Or_Error_Report *staterr;
371 parseargs( argc, argv, &args);
373 stack = connect_to(args.host);
374 apdu = createrequest(&args, out_odr);
375 sendrequest(apdu, out_odr, stack );
376 resp = getresponse(stack, in_odr );
379 staterr=getstaterr(resp, in_odr);
383 printf ("Ok\n"); /* while debugging */
390 * indent-tabs-mode: nil
392 * vim: shiftwidth=4 tabstop=8 expandtab