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