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