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