Fix warnings
[yaz-moved-to-github.git] / comstack / unix.c
1 /*
2  * Copyright (c) 1995-2002, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: unix.c,v 1.2 2002-06-18 21:30:38 adam Exp $
6  * UNIX socket COMSTACK. By Morten Bøgeskov.
7  */
8 #ifndef WIN32
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <signal.h>
17
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/un.h>
21
22 #include <yaz/comstack.h>
23 #include <yaz/unix.h>
24 #include <yaz/log.h>
25
26 /* Chas added the following, so we get the definition of completeBER */
27 #include <yaz/odr.h>
28
29 int unix_close(COMSTACK h);
30 int unix_put(COMSTACK h, char *buf, int size);
31 int unix_get(COMSTACK h, char **buf, int *bufsize);
32 int unix_connect(COMSTACK h, void *address);
33 int unix_more(COMSTACK h);
34 int unix_rcvconnect(COMSTACK h);
35 int unix_bind(COMSTACK h, void *address, int mode);
36 int unix_listen(COMSTACK h, char *raddr, int *addrlen,
37                 int (*check_ip)(void *cd, const char *a, int len, int type),
38                 void *cd);
39 int static unix_set_blocking(COMSTACK p, int blocking);
40
41
42 COMSTACK unix_accept(COMSTACK h);
43 char *unix_addrstr(COMSTACK h);
44 void *unix_straddr(COMSTACK h, const char *str);
45
46 #if 0
47 #define TRC(x) x
48 #else
49 #define TRC(X)
50 #endif
51
52 /* this state is used for both SSL and straight TCP/IP */
53 typedef struct unix_state
54 {
55     char *altbuf; /* alternate buffer for surplus data */
56     int altsize;  /* size as xmalloced */
57     int altlen;   /* length of data or 0 if none */
58
59     int written;  /* -1 if we aren't writing */
60     int towrite;  /* to verify against user input */
61     int (*complete)(const unsigned char *buf, int len); /* length/comple. */
62     struct sockaddr_un addr;  /* returned by cs_straddr */
63     char buf[128]; /* returned by cs_addrstr */
64 } unix_state;
65
66 static int unix_init (void)
67 {
68     return 1;
69 }
70
71 /*
72  * This function is always called through the cs_create() macro.
73  * s >= 0: socket has already been established for us.
74  */
75 COMSTACK unix_type(int s, int blocking, int protocol, void *vp)
76 {
77     COMSTACK p;
78     unix_state *state;
79     int new_socket;
80
81     if (!unix_init ())
82         return 0;
83     if (s < 0)
84     {
85         if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
86             return 0;
87         new_socket = 1;
88     }
89     else
90         new_socket = 0;
91     if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
92         return 0;
93     if (!(state = (struct unix_state *)(p->cprivate =
94                                         xmalloc(sizeof(unix_state)))))
95         return 0;
96
97     if (!(p->blocking = blocking))
98     {
99         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
100             return 0;
101 #ifndef MSG_NOSIGNAL
102         signal (SIGPIPE, SIG_IGN);
103 #endif
104     }
105
106     p->io_pending = 0;
107     p->iofile = s;
108     p->type = unix_type;
109     p->protocol = (enum oid_proto) protocol;
110
111     p->f_connect = unix_connect;
112     p->f_rcvconnect = unix_rcvconnect;
113     p->f_get = unix_get;
114     p->f_put = unix_put;
115     p->f_close = unix_close;
116     p->f_more = unix_more;
117     p->f_bind = unix_bind;
118     p->f_listen = unix_listen;
119     p->f_accept = unix_accept;
120     p->f_addrstr = unix_addrstr;
121     p->f_straddr = unix_straddr;
122     p->f_set_blocking = unix_set_blocking;
123
124     p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
125     p->event = CS_NONE;
126     p->cerrno = 0;
127     p->stackerr = 0;
128
129     state->altbuf = 0;
130     state->altsize = state->altlen = 0;
131     state->towrite = state->written = -1;
132     if (protocol == PROTO_WAIS)
133         state->complete = completeWAIS;
134     else
135         state->complete = completeBER;
136
137     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
138     TRC(fprintf(stderr, "Created new UNIX comstack\n"));
139
140     return p;
141 }
142
143
144 int unix_strtoaddr_ex(const char *str, struct sockaddr_un *add)
145 {
146     if (!unix_init ())
147         return 0;
148     TRC(fprintf(stderr, "unix_strtoaddress: %s\n", str ? str : "NULL"));
149     add->sun_family = AF_UNIX;
150     strncpy(add->sun_path, str, sizeof(add->sun_path));
151     return 1;
152 }
153
154 void *unix_straddr(COMSTACK h, const char *str)
155 {
156     unix_state *sp = (unix_state *)h->cprivate;
157
158     TRC(fprintf(stderr, "unix_straddr: %s\n", str ? str : "NULL"));
159
160     if (!unix_strtoaddr_ex (str, &sp->addr))
161         return 0;
162     return &sp->addr;
163 }
164
165 struct sockaddr_un *unix_strtoaddr(const char *str)
166 {
167     static struct sockaddr_un add;
168
169     TRC(fprintf(stderr, "unix_strtoaddr: %s\n", str ? str : "NULL"));
170
171     if (!unix_strtoaddr_ex (str, &add))
172         return 0;
173     return &add;
174 }
175
176 int unix_more(COMSTACK h)
177 {
178     unix_state *sp = (unix_state *)h->cprivate;
179
180     return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
181                                          sp->altlen);
182 }
183
184 /*
185  * connect(2) will block (sometimes) - nothing we can do short of doing
186  * weird things like spawning subprocesses or threading or some weird junk
187  * like that.
188  */
189 int unix_connect(COMSTACK h, void *address)
190 {
191     struct sockaddr_un *add = (struct sockaddr_un *)address;
192     int r;
193
194     TRC(fprintf(stderr, "unix_connect\n"));
195     h->io_pending = 0;
196     if (h->state != CS_ST_UNBND)
197     {
198         h->cerrno = CSOUTSTATE;
199         return -1;
200     }
201     r = connect(h->iofile, (struct sockaddr *) add, SUN_LEN(add));
202     if (r < 0)
203     {
204         if (errno == EINPROGRESS)
205         {
206             h->event = CS_CONNECT;
207             h->state = CS_ST_CONNECTING;
208             h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
209             return 1;
210         }
211         h->cerrno = CSYSERR;
212         return -1;
213     }
214     h->event = CS_CONNECT;
215     h->state = CS_ST_CONNECTING;
216
217     return unix_rcvconnect (h);
218 }
219
220 /*
221  * nop
222  */
223 int unix_rcvconnect(COMSTACK h)
224 {
225     TRC(fprintf(stderr, "unix_rcvconnect\n"));
226
227     if (h->state == CS_ST_DATAXFER)
228         return 0;
229     if (h->state != CS_ST_CONNECTING)
230     {
231         h->cerrno = CSOUTSTATE;
232         return -1;
233     }
234     h->event = CS_DATA;
235     h->state = CS_ST_DATAXFER;
236     return 0;
237 }
238
239 #define CERTF "ztest.pem"
240 #define KEYF "ztest.pem"
241
242 int unix_bind(COMSTACK h, void *address, int mode)
243 {
244     struct sockaddr *addr = (struct sockaddr *)address;
245     const char * path = ((struct sockaddr_un *)addr)->sun_path;
246     struct stat stat_buf;
247
248     TRC (fprintf (stderr, "unix_bind\n"));
249
250     if(stat(path, &stat_buf) != -1) {
251         struct sockaddr_un socket_unix;
252         int socket_out = -1;
253         if(! S_ISSOCK(stat_buf.st_mode)) {
254             h->cerrno = CSYSERR;
255             errno = EEXIST; /* Not a socket (File exists) */
256             return -1;
257         }
258         if((socket_out = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
259             h->cerrno = CSYSERR;
260             return -1;
261         }
262         socket_unix.sun_family = AF_UNIX;
263         strncpy(socket_unix.sun_path, path, sizeof(socket_unix.sun_path));
264         if(connect(socket_out, (struct sockaddr *) &socket_unix, SUN_LEN(&socket_unix)) < 0) {
265             if(errno == ECONNREFUSED) {
266                 TRC (fprintf (stderr, "Socket exists but nobody is listening\n"));
267             } else {
268                 h->cerrno = CSYSERR;
269                 return -1;
270             }
271         } else {
272             close(socket_out);
273             h->cerrno = CSYSERR;
274             errno = EADDRINUSE;
275             return -1;
276         }
277         unlink(path);
278     }
279
280     if (bind(h->iofile, (struct sockaddr *) addr, SUN_LEN((struct sockaddr_un *)addr)))
281     {
282         h->cerrno = CSYSERR;
283         return -1;
284     }
285     if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
286     {
287         h->cerrno = CSYSERR;
288         return -1;
289     }
290     h->state = CS_ST_IDLE;
291     h->event = CS_LISTEN;
292     return 0;
293 }
294
295 int unix_listen(COMSTACK h, char *raddr, int *addrlen,
296                 int (*check_ip)(void *cd, const char *a, int len, int t),
297                 void *cd)
298 {
299     struct sockaddr_un addr;
300 #ifdef __cplusplus
301     socklen_t len = SUN_LEN(&addr);
302 #else
303     int len = SUN_LEN(&addr);
304 #endif
305
306     TRC(fprintf(stderr, "unix_listen pid=%d\n", getpid()));
307     if (h->state != CS_ST_IDLE)
308     {
309         h->cerrno = CSOUTSTATE;
310         return -1;
311     }
312     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
313     if (h->newfd < 0)
314     {
315         if (
316             errno == EWOULDBLOCK
317 #ifdef EAGAIN
318 #if EAGAIN != EWOULDBLOCK
319             || errno == EAGAIN
320 #endif
321 #endif
322             )
323             h->cerrno = CSNODATA;
324         else
325             h->cerrno = CSYSERR;
326         return -1;
327     }
328     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_un))
329         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_un));
330     else if (addrlen)
331         *addrlen = 0;
332     h->state = CS_ST_INCON;
333     return 0;
334 }
335
336 COMSTACK unix_accept(COMSTACK h)
337 {
338     COMSTACK cnew;
339     unix_state *state, *st = (unix_state *)h->cprivate;
340
341     TRC(fprintf(stderr, "unix_accept\n"));
342     if (h->state == CS_ST_INCON)
343     {
344         if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
345         {
346             h->cerrno = CSYSERR;
347             close(h->newfd);
348             h->newfd = -1;
349             return 0;
350         }
351         memcpy(cnew, h, sizeof(*h));
352         cnew->iofile = h->newfd;
353         cnew->io_pending = 0;
354         if (!(state = (unix_state *)
355               (cnew->cprivate = xmalloc(sizeof(unix_state)))))
356         {
357             h->cerrno = CSYSERR;
358             if (h->newfd != -1)
359             {
360                 close(h->newfd);
361                 h->newfd = -1;
362             }
363             return 0;
364         }
365         if (!cnew->blocking &&
366             (!cnew->blocking && fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
367             )
368         {
369             h->cerrno = CSYSERR;
370             if (h->newfd != -1)
371             {
372                 close(h->newfd);
373                 h->newfd = -1;
374             }
375             xfree (cnew);
376             xfree (state);
377             return 0;
378         }
379         h->newfd = -1;
380         state->altbuf = 0;
381         state->altsize = state->altlen = 0;
382         state->towrite = state->written = -1;
383         state->complete = st->complete;
384         cnew->state = CS_ST_ACCEPT;
385         cnew->event = CS_NONE;
386         h->state = CS_ST_IDLE;
387
388         h = cnew;
389     }
390     if (h->state == CS_ST_ACCEPT)
391     {
392     }
393     else
394     {
395         h->cerrno = CSOUTSTATE;
396         return 0;
397     }
398     h->io_pending = 0;
399     h->state = CS_ST_DATAXFER;
400     h->event = CS_DATA;
401     return h;
402 }
403
404 #define CS_UNIX_BUFCHUNK 4096
405
406 /*
407  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
408  * 0=connection closed.
409  */
410 int unix_get(COMSTACK h, char **buf, int *bufsize)
411 {
412     unix_state *sp = (unix_state *)h->cprivate;
413     char *tmpc;
414     int tmpi, berlen, rest, req, tomove;
415     int hasread = 0, res;
416
417     TRC(fprintf(stderr, "unix_get: bufsize=%d\n", *bufsize));
418     if (sp->altlen) /* switch buffers */
419     {
420         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
421                     (unsigned) sp->altbuf));
422         tmpc = *buf;
423         tmpi = *bufsize;
424         *buf = sp->altbuf;
425         *bufsize = sp->altsize;
426         hasread = sp->altlen;
427         sp->altlen = 0;
428         sp->altbuf = tmpc;
429         sp->altsize = tmpi;
430     }
431     h->io_pending = 0;
432     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
433     {
434         if (!*bufsize)
435         {
436             if (!(*buf = (char *)xmalloc(*bufsize = CS_UNIX_BUFCHUNK)))
437                 return -1;
438         }
439         else if (*bufsize - hasread < CS_UNIX_BUFCHUNK)
440             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
441                 return -1;
442         res = recv(h->iofile, *buf + hasread, CS_UNIX_BUFCHUNK, 0);
443         TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
444         if (res < 0)
445         {
446             if (errno == EWOULDBLOCK
447 #ifdef EAGAIN
448 #if EAGAIN != EWOULDBLOCK
449                 || errno == EAGAIN
450 #endif
451 #endif
452                 || errno == EINPROGRESS
453                 )
454             {
455                 h->io_pending = CS_WANT_READ;
456                 break;
457             }
458             else if (errno == 0)
459                 continue;
460             else
461                 return -1;
462         }
463         else if (!res)
464             return 0;
465         hasread += res;
466     }
467     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
468                   hasread, berlen));
469     /* move surplus buffer (or everything if we didn't get a BER rec.) */
470     if (hasread > berlen)
471     {
472         tomove = req = hasread - berlen;
473         rest = tomove % CS_UNIX_BUFCHUNK;
474         if (rest)
475             req += CS_UNIX_BUFCHUNK - rest;
476         if (!sp->altbuf)
477         {
478             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
479                 return -1;
480         } else if (sp->altsize < req)
481             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
482                 return -1;
483         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
484                     (unsigned) sp->altbuf));
485         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
486     }
487     if (berlen < CS_UNIX_BUFCHUNK - 1)
488         *(*buf + berlen) = '\0';
489     return berlen ? berlen : 1;
490 }
491
492
493
494 /*
495  * Returns 1, 0 or -1
496  * In nonblocking mode, you must call again with same buffer while
497  * return value is 1.
498  */
499 int unix_put(COMSTACK h, char *buf, int size)
500 {
501     int res;
502     struct unix_state *state = (struct unix_state *)h->cprivate;
503
504     TRC(fprintf(stderr, "unix_put: size=%d\n", size));
505     h->io_pending = 0;
506     h->event = CS_DATA;
507     if (state->towrite < 0)
508     {
509         state->towrite = size;
510         state->written = 0;
511     }
512     else if (state->towrite != size)
513     {
514         h->cerrno = CSWRONGBUF;
515         return -1;
516     }
517     while (state->towrite > state->written)
518     {
519         if ((res =
520              send(h->iofile, buf + state->written, size -
521                   state->written,
522 #ifdef MSG_NOSIGNAL
523                   MSG_NOSIGNAL
524 #else
525                   0
526 #endif
527                  )) < 0)
528         {
529             if (
530                 errno == EWOULDBLOCK
531 #ifdef EAGAIN
532 #if EAGAIN != EWOULDBLOCK
533                 || errno == EAGAIN
534 #endif
535 #endif
536                 )
537             {
538                 TRC(fprintf(stderr, "  Flow control stop\n"));
539                 h->io_pending = CS_WANT_WRITE;
540                 return 1;
541             }
542             h->cerrno = CSYSERR;
543             return -1;
544         }
545         state->written += res;
546         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
547                     res, state->written, size));
548     }
549     state->towrite = state->written = -1;
550     TRC(fprintf(stderr, "  Ok\n"));
551     return 0;
552 }
553
554
555
556 int unix_close(COMSTACK h)
557 {
558     unix_state *sp = (struct unix_state *)h->cprivate;
559
560     TRC(fprintf(stderr, "unix_close\n"));
561     if (h->iofile != -1)
562     {
563         close(h->iofile);
564     }
565     if (sp->altbuf)
566         xfree(sp->altbuf);
567     xfree(sp);
568     xfree(h);
569     return 0;
570 }
571
572 char *unix_addrstr(COMSTACK h)
573 {
574     unix_state *sp = (struct unix_state *)h->cprivate;
575     char *buf = sp->buf;
576     sprintf(buf, "unix:%s", sp->addr.sun_path);
577     return buf;
578 }
579
580 int static unix_set_blocking(COMSTACK p, int blocking)
581 {
582     unsigned long flag;
583
584     if (p->blocking == blocking)
585         return 1;
586     flag = fcntl(p->iofile, F_GETFL, 0);
587     if(!blocking)
588         flag = flag & ~O_NONBLOCK;
589     else
590         flag = flag | O_NONBLOCK;
591     if (fcntl(p->iofile, F_SETFL, flag) < 0)
592         return 0;
593     p->blocking = blocking;
594     return 1;
595 }
596 #endif