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