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