Exemple #1
0
/*
 * Returns 1, 0 or -1
 * In nonblocking mode, you must call again with same buffer while
 * return value is 1.
 */
static int unix_put(COMSTACK h, char *buf, int size)
{
    int res;
    struct unix_state *state = (struct unix_state *)h->cprivate;

    TRC(fprintf(stderr, "unix_put: size=%d\n", size));
    h->io_pending = 0;
    h->event = CS_DATA;
    if (state->towrite < 0)
    {
        state->towrite = size;
        state->written = 0;
    }
    else if (state->towrite != size)
    {
        h->cerrno = CSWRONGBUF;
        return -1;
    }
    while (state->towrite > state->written)
    {
        if ((res =
             send(h->iofile, buf + state->written, size -
                  state->written,
#ifdef MSG_NOSIGNAL
                  MSG_NOSIGNAL
#else
                  0
#endif
                 )) < 0)
        {
            if (
                yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
                || yaz_errno() == EAGAIN
#endif
#endif
                )
            {
                TRC(fprintf(stderr, "  Flow control stop\n"));
                h->io_pending = CS_WANT_WRITE;
                return 1;
            }
            h->cerrno = CSYSERR;
            return -1;
        }
        state->written += res;
        TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
                    res, state->written, size));
    }
    state->towrite = state->written = -1;
    TRC(fprintf(stderr, "  Ok\n"));
    return 0;
}
Exemple #2
0
/*
 * connect(2) will block (sometimes) - nothing we can do short of doing
 * weird things like spawning subprocesses or threading or some weird junk
 * like that.
 */
static int unix_connect(COMSTACK h, void *address)
{
    struct sockaddr_un *add = (struct sockaddr_un *)address;
    int r;
    int i;

    TRC(fprintf(stderr, "unix_connect\n"));
    h->io_pending = 0;
    if (h->state != CS_ST_UNBND)
    {
        h->cerrno = CSOUTSTATE;
        return -1;
    }
    for (i = 0; i<3; i++)
    {
        r = connect(h->iofile, (struct sockaddr *) add, SUN_LEN(add));
        if (r < 0 && yaz_errno() == EAGAIN)
        {
#if HAVE_USLEEP
            usleep(i*10000+1000); /* 1ms, 11ms, 21ms */
#else
            sleep(1);
#endif
            continue;
        }
        else
            break;
    }
    if (r < 0)
    {
        if (yaz_errno() == EINPROGRESS)
        {
            h->event = CS_CONNECT;
            h->state = CS_ST_CONNECTING;
            h->io_pending = CS_WANT_WRITE;
            return 1;
        }
        h->cerrno = CSYSERR;
        return -1;
    }
    h->event = CS_CONNECT;
    h->state = CS_ST_CONNECTING;

    return unix_rcvconnect (h);
}
Exemple #3
0
void yaz_strerror(char *buf, size_t bufsz)
{
#ifdef WIN32
    DWORD err;
#endif
    char *cp;
#ifdef WIN32
    err = GetLastError();
    if (err)
    {
        FormatMessage(
                FORMAT_MESSAGE_FROM_SYSTEM,
                NULL,
                err,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default lang */
                (LPTSTR) buf,
                bufsz-1,
                NULL);
    }
    else
        *buf = '\0';
#else
/* UNIX */
#if HAVE_STRERROR_R
    *buf = '\0';
    strerror_r(errno, buf, bufsz);
    /* if buffer is unset - use strerror anyway (GLIBC bug) */
    if (*buf == '\0')
        strcpy(buf, strerror(yaz_errno()));
#else
    strcpy(buf, strerror(yaz_errno()));
#endif
/* UNIX */
#endif
    if ((cp = strrchr(buf, '\n')))
        *cp = '\0';
    if ((cp = strrchr(buf, '\r')))
        *cp = '\0';
}
Exemple #4
0
static int unix_listen(COMSTACK h, char *raddr, int *addrlen,
                    int (*check_ip)(void *cd, const char *a, int len, int t),
                    void *cd)
{
    struct sockaddr_un addr;
    YAZ_SOCKLEN_T len = sizeof(addr);

    TRC(fprintf(stderr, "unix_listen pid=%d\n", getpid()));
    if (h->state != CS_ST_IDLE)
    {
        h->cerrno = CSOUTSTATE;
        return -1;
    }
    h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
    if (h->newfd < 0)
    {
        if (
            yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
            || yaz_errno() == EAGAIN
#endif
#endif
            )
            h->cerrno = CSNODATA;
        else
            h->cerrno = CSYSERR;
        return -1;
    }
    if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_un))
        memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_un));
    else if (addrlen)
        *addrlen = 0;
    h->state = CS_ST_INCON;
    return 0;
}
Exemple #5
0
/*
 * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
 * 0=connection closed.
 */
static int unix_get(COMSTACK h, char **buf, int *bufsize)
{
    unix_state *sp = (unix_state *)h->cprivate;
    char *tmpc;
    int tmpi, berlen, rest, req, tomove;
    int hasread = 0, res;

    TRC(fprintf(stderr, "unix_get: bufsize=%d\n", *bufsize));
    if (sp->altlen) /* switch buffers */
    {
        TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
                    (unsigned) sp->altbuf));
        tmpc = *buf;
        tmpi = *bufsize;
        *buf = sp->altbuf;
        *bufsize = sp->altsize;
        hasread = sp->altlen;
        sp->altlen = 0;
        sp->altbuf = tmpc;
        sp->altsize = tmpi;
    }
    h->io_pending = 0;
    while (!(berlen = (*sp->complete)(*buf, hasread)))
    {
        if (!*bufsize)
        {
            if (!(*buf = (char *)xmalloc(*bufsize = CS_UNIX_BUFCHUNK)))
                return -1;
        }
        else if (*bufsize - hasread < CS_UNIX_BUFCHUNK)
            if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
                return -1;
        res = recv(h->iofile, *buf + hasread, CS_UNIX_BUFCHUNK, 0);
        TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
        if (res < 0)
        {
            if (yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
                || yaz_errno() == EAGAIN
#endif
#endif
                || yaz_errno() == EINPROGRESS
                )
            {
                h->io_pending = CS_WANT_READ;
                break;
            }
            else if (yaz_errno() == 0)
                continue;
            else
                return -1;
        }
        else if (!res)
            return hasread;
        hasread += res;
    }
    TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
                  hasread, berlen));
    /* move surplus buffer (or everything if we didn't get a BER rec.) */
    if (hasread > berlen)
    {
        tomove = req = hasread - berlen;
        rest = tomove % CS_UNIX_BUFCHUNK;
        if (rest)
            req += CS_UNIX_BUFCHUNK - rest;
        if (!sp->altbuf)
        {
            if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
                return -1;
        } else if (sp->altsize < req)
            if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
                return -1;
        TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
                    (unsigned) sp->altbuf));
        memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
    }
    if (berlen < CS_UNIX_BUFCHUNK - 1)
        *(*buf + berlen) = '\0';
    return berlen ? berlen : 1;
}
Exemple #6
0
static int unix_bind(COMSTACK h, void *address, int mode)
{
    unix_state *sp = (unix_state *)h->cprivate;
    struct sockaddr *addr = (struct sockaddr *)address;
    const char * path = ((struct sockaddr_un *)addr)->sun_path;
    struct stat stat_buf;

    TRC (fprintf (stderr, "unix_bind\n"));

    if(stat(path, &stat_buf) != -1) {
        struct sockaddr_un socket_unix;
        int socket_out = -1;

        if((stat_buf.st_mode&S_IFMT) != S_IFSOCK) { /* used to be S_ISSOCK */
            h->cerrno = CSYSERR;
            yaz_set_errno(EEXIST); /* Not a socket (File exists) */
            return -1;
        }
        if((socket_out = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
            h->cerrno = CSYSERR;
            return -1;
        }
        socket_unix.sun_family = AF_UNIX;
        strncpy(socket_unix.sun_path, path, sizeof(socket_unix.sun_path)-1);
        socket_unix.sun_path[sizeof(socket_unix.sun_path)-1] = 0;
        if(connect(socket_out, (struct sockaddr *) &socket_unix, SUN_LEN(&socket_unix)) < 0) {
            if(yaz_errno() == ECONNREFUSED) {
                TRC (fprintf (stderr, "Socket exists but nobody is listening\n"));
            } else {
                h->cerrno = CSYSERR;
                return -1;
            }
        } else {
            close(socket_out);
            h->cerrno = CSYSERR;
            yaz_set_errno(EADDRINUSE);
            return -1;
        }
        unlink(path);
    }

    if (bind(h->iofile, (struct sockaddr *) addr, SUN_LEN((struct sockaddr_un *)addr)))
    {
        h->cerrno = CSYSERR;
        return -1;
    }
    if (chown(path, sp->uid, sp->gid))
    {
        h->cerrno = CSYSERR;
        return -1;
    }
    if (chmod(path, sp->umask != -1 ? sp->umask : 0666))
    {
        h->cerrno = CSYSERR;
        return -1;
    }
    if (mode == CS_SERVER && listen(h->iofile, 100) < 0)
    {
        h->cerrno = CSYSERR;
        return -1;
    }
    h->state = CS_ST_IDLE;
    h->event = CS_LISTEN;
    return 0;
}
Exemple #7
0
Fichier : siconv.c Projet : nla/yaz
size_t yaz_iconv(yaz_iconv_t cd, char **inbuf, size_t *inbytesleft,
                 char **outbuf, size_t *outbytesleft)
{
    char *inbuf0 = 0;
    size_t r = 0;

#if HAVE_ICONV_H
    if (cd->iconv_cd != (iconv_t) (-1))
    {
        size_t r =
            iconv(cd->iconv_cd, inbuf, inbytesleft, outbuf, outbytesleft);
        if (r == (size_t)(-1))
        {
            switch (yaz_errno())
            {
            case E2BIG:
                cd->my_errno = YAZ_ICONV_E2BIG;
                break;
            case EINVAL:
                cd->my_errno = YAZ_ICONV_EINVAL;
                break;
            case EILSEQ:
                cd->my_errno = YAZ_ICONV_EILSEQ;
                break;
            default:
                cd->my_errno = YAZ_ICONV_UNKNOWN;
            }
        }
        return r;
    }
#endif

    if (inbuf)
        inbuf0 = *inbuf;

    if (cd->init_flag)
    {
        cd->my_errno = YAZ_ICONV_UNKNOWN;

        if (cd->encoder.init_handle)
            (*cd->encoder.init_handle)(&cd->encoder);

        cd->unget_x = 0;
        cd->no_read_x = 0;

        if (cd->decoder.init_handle)
        {
            size_t no_read = 0;
            size_t r = (cd->decoder.init_handle)(
                cd, &cd->decoder,
                inbuf ? (unsigned char *) *inbuf : 0,
                inbytesleft ? *inbytesleft : 0,
                &no_read);
            if (r)
            {
                if (cd->my_errno == YAZ_ICONV_EINVAL)
                    return r;
                cd->init_flag = 0;
                return r;
            }
            if (inbytesleft)
                *inbytesleft -= no_read;
            if (inbuf)
                *inbuf += no_read;
        }
    }
    cd->init_flag = 0;

    if (!inbuf || !*inbuf)
    {
        if (outbuf && *outbuf)
        {
            if (cd->unget_x)
                r = (*cd->encoder.write_handle)(cd, &cd->encoder,
                                                cd->unget_x, outbuf, outbytesleft);
            if (cd->encoder.flush_handle)
                r = (*cd->encoder.flush_handle)(cd, &cd->encoder,
                                                outbuf, outbytesleft);
        }
        if (r == 0)
            cd->init_flag = 1;
        cd->unget_x = 0;
        return r;
    }
    while (1)
    {
        unsigned long x;
        size_t no_read;

        if (cd->unget_x)
        {
            x = cd->unget_x;
            no_read = cd->no_read_x;
        }
        else
        {
            if (*inbytesleft == 0)
            {
                r = *inbuf - inbuf0;
                break;
            }
            x = (*cd->decoder.read_handle)(
                cd, &cd->decoder,
                (unsigned char *) *inbuf, *inbytesleft, &no_read);
            if (no_read == 0)
            {
                r = (size_t)(-1);
                break;
            }
        }
        if (x)
        {
            r = (*cd->encoder.write_handle)(cd, &cd->encoder,
                                            x, outbuf, outbytesleft);
            if (r)
            {
                /* unable to write it. save it because read_handle cannot
                   rewind .. */
                if (cd->my_errno == YAZ_ICONV_E2BIG)
                {
                    cd->unget_x = x;
                    cd->no_read_x = no_read;
                    break;
                }
            }
            cd->unget_x = 0;
        }
        *inbytesleft -= no_read;
        (*inbuf) += no_read;
    }
    return r;
}
Exemple #8
0
Fichier : eventl.c Projet : nla/yaz
int iochan_event_loop(IOCHAN *iochans)
{
    do /* loop as long as there are active associations to process */
    {
        IOCHAN p, nextp;
        int i;
        int tv_sec = 3600;
        int no_fds = 0;
        struct yaz_poll_fd *fds = 0;
        int res;
        time_t now = time(0);

        for (p = *iochans; p; p = p->next)
            no_fds++;
        fds = (struct yaz_poll_fd *) xmalloc(no_fds * sizeof(*fds));
        for (i = 0, p = *iochans; p; p = p->next, i++)
        {
            time_t w, ftime;
            enum yaz_poll_mask input_mask = yaz_poll_none;
            yaz_log(log_level, "fd=%d flags=%d force_event=%d",
                    p->fd, p->flags, p->force_event);
            if (p->force_event)
                tv_sec = 0;          /* polling select */
            if (p->flags & EVENT_INPUT)
                yaz_poll_add(input_mask, yaz_poll_read);
            if (p->flags & EVENT_OUTPUT)
                yaz_poll_add(input_mask, yaz_poll_write);
            if (p->flags & EVENT_EXCEPT)
                yaz_poll_add(input_mask, yaz_poll_except);
            if (p->max_idle && p->last_event)
            {
                ftime = p->last_event + p->max_idle;
                if (ftime < now)
                    w = p->max_idle;
                else
                    w = ftime - now;
                /* tv_sec will be minimum wait.. */
                if (w < tv_sec)
                    tv_sec = (int) w; /* can hold it because w < tv_sec */
            }
            fds[i].fd = p->fd;
            fds[i].input_mask = input_mask;
        }
        res = yaz_poll(fds, no_fds, tv_sec, 0);
        if (res < 0)
        {
            if (yaz_errno() == EINTR)
            {
                xfree(fds);
                continue;
            }
            else
            {
                yaz_log(YLOG_WARN|YLOG_ERRNO, "yaz_poll");
                xfree(fds);
                continue;
            }
        }
        now = time(0);
        for (i = 0, p = *iochans; p; p = p->next, i++)
        {
            int force_event = p->force_event;
            enum yaz_poll_mask output_mask = fds[i].output_mask;

            p->force_event = 0;
            if (!p->destroyed && ((output_mask & yaz_poll_read) ||
                                  force_event == EVENT_INPUT))
            {
                p->last_event = now;
                (*p->fun)(p, EVENT_INPUT);
            }
            if (!p->destroyed && ((output_mask & yaz_poll_write) ||
                                  force_event == EVENT_OUTPUT))
            {
                p->last_event = now;
                (*p->fun)(p, EVENT_OUTPUT);
            }
            if (!p->destroyed && ((output_mask & yaz_poll_except) ||
                force_event == EVENT_EXCEPT))
            {
                p->last_event = now;
                (*p->fun)(p, EVENT_EXCEPT);
            }
            if (!p->destroyed && ((p->max_idle && now - p->last_event >=
                p->max_idle) || force_event == EVENT_TIMEOUT))
            {
                p->last_event = now;
                (*p->fun)(p, EVENT_TIMEOUT);
            }
        }
        xfree(fds);
        for (p = *iochans; p; p = nextp)
        {
            nextp = p->next;

            if (p->destroyed)
            {
                IOCHAN tmp = p, pr;

                /* We need to inform the threadlist that this channel has been destroyed */
                statserv_remove(p);

                /* Now reset the pointers */
                if (p == *iochans)
                    *iochans = p->next;
                else
                {
                    for (pr = *iochans; pr; pr = pr->next)
                        if (pr->next == p)
                            break;
                    assert(pr); /* grave error if it weren't there */
                    pr->next = p->next;
                }
                if (nextp == p)
                    nextp = p->next;
                xfree(tmp);
            }
        }
    }
    while (*iochans);
    return 0;
}
Exemple #9
0
static int statserv_sc_main(yaz_sc_t s, int argc, char **argv)
{
    char sep;
#ifdef WIN32
    /* We need to initialize the thread list */
    ThreadList_Initialize();
/* WIN32 */
#endif


#ifdef WIN32
    sep = '\\';
#else
    sep = '/';
#endif
    if ((me = strrchr(argv[0], sep)))
        me++; /* get the basename */
    else
        me = argv[0];
    programname = argv[0];

    if (control_block.options_func(argc, argv))
        return 1;

    xml_config_open();
    
    xml_config_bend_start();

#ifdef WIN32
    xml_config_add_listeners();

    yaz_log(log_server, "Starting server %s", me);
    if (!pListener && *control_block.default_listen)
        add_listener(control_block.default_listen, 0);
#else
/* UNIX */
    if (control_block.inetd)
        inetd_connection(control_block.default_proto);
    else
    {
        static int hand[2];
        if (control_block.background)
        {
            /* create pipe so that parent waits until child has created
               PID (or failed) */
            if (pipe(hand) < 0)
            {
                yaz_log(YLOG_FATAL|YLOG_ERRNO, "pipe");
                return 1;
            }
            switch (fork())
            {
            case 0: 
                break;
            case -1:
                return 1;
            default:
                close(hand[1]);
                while(1)
                {
                    char dummy[1];
                    int res = read(hand[0], dummy, 1);
                    if (res < 0 && yaz_errno() != EINTR)
                    {
                        yaz_log(YLOG_FATAL|YLOG_ERRNO, "read fork handshake");
                        break;
                    }
                    else if (res >= 0)
                        break;
                }
                close(hand[0]);
                _exit(0);
            }
            /* child */
            close(hand[0]);
            if (setsid() < 0)
                return 1;
            
            close(0);
            close(1);
            close(2);
            open("/dev/null", O_RDWR);
            if (dup(0) == -1)
                return 1;
            if (dup(0) == -1)
                return 1;
        }
        xml_config_add_listeners();

        if (!pListener && *control_block.default_listen)
            add_listener(control_block.default_listen, 0);
        
        if (!pListener)
            return 1;

        if (*control_block.pid_fname)
        {
            FILE *f = fopen(control_block.pid_fname, "w");
            if (!f)
            {
                yaz_log(YLOG_FATAL|YLOG_ERRNO, "Couldn't create %s", 
                        control_block.pid_fname);
                exit(0);
            }
            fprintf(f, "%ld", (long) getpid());
            fclose(f);
        }
        
        if (control_block.background)
            close(hand[1]);


        yaz_log(log_server, "Starting server %s pid=%ld", programname, 
                (long) getpid());
#if 0
        sigset_t sigs_to_block;
        
        sigemptyset(&sigs_to_block);
        sigaddset(&sigs_to_block, SIGTERM);
        pthread_sigmask(SIG_BLOCK, &sigs_to_block, 0);
        /* missing... */
#endif
        if (control_block.dynamic)
            signal(SIGCHLD, catchchld);
    }
    signal(SIGPIPE, SIG_IGN);
    signal(SIGTERM, sigterm);
    if (*control_block.setuid)
    {
        struct passwd *pw;
        
        if (!(pw = getpwnam(control_block.setuid)))
        {
            yaz_log(YLOG_FATAL, "%s: Unknown user", control_block.setuid);
            return(1);
        }
        if (setuid(pw->pw_uid) < 0)
        {
            yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid");
            exit(1);
        }
    }
/* UNIX */
#endif
    if (pListener == NULL)
        return 1;
    if (s)
        yaz_sc_running(s);
    yaz_log(YLOG_DEBUG, "Entering event loop.");
    return iochan_event_loop(&pListener);
}