Fix sample PQF
[yaz-moved-to-github.git] / comstack / xmosi.c
1 /*
2  * Copyright (c) 1995, Index Data
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: xmosi.c,v $
7  * Revision 1.17  1999-06-16 11:55:24  adam
8  * Added APDU log to client.
9  *
10  * Revision 1.16  1997/09/17 12:10:30  adam
11  * YAZ version 1.4.
12  *
13  * Revision 1.15  1997/05/14 06:53:34  adam
14  * C++ support.
15  *
16  * Revision 1.14  1996/07/26 12:34:07  quinn
17  * Porting.
18  *
19  * Revision 1.13  1996/07/06  19:58:30  quinn
20  * System headerfiles gathered in yconfig
21  *
22  * Revision 1.12  1996/05/22  08:34:44  adam
23  * Added ifdef USE_XTIMOSI; so that 'make depend' works.
24  *
25  * Revision 1.11  1996/02/23 10:00:41  quinn
26  * WAIS Work
27  *
28  * Revision 1.10  1996/02/10  12:23:13  quinn
29  * Enablie inetd operations fro TCP/IP stack
30  *
31  * Revision 1.9  1996/01/02  08:57:28  quinn
32  * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
33  *
34  * Revision 1.8  1995/11/01  13:54:29  quinn
35  * Minor adjustments
36  *
37  * Revision 1.7  1995/10/30  12:41:17  quinn
38  * Added hostname lookup for server.
39  *
40  * Revision 1.6  1995/09/29  17:12:00  quinn
41  * Smallish
42  *
43  * Revision 1.5  1995/09/28  10:24:32  quinn
44  * Windows changes
45  *
46  * Revision 1.4  1995/09/27  15:02:45  quinn
47  * Modified function heads & prototypes.
48  *
49  * Revision 1.3  1995/06/16  10:30:38  quinn
50  * Added REUSEADDR.
51  *
52  * Revision 1.2  1995/06/15  12:30:07  quinn
53  * Added @ as hostname alias for INADDR ANY.
54  *
55  * Revision 1.1  1995/06/14  09:58:20  quinn
56  * Renamed yazlib to comstack.
57  *
58  * Revision 1.15  1995/05/29  08:12:33  quinn
59  * Updates to aynch. operations.
60  *
61  * Revision 1.14  1995/05/16  09:37:31  quinn
62  * Fixed bug
63  *
64  * Revision 1.13  1995/05/16  08:51:19  quinn
65  * License, documentation, and memory fixes
66  *
67  * Revision 1.12  1995/05/02  08:53:24  quinn
68  * Trying in vain to fix comm with ISODE
69  *
70  * Revision 1.11  1995/04/21  16:32:08  quinn
71  * *** empty log message ***
72  *
73  * Revision 1.10  1995/03/27  08:36:14  quinn
74  * Some work on nonblocking operation in xmosi.c and rfct.c.
75  * Added protocol parameter to cs_create()
76  *
77  * Revision 1.9  1995/03/20  09:47:23  quinn
78  * Added server-side support to xmosi.c
79  * Fixed possible problems in rfct
80  * Other little mods
81  *
82  * Revision 1.8  1995/03/16  13:29:30  quinn
83  * Beginning to add server-side functions
84  *
85  * Revision 1.7  1995/03/14  10:28:47  quinn
86  * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
87  *
88  * Revision 1.6  1995/03/09  15:22:43  quinn
89  * Fixed two bugs in get/rcv
90  *
91  * Revision 1.5  1995/03/07  16:29:47  quinn
92  * Various fixes.
93  *
94  * Revision 1.4  1995/03/07  10:26:56  quinn
95  * Initialized type field in the comstacks.
96  *
97  * Revision 1.3  1995/03/06  16:48:03  quinn
98  * Smallish changes.
99  *
100  * Revision 1.2  1995/03/06  10:54:41  quinn
101  * Server-side functions (t_bind/t_listen/t_accept) seem to work ok, now.
102  * Nonblocking mode needs work (and testing!)
103  * Added makensap to replace function in mosiutil.c.
104  *
105  * Revision 1.1  1995/03/01  08:40:33  quinn
106  * First working version of rfct. Addressing needs work.
107  *
108  */
109
110 #ifdef USE_XTIMOSI
111 /*
112  * Glue layer for Peter Furniss' xtimosi package.
113  */
114
115 #include <fcntl.h>
116 #include <stdlib.h>
117 #include <string.h>
118 #include <assert.h>
119
120 #define YNETINCLUDE
121 #include <yconfig.h>
122
123 #include <comstack.h>
124 #include <xmosi.h>
125
126 #include <oid.h>
127
128 int mosi_connect(COMSTACK h, void *address);
129 int mosi_get(COMSTACK h, char **buf, int *bufsize);
130 int mosi_put(COMSTACK h, char *buf, int size);
131 int mosi_more(COMSTACK h) { return 0; } /* not correct */
132 int mosi_close(COMSTACK h);
133 int mosi_rcvconnect(COMSTACK h);
134 int mosi_bind(COMSTACK h, void *address, int mode);
135 int mosi_listen(COMSTACK h, char *addrp, int *addrlen);
136 COMSTACK mosi_accept(COMSTACK h);
137 char *mosi_addrstr(COMSTACK h);
138 void *mosi_straddr(COMSTACK h, const char *str);
139
140 typedef struct mosi_state
141 {
142     struct t_info info;        /* data returned by t_open */
143     struct t_call *call;
144     int hasread;               /* how many bytes read of current PDU */
145     int haswrit;               /* how many bytes have we written */
146     struct netbuf netbuf;
147 } mosi_state;
148
149 static char *oidtostr(int *o)
150 {
151     static char buf[512];
152
153     buf[0] = '\0';
154     while (*o >= 0)
155     {
156         sprintf(buf + strlen(buf), "%d", *o);
157         if (*(++o) >= 0)
158             strcat(buf, " ");
159     }
160     return buf;
161 }
162
163 static int addopt(struct netbuf *optbuf, unsigned long level, unsigned long
164     name, enum oid_proto proto, enum oid_class class, enum oid_value value)
165 {
166     int *oid;
167     oident ent;
168     char *str;
169
170     ent.proto = proto;
171     ent.oclass = class;
172     ent.value = value;
173     if (!(oid = oid_getoidbyent(&ent)))
174         return -1;
175     str = oidtostr(oid);
176     if (addoidoption(optbuf, level, name, str) < 0)
177         return -1;
178     return 0;
179 }
180
181 COMSTACK mosi_type(int s, int blocking, int protocol)
182 {
183     COMSTACK r;
184     mosi_state *state;
185     int flags = O_RDWR;
186
187     if (s >= 0)
188         return 0;
189
190     if (!(r = xmalloc(sizeof(*r))))
191         return 0;
192     if (!(state = r->cprivate = xmalloc(sizeof(*state))))
193         return 0;
194
195     state->call = 0;
196     state->hasread = 0;
197     state->haswrit = 0;
198     r->protocol = protocol;
199     r->state = CS_UNBND;
200     r->type = mosi_type;
201     r->blocking = blocking;
202     r->f_connect = mosi_connect;
203     r->f_put = mosi_put;
204     r->f_get = mosi_get;
205     r->f_close = mosi_close;
206     r->f_more = mosi_more;
207     r->f_rcvconnect = mosi_rcvconnect;
208     r->f_bind = mosi_bind;
209     r->f_listen = mosi_listen;
210     r->f_accept = mosi_accept;
211     r->f_addrstr = mosi_addrstr;
212     r->r_straddr = mosi_straddr;
213
214     if (!blocking)
215         flags |= O_NONBLOCK;
216     if ((r->iofile = u_open(CO_MOSI_NAME, flags, &state->info)) < 0)
217         return 0;
218
219     r->timeout = COMSTACK_DEFAULT_TIMEOUT;
220
221     return r;
222 }
223
224 int hex2oct(char *hex, char *oct)
225 {
226     int len = 0;
227     unsigned val;
228
229     while (sscanf(hex, "%2x", &val) == 1)
230     {
231         if (strlen(hex) < 2)
232             return -1;
233         *((unsigned char*) oct++) = (unsigned char) val;
234         len++;
235         hex += 2;
236     }
237     return len;
238 }
239
240 /*
241  * addressing specific to our hack of OSI transport. A sockaddr_in wrapped
242  * up in a t_mosiaddr in a netbuf (on a stick).
243  */
244
245 int *mosi_strtoaddr_ex(const char *str, struct netbuf *ret)
246 {
247     struct sockaddr_in *add = xmalloc(sizeof(struct sockaddr_in));
248     struct t_mosiaddr *mosiaddr = xmalloc(sizeof(struct t_mosiaddr));
249     struct hostent *hp;
250     char *p, *b, buf[512], *nsap;
251     short int port = 102;
252     unsigned long tmpadd;
253     int ll = 0;
254
255     assert(ret && add && mosiaddr);
256 #if 0
257     mosiaddr->osi_ap_inv_id = NO_INVOKEID;
258     mosiaddr->osi_ae_inv_id = NO_INVOKEID;
259 #endif
260     mosiaddr->osi_apt_len = 0;
261     mosiaddr->osi_aeq_len = 0;
262     p = (char*)MOSI_PADDR(mosiaddr);
263     *(p++) = 0; /* No presentation selector */
264     ll++;
265     *(p++) = 0; /* no session selector */
266     ll++;
267     /* do we have a transport selector? */
268     strcpy(buf, str);
269     if ((nsap = strchr(buf, '/')))
270     {
271         *(nsap++) = '\0';
272         if ((*p = hex2oct(buf, p + 1)) < 0)
273             return 0;
274         ll += *p + 1;
275         p += *p + 1;
276     }
277     else
278     {
279         nsap = buf;
280         *(p++) = 0;
281         ll++;
282     }
283     if (nsap && *nsap)
284     {
285         add->sin_family = AF_INET;
286         strcpy(buf, nsap);
287         if ((b = strchr(buf, ':')))
288         {
289             *b = 0;
290             port = atoi(b + 1);
291         }
292         add->sin_port = htons(port);
293         if (!strcmp("@", buf))
294             add->sin_addr.s_addr = INADDR_ANY;
295         else if ((hp = gethostbyname(buf)))
296             memcpy(&add->sin_addr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
297         else if ((tmpadd = inet_addr(buf)) != 0)
298             memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
299         else
300             return 0;
301         *(p++) = (char) sizeof(*add);
302         ll++;
303         memcpy(p, add, sizeof(*add));
304         ll += sizeof(*add);
305     }
306     else
307     {
308         *(p++) = 0;
309         ll++;
310     }
311     mosiaddr->osi_paddr_len = ll;
312     ret->buf = (char*)mosiaddr;
313     ret->len = ret->maxlen = 100 /* sizeof(*mosiaddr) */ ;
314
315     return 1;
316 }
317
318 struct netbuf *mosi_strtoaddr(const char *str)
319 {
320     struct netbuf *ret = xmalloc(sizeof(struct netbuf));
321
322     if (!mosi_strtoaddr_ex (str, ret))
323     {
324         xfree (ret);
325         return 0;
326     }
327     return ret;
328 }
329
330 struct netbuf *mosi_straddr(COMSTACK h, const char *str)
331 {
332     mosi_state *st = h->cprivate;
333     struct netbuf *ret = &st->netbuf;
334
335     if (!mosi_strtoaddr_ex (str, ret))
336     {
337         xfree (ret);
338         return 0;
339     }
340     return ret;
341 }
342
343 int mosi_connect(COMSTACK h, void *address)
344 {
345     struct netbuf *addr = address, *local;
346     struct t_call *snd, *rcv;
347     struct t_bind bnd;
348
349     if (!(snd = (struct t_call *) u_alloc(h->iofile, T_CALL, T_ALL)))
350         return -1;
351     if (!(rcv = (struct t_call *) u_alloc(h->iofile, T_CALL, T_ALL)))
352         return -1;
353
354     snd->udata.len = 0;
355     if (addopt(&snd->opt, ISO_APCO, AP_CNTX_NAME, h->protocol, CLASS_APPCTX,
356         VAL_BASIC_CTX) < 0)
357         return -1;
358     if (addopt(&snd->opt, ISO_APCO, AP_ABS_SYN, h->protocol, CLASS_ABSYN,
359         VAL_APDU) < 0)
360         return -1;
361     /*
362      * We don't specify record formats yet.
363      *
364      * Xtimosi adds the oid for BER as transfer syntax automatically.
365      */
366
367     bnd.qlen = 0;
368
369     if (h->state == CS_UNBND)
370     {
371         local = mosi_strtoaddr("");   /* not good in long run */
372         memcpy(&bnd.addr, local, sizeof(*local));
373         if (u_bind(h->iofile, &bnd, 0) < 0)
374             return -1;
375     }
376
377     memcpy(&snd->addr, addr, sizeof(*addr));
378     if (u_connect(h->iofile, snd, rcv) < 0)
379     {
380         if (t_errno == TNODATA)
381             return 1;
382         return -1; 
383     }
384     return 0;
385 }
386
387 int mosi_rcvconnect(COMSTACK h)
388 {
389     if (u_rcvconnect(h->iofile, 0) < 0)
390     {
391         if (t_errno == TNODATA)
392             return 1;
393         return -1;
394     }
395     return 0;
396 }
397
398 int mosi_bind(COMSTACK h, void *address, int mode)
399 {
400     int res;
401     struct t_bind bnd;
402     int one = 1;
403
404     if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
405     {
406         h->cerrno = CSYSERR;
407         return -1;
408     }
409     if (mode == CS_SERVER)
410         bnd.qlen = 3;
411     else
412         bnd.qlen = 0;
413     memcpy(&bnd.addr, address, sizeof(struct netbuf));
414     if ((res = u_bind(h->iofile, &bnd, 0)) < 0)
415         return -1;
416     h->state = CS_IDLE;
417     return 0;
418 }
419
420 int mosi_listen(COMSTACK h, char *addp, int *addrlen)
421 {
422     int res;
423     mosi_state *st = h->cprivate;
424
425     if (!(st->call = (struct t_call*) t_alloc(h->iofile, T_CALL_STR,
426          T_ALL)))
427         return -1;
428     if ((res = u_listen(h->iofile, st->call)) < 0)
429     {
430         if (t_errno == TNODATA)
431             return 1;
432         return -1;
433     }
434     h->state = CS_INCON;
435     return 0;
436 }
437
438 COMSTACK mosi_accept(COMSTACK h)
439 {
440     COMSTACK new;
441     void *local;
442     struct mosi_state *st = h->cprivate, *ns;
443     int flags = O_RDWR;
444
445     if (h->state != CS_INCON)
446     {
447         h->cerrno = CSOUTSTATE;
448         return 0;
449     }
450     if (!(new = xmalloc(sizeof(*new))))
451         return 0;
452     *new = *h;
453     if (!(new->cprivate = ns = xmalloc(sizeof(*ns))))
454         return 0;
455     *ns = *st;
456     if (!h->blocking)
457         flags |= O_NONBLOCK;
458     if ((new->iofile = u_open_r(CO_MOSI_NAME, flags, &st->info, st->call)) < 0)
459         return 0;
460     if (!(local = mosi_strtoaddr("")))
461         return 0;
462     if (mosi_bind(new, local, CS_CLIENT) < 0) /* CS_CLIENT: qlen == 0 */
463         return 0;
464     memcpy(&st->call->addr, local, sizeof(st->call->addr));
465     if (u_accept(h->iofile, new->iofile, st->call) < 0)
466     {
467         mosi_close(new);
468         return 0;
469     }
470     return new;
471 }
472
473 #define CS_MOSI_BUFCHUNK 4096
474
475 int mosi_get(COMSTACK h, char **buf, int *bufsize)
476 {
477     int flags = 0, res;
478     mosi_state *ct = h->cprivate;
479     int got;
480
481     do
482     {
483         if (!*bufsize)
484         {
485             if (!(*buf = xmalloc(*bufsize = CS_MOSI_BUFCHUNK)))
486                 return -1;
487         }
488         else if (*bufsize - ct->hasread < CS_MOSI_BUFCHUNK)
489             if (!(*buf =xrealloc(*buf, *bufsize *= 2)))
490                 return -1;
491
492         if ((res = u_rcv(h->iofile, *buf + ct->hasread, CS_MOSI_BUFCHUNK,
493             &flags)) <= 0)
494         {
495             if (t_errno == TNODATA)
496                 return 1;
497             return -1;
498         }
499         ct->hasread += res;
500     }
501     while (flags & T_MORE);
502
503     /* all done. Reset hasread */
504     got = ct->hasread;
505     ct->hasread = 0;  
506     return got;
507 }
508
509 int mosi_put(COMSTACK h, char *buf, int size)
510 {
511     mosi_state *ct = h->cprivate;
512     int res = u_snd(h->iofile, buf + ct->haswrit, size - ct->haswrit, 0);
513
514     if (res == size - ct->haswrit)
515     {
516         ct->haswrit = 0;
517         return 0;
518     }
519     else if (res < 0)
520     {
521         if (t_errno == TFLOW)
522             return 1;
523         return -1;
524     }
525     ct->haswrit += res;
526     return 1;
527 }
528
529 int mosi_close(COMSTACK h)
530 {
531     xfree(h->cprivate);
532     if (h->iofile >= 0)
533         u_close(h->iofile);
534    xfree(h);
535     return 0;
536 }    
537
538 char *mosi_addrstr(COMSTACK h)
539 {
540     return "osi:[UNIMPLEMENTED]";
541 }
542
543 #endif