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