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