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