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