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