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