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