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