Пример #1
0
/* Accept a new command connection */
static void http_accept(IOCHAN i, int event)
{
    struct sockaddr_in addr;
    int fd = iochan_getfd(i);
    socklen_t len;
    int s;
    IOCHAN c;
    struct http_channel *ch;
    struct conf_server *server = iochan_getdata(i);

    len = sizeof addr;
    if ((s = accept(fd, (struct sockaddr *) &addr, &len)) < 0)
    {
        yaz_log(YLOG_WARN|YLOG_ERRNO, "accept");
        return;
    }
    enable_nonblock(s);

    yaz_log(YLOG_DEBUG, "New command connection");
    c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT, "http_session_socket");
    
    ch = http_channel_create(server->http_server, inet_ntoa(addr.sin_addr),
                             server);
    ch->iochan = c;
    iochan_setdata(c, ch);
    iochan_add(server->iochan_man, c);
}
Пример #2
0
static void connection_handler(IOCHAN iochan, int event)
{
    struct connection *co = iochan_getdata(iochan);
    struct client *cl;
    struct host *host = co->host;

    yaz_mutex_enter(host->mutex);
    cl = co->client;
    if (!cl) 
    {
        /* no client associated with it.. We are probably getting
           a closed connection from the target.. Or, perhaps, an unexpected
           package.. We will just close the connection */
        yaz_log(YLOG_LOG, "timeout connection %p event=%d", co, event);
        remove_connection_from_host(co);
        yaz_mutex_leave(host->mutex);
        connection_destroy(co);
    }
    else if (event & EVENT_TIMEOUT)
    {
        if (co->state == Conn_Connecting)
        {
            yaz_log(YLOG_WARN, "%p connect timeout %s", co, client_get_id(cl));

            client_set_state(cl, Client_Error);
            remove_connection_from_host(co);
            yaz_mutex_leave(host->mutex);
            connection_destroy(co);
        }
        else
        {
            yaz_log(YLOG_LOG,  "%p Connection idle timeout %s", co, client_get_id(cl));
            remove_connection_from_host(co);
            yaz_mutex_leave(host->mutex);
            connection_destroy(co);
        }
    }
    else
    {
        yaz_mutex_leave(host->mutex);

        client_lock(cl);
        non_block_events(co);

        ZOOM_connection_fire_event_socket(co->link, event);
        
        non_block_events(co);
        client_unlock(cl);

        if (co->link)
        {
            iochan_setflags(iochan, ZOOM_connection_get_mask(co->link));
            iochan_setfd(iochan, ZOOM_connection_get_socket(co->link));
        }
    }
}
Пример #3
0
void iochan_handler(struct iochan *i, int event)
{
    sel_thread_t p = iochan_getdata(i);

    if (event & EVENT_INPUT)
    {
        struct work *w = sel_thread_result(p);
        w->host->ipport = w->ipport;
        connect_resolver_host(w->host, w->iochan_man);
        xfree(w);
    }
}
Пример #4
0
// Cleanup channel
static void http_channel_destroy(IOCHAN i)
{
    struct http_channel *s = iochan_getdata(i);
    http_server_t http_server;

    if (s->proxy)
    {
        if (s->proxy->iochan)
        {
#ifdef WIN32
            closesocket(iochan_getfd(s->proxy->iochan));
#else
            close(iochan_getfd(s->proxy->iochan));
#endif
            iochan_destroy(s->proxy->iochan);
        }
        http_buf_destroy_queue(s->http_server, s->proxy->oqueue);
        xfree(s->proxy);
    }
    http_buf_destroy_queue(s->http_server, s->iqueue);
    http_buf_destroy_queue(s->http_server, s->oqueue);
    http_fire_observers(s);
    http_destroy_observers(s);

    http_server = s->http_server; /* save it for destroy (decref) */

    http_server_destroy(http_server);

#ifdef WIN32
    closesocket(iochan_getfd(i));
#else
    close(iochan_getfd(i));
#endif
    iochan_destroy(i);
    nmem_destroy(s->nmem);
    wrbuf_destroy(s->wrbuf);
    xfree(s);
}
Пример #5
0
void iochan_handler(struct iochan *i, int event)
{
    static int number = 0;
    sel_thread_t p = iochan_getdata(i);

    if (event & EVENT_INPUT)
    {
        struct my_work_data *work;

        work = sel_thread_result(p);

        YAZ_CHECK(work);
        if (work)
        {
            YAZ_CHECK_EQ(work->x * 2, work->y);
            /* stop work after a couple of iterations */
            if (work->x > 10)
                iochan_destroy(i);

            xfree(work);
        }

    }
    if (event & EVENT_TIMEOUT)
    {
        struct my_work_data *work;

        work = xmalloc(sizeof(*work));
        work->x = number;
        sel_thread_add(p, work);

        work = xmalloc(sizeof(*work));
        work->x = number+1;
        sel_thread_add(p, work);

        number += 10;
    }
}
Пример #6
0
static void http_io(IOCHAN i, int event)
{
    struct http_channel *hc = iochan_getdata(i);
    while (event)
    {
        if (event == EVENT_INPUT)
        {
            int res, reqlen;
            struct http_buf *htbuf;
            
            htbuf = http_buf_create(hc->http_server);
            res = recv(iochan_getfd(i), htbuf->buf, HTTP_BUF_SIZE -1, 0);
            if (res == -1 && errno == EAGAIN)
            {
                http_buf_destroy(hc->http_server, htbuf);
                return;
            }
            if (res <= 0)
            {
#if HAVE_SYS_TIME_H
                if (hc->http_server->record_file)
                {
                    struct timeval tv;
                    gettimeofday(&tv, 0);
                    fprintf(hc->http_server->record_file, "%lld %lld %lld 0\n",
                            (long long) tv.tv_sec, (long long) tv.tv_usec,
                            (long long) iochan_getfd(i));
                }
#endif
                http_buf_destroy(hc->http_server, htbuf);
                fflush(hc->http_server->record_file);
                http_channel_destroy(i);
                return;
            }
            htbuf->buf[res] = '\0';
            htbuf->len = res;
            http_buf_enqueue(&hc->iqueue, htbuf);

            while (1)
            {
                if (hc->state == Http_Busy)
                    return;
                reqlen = request_check(hc->iqueue);
                if (reqlen <= 2)
                    return;
                // we have a complete HTTP request
                nmem_reset(hc->nmem);
#if HAVE_SYS_TIME_H
                if (hc->http_server->record_file)
                {
                    struct timeval tv;
                    int sz = 0;
                    struct http_buf *hb;
                    for (hb = hc->iqueue; hb; hb = hb->next)
                        sz += hb->len;
                    gettimeofday(&tv, 0);
                    fprintf(hc->http_server->record_file, "%lld %lld %lld %d\n",
                            (long long) tv.tv_sec, (long long) tv.tv_usec,
                            (long long) iochan_getfd(i), sz);
                    for (hb = hc->iqueue; hb; hb = hb->next)
                        fwrite(hb->buf, 1, hb->len, hc->http_server->record_file);
                }
 #endif
                if (!(hc->request = http_parse_request(hc, &hc->iqueue, reqlen)))
                {
                    yaz_log(YLOG_WARN, "Failed to parse request");
                    http_error(hc, 400, "Bad Request");
                    return;
                }
                hc->response = 0;
                yaz_log(YLOG_LOG, "Request: %s %s%s%s", hc->request->method,
                        hc->request->path,
                        *hc->request->search ? "?" : "",
                        hc->request->search);
                if (hc->request->content_buf)
                    yaz_log(YLOG_LOG, "%s", hc->request->content_buf);
                if (http_weshouldproxy(hc->request))
                    http_proxy(hc->request);
                else
                {
                    // Execute our business logic!
                    hc->state = Http_Busy;
                    http_command(hc);
                }
            }
        }
        else if (event == EVENT_OUTPUT)
        {
            event = 0;
            if (hc->oqueue)
            {
                struct http_buf *wb = hc->oqueue;
                int res;
                res = send(iochan_getfd(hc->iochan),
                           wb->buf + wb->offset, wb->len, 0);
                if (res <= 0)
                {
                    yaz_log(YLOG_WARN|YLOG_ERRNO, "write");
                    http_channel_destroy(i);
                    return;
                }
                if (res == wb->len)
                {
                    hc->oqueue = hc->oqueue->next;
                    http_buf_destroy(hc->http_server, wb);
                }
                else
                {
                    wb->len -= res;
                    wb->offset += res;
                }
                if (!hc->oqueue)
                {
                    if (!hc->keep_alive)
                    {
                        http_channel_destroy(i);
                        return;
                    }
                    else
                    {
                        iochan_clearflag(i, EVENT_OUTPUT);
                        if (hc->iqueue)
                            event = EVENT_INPUT;
                    }
                }
            }
            if (!hc->oqueue && hc->proxy && !hc->proxy->iochan) 
                http_channel_destroy(i); // Server closed; we're done
        }
        else
        {
            yaz_log(YLOG_WARN, "Unexpected event on connection");
            http_channel_destroy(i);
            event = 0;
        }
    }
}
Пример #7
0
// Handles I/O on a client connection to a backend web server (proxy mode)
static void proxy_io(IOCHAN pi, int event)
{
    struct http_proxy *pc = iochan_getdata(pi);
    struct http_channel *hc = pc->channel;

    switch (event)
    {
        int res;
        struct http_buf *htbuf;

        case EVENT_INPUT:
            htbuf = http_buf_create(hc->http_server);
            res = recv(iochan_getfd(pi), htbuf->buf, HTTP_BUF_SIZE -1, 0);
            if (res == 0 || (res < 0 && !is_inprogress()))
            {
                if (hc->oqueue)
                {
                    yaz_log(YLOG_WARN, "Proxy read came up short");
                    // Close channel and alert client HTTP channel that we're gone
                    http_buf_destroy(hc->http_server, htbuf);
#ifdef WIN32
                    closesocket(iochan_getfd(pi));
#else
                    close(iochan_getfd(pi));
#endif
                    iochan_destroy(pi);
                    pc->iochan = 0;
                }
                else
                {
                    http_channel_destroy(hc->iochan);
                    return;
                }
            }
            else
            {
                htbuf->buf[res] = '\0';
                htbuf->offset = 0;
                htbuf->len = res;
                // Write any remaining payload
                if (htbuf->len - htbuf->offset > 0)
                    http_buf_enqueue(&hc->oqueue, htbuf);
            }
            iochan_setflag(hc->iochan, EVENT_OUTPUT);
            break;
        case EVENT_OUTPUT:
            if (!(htbuf = pc->oqueue))
            {
                iochan_clearflag(pi, EVENT_OUTPUT);
                return;
            }
            res = send(iochan_getfd(pi), htbuf->buf + htbuf->offset, htbuf->len, 0);
            if (res <= 0)
            {
                yaz_log(YLOG_WARN|YLOG_ERRNO, "write");
                http_channel_destroy(hc->iochan);
                return;
            }
            if (res == htbuf->len)
            { 
                struct http_buf *np = htbuf->next;
                http_buf_destroy(hc->http_server, htbuf);
                pc->oqueue = np;
            }
            else
            {
                htbuf->len -= res;
                htbuf->offset += res;
            }

            if (!pc->oqueue) {
                iochan_setflags(pi, EVENT_INPUT); // Turns off output flag
            }
            break;
        default:
            yaz_log(YLOG_WARN, "Unexpected event on connection");
            http_channel_destroy(hc->iochan);
    }
}
Пример #8
0
static void session_timeout(IOCHAN i, int event)
{
    struct http_session *s = iochan_getdata(i);
    http_session_destroy(s);
}
Пример #9
0
/* UNIX listener */
static void listener(IOCHAN h, int event)
{
    COMSTACK line = (COMSTACK) iochan_getdata(h);
    int res;

    if (event == EVENT_INPUT)
    {
        COMSTACK new_line;
        if ((res = cs_listen_check(line, 0, 0, control_block.check_ip,
                                   control_block.daemon_name)) < 0)
        {
            yaz_log(YLOG_WARN|YLOG_ERRNO, "cs_listen failed");
            return;
        }
        else if (res == 1)
        {
            yaz_log(YLOG_WARN, "cs_listen incomplete");
            return;
        }
        new_line = cs_accept(line);
        if (!new_line)
        {
            yaz_log(YLOG_FATAL, "Accept failed.");
            iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
            return;
        }

        yaz_log(log_sessiondetail, "Connect from %s", cs_addrstr(new_line));

        no_sessions++;
        if (control_block.dynamic)
        {
            if ((res = fork()) < 0)
            {
                yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork");
                iochan_destroy(h);
                return;
            }
            else if (res == 0) /* child */
            {
                char nbuf[100];
                IOCHAN pp;

                for (pp = pListener; pp; pp = iochan_getnext(pp))
                {
                    COMSTACK l = (COMSTACK)iochan_getdata(pp);
                    cs_close(l);
                    iochan_destroy(pp);
                }
                sprintf(nbuf, "%s(%d)", me, no_sessions);
                yaz_log_init_prefix(nbuf);
                /* ensure that bend_stop is not called when each child exits -
                   only for the main process ..  */
                control_block.bend_stop = 0;
            }
            else /* parent */
            {
                cs_close(new_line);
                return;
            }
        }

        if (control_block.threads)
        {
#if YAZ_POSIX_THREADS
            pthread_t child_thread;
            pthread_create(&child_thread, 0, new_session, new_line);
            pthread_detach(child_thread);
#elif YAZ_GNU_THREADS
            pth_attr_t attr;
            pth_t child_thread;

            attr = pth_attr_new();
            pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
            pth_attr_set(attr, PTH_ATTR_STACK_SIZE, 32*1024);
            pth_attr_set(attr, PTH_ATTR_NAME, "session");
            yaz_log(YLOG_DEBUG, "pth_spawn begin");
            child_thread = pth_spawn(attr, new_session, new_line);
            yaz_log(YLOG_DEBUG, "pth_spawn finish");
            pth_attr_destroy(attr);
#else
            new_session(new_line);
#endif
        }
        else
            new_session(new_line);
    }
    else if (event == EVENT_TIMEOUT)
    {
        yaz_log(log_server, "Shutting down listener.");
        iochan_destroy(h);
    }
    else
    {
        yaz_log(YLOG_FATAL, "Bad event on listener.");
        iochan_destroy(h);
    }
}
Пример #10
0
/* WIN32 listener */
static void listener(IOCHAN h, int event)   
{
    COMSTACK line = (COMSTACK) iochan_getdata(h);
    IOCHAN parent_chan = line->user;
    association *newas;
    int res;
    HANDLE newHandle;

    if (event == EVENT_INPUT)
    {
        COMSTACK new_line;
        IOCHAN new_chan;

        if ((res = cs_listen(line, 0, 0)) < 0)
        {
            yaz_log(YLOG_FATAL|YLOG_ERRNO, "cs_listen failed");
            return;
        }
        else if (res == 1)
            return; /* incomplete */
        yaz_log(YLOG_DEBUG, "listen ok");
        new_line = cs_accept(line);
	if (!new_line)
        {
            yaz_log(YLOG_FATAL, "Accept failed.");
            return;
        }
        yaz_log(YLOG_DEBUG, "Accept ok");

        if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
                                       EVENT_INPUT, parent_chan->chan_id)))
        {
            yaz_log(YLOG_FATAL, "Failed to create iochan");
            iochan_destroy(h);
            return;
        }

        yaz_log(YLOG_DEBUG, "Creating association");
        if (!(newas = create_association(new_chan, new_line,
                                         control_block.apdufile)))
        {
            yaz_log(YLOG_FATAL, "Failed to create new assoc.");
            iochan_destroy(h);
            return;
        }
        newas->cs_get_mask = EVENT_INPUT;
        newas->cs_put_mask = 0;
        newas->cs_accept_mask = 0;

        yaz_log(YLOG_DEBUG, "Setting timeout %d", control_block.idle_timeout);
        iochan_setdata(new_chan, newas);
        iochan_settimeout(new_chan, 60);

        /* Now what we need todo is create a new thread with this iochan as
           the parameter */
        newHandle = (HANDLE) _beginthread(event_loop_thread, 0, new_chan);
        if (newHandle == (HANDLE) -1)
        {
            
            yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create new thread.");
            iochan_destroy(h);
            return;
        }
        /* We successfully created the thread, so add it to the list */
        statserv_add(newHandle, new_chan);

        yaz_log(YLOG_DEBUG, "Created new thread, id = %ld iochan %p",(long) newHandle, new_chan);
        iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
    }
    else
    {
        yaz_log(YLOG_FATAL, "Bad event on listener.");
        iochan_destroy(h);
        return;
    }
}