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