Ejemplo n.º 1
0
normalize_record_t normalize_cache_get(normalize_cache_t nc,
                                       struct conf_service *service,
                                       const char *spec)
{
    normalize_record_t nt;
    struct cached_item *ci;

    yaz_mutex_enter(nc->mutex);
    for (ci = nc->items; ci; ci = ci->next)
        if (!strcmp(spec, ci->spec))
            break;
    if (ci)
        nt = ci->nt;
    else
    {
        nt = normalize_record_create(service, spec);
        if (nt)
        {
            ci = nmem_malloc(nc->nmem, sizeof(*ci));
            ci->next = nc->items;
            nc->items = ci;
            ci->nt = nt;
            ci->spec = nmem_strdup(nc->nmem, spec);
        }
    }
    yaz_mutex_leave(nc->mutex);
    return nt;
}
Ejemplo n.º 2
0
void http_server_incref(http_server_t hs)
{
    assert(hs);
    yaz_mutex_enter(hs->mutex);
    (hs->ref_count)++;
    yaz_mutex_leave(hs->mutex);
}
Ejemplo n.º 3
0
// Creates a new connection for client, associated with the host of 
// client's database
static struct connection *connection_create(struct client *cl,
                                            struct host *host,
                                            int operation_timeout,
                                            int session_timeout,
                                            iochan_man_t iochan_man)
{
    struct connection *co;

    co = xmalloc(sizeof(*co));
    co->host = host;

    co->client = cl;
    co->zproxy = 0;
    client_set_connection(cl, co);
    co->link = 0;
    co->state = Conn_Closed;
    co->operation_timeout = operation_timeout;
    co->session_timeout = session_timeout;
    
    if (host->ipport)
        connection_connect(co, iochan_man);

    yaz_mutex_enter(host->mutex);
    co->next = co->host->connections;
    co->host->connections = co;
    yaz_mutex_leave(host->mutex);

    connection_use(1);
    return co;
}
Ejemplo n.º 4
0
static struct http_session *locate_session(struct http_channel *c)
{
    struct http_request *rq = c->request;
    struct http_response *rs = c->response;
    struct http_session *p;
    const char *session = http_argbyname(rq, "session");
    http_sessions_t http_sessions = c->http_sessions;
    unsigned int id;

    if (!session)
    {
        error(rs, PAZPAR2_MISSING_PARAMETER, "session");
        return 0;
    }
    id = atoi(session);
    yaz_mutex_enter(http_sessions->mutex);
    for (p = http_sessions->session_list; p; p = p->next)
        if (id == p->session_id)
            break;
    if (p)
        p->activity_counter++;
    yaz_mutex_leave(http_sessions->mutex);
    if (p)
        iochan_activity(p->timeout_iochan);
    else
        error(rs, PAZPAR2_NO_SESSION, session);
    return p;
}
Ejemplo n.º 5
0
void http_session_destroy(struct http_session *s)
{
    int must_destroy = 0;

    http_sessions_t http_sessions = s->http_sessions;

    yaz_log(http_sessions->log_level, "Session %u destroy", s->session_id);
    yaz_mutex_enter(http_sessions->mutex);
    /* only if http_session has no active http sessions on it can be destroyed */
    if (s->destroy_counter == s->activity_counter)
    {
        struct http_session **p = 0;
        must_destroy = 1;
        for (p = &http_sessions->session_list; *p; p = &(*p)->next)
            if (*p == s)
            {
                *p = (*p)->next;
                break;
            }
    }
    yaz_mutex_leave(http_sessions->mutex);
    if (must_destroy)
    {   /* destroying for real */
        yaz_log(http_sessions->log_level, "Session %u destroyed", s->session_id);
        iochan_destroy(s->timeout_iochan);
        session_destroy(s->psession);
        http_session_use(-1);
        nmem_destroy(s->nmem);
    }
    else {
        yaz_log(http_sessions->log_level, "Session %u destroying delayed. Active clients (%d-%d). Waiting for new timeout.",
                s->session_id, s->activity_counter, s->destroy_counter);
    }

}
Ejemplo n.º 6
0
struct http_session *http_session_create(struct conf_service *service,
        http_sessions_t http_sessions,
        unsigned int sesid)
{
    NMEM nmem = nmem_create();
    struct http_session *r = nmem_malloc(nmem, sizeof(*r));
    char tmp_str[50];

    sprintf(tmp_str, "session#%u", sesid);
    r->psession = new_session(nmem, service, sesid);
    r->session_id = sesid;
    r->timestamp = 0;
    r->nmem = nmem;
    r->destroy_counter = r->activity_counter = 0;
    r->http_sessions = http_sessions;

    yaz_mutex_enter(http_sessions->mutex);
    r->next = http_sessions->session_list;
    http_sessions->session_list = r;
    yaz_mutex_leave(http_sessions->mutex);

    r->timeout_iochan = iochan_create(-1, session_timeout, 0, "http_session_timeout");
    iochan_setdata(r->timeout_iochan, r);
    yaz_log(http_sessions->log_level, "Session %u created. timeout chan=%p timeout=%d", sesid, r->timeout_iochan, service->session_timeout);
    iochan_settimeout(r->timeout_iochan, service->session_timeout);

    iochan_add(service->server->iochan_man, r->timeout_iochan);
    http_session_use(1);
    return r;
}
Ejemplo n.º 7
0
void *sel_thread_result(sel_thread_t p)
{
    struct work_item *work_this = 0;
    void *data = 0;
    char read_buf[1];

    yaz_mutex_enter(p->mutex);

    /* got something. Take the last one out of output_queue */
    work_this = queue_remove_last(&p->output_queue);
    if (work_this)
    {
        /* put freed item in free list */
        work_this->next = p->free_queue;
        p->free_queue = work_this;
        
        data = work_this->data;
#ifdef WIN32
        (void) recv(p->read_fd, read_buf, 1, 0);
#else
        (void) read(p->read_fd, read_buf, 1);
#endif
    }
    yaz_mutex_leave(p->mutex);
    return data;
}
Ejemplo n.º 8
0
int pazpar2_decref(int *ref, YAZ_MUTEX mutex)
{
    int value ;
    yaz_mutex_enter(mutex);
    value = --(*ref);
    yaz_mutex_leave(mutex);
    return value;
}
Ejemplo n.º 9
0
static void *sel_thread_handler(void *vp)
{
    sel_thread_t p = (sel_thread_t) vp;

    while (1)
    {
        struct work_item *work_this = 0;
        /* wait for some work */
        yaz_mutex_enter(p->mutex);
        while (!p->stop_flag && !p->input_queue)
            yaz_cond_wait(p->input_data, p->mutex, 0);
        /* see if we were waken up because we're shutting down */
        if (p->stop_flag)
            break;
        /* got something. Take the last one out of input_queue */

        assert(p->input_queue);
        work_this = queue_remove_last(&p->input_queue);
        input_queue_length--;
#if 0
        yaz_log(YLOG_DEBUG, "input queue length after pop: %d", input_queue_length);
#endif
        assert(work_this);

        yaz_mutex_leave(p->mutex);

        /* work on this item */
        p->work_handler(work_this->data);
        
        /* put it back into output queue */
        yaz_mutex_enter(p->mutex);
        work_this->next = p->output_queue;
        p->output_queue = work_this;
        yaz_mutex_leave(p->mutex);

        /* wake up select/poll with a single byte */
#ifdef WIN32
        (void) send(p->write_fd, "", 1, 0);
#else
        (void) write(p->write_fd, "", 1);
#endif
    }        
    yaz_mutex_leave(p->mutex);
    return 0;
}
Ejemplo n.º 10
0
void iochan_add(iochan_man_t man, IOCHAN chan) {
    chan->man = man;
    yaz_mutex_enter(man->iochan_mutex);
    yaz_log(man->log_level, "iochan_add : chan=%p channel list=%p", chan,
            man->channel_list);
    chan->next = man->channel_list;
    man->channel_list = chan;
    yaz_mutex_leave(man->iochan_mutex);
}
Ejemplo n.º 11
0
// Call after use of locate_session, in order to increment the destroy_counter
static void release_session(struct http_channel *c,
                            struct http_session *session)
{
    http_sessions_t http_sessions = c->http_sessions;
    yaz_mutex_enter(http_sessions->mutex);
    if (session)
        session->destroy_counter++;
    yaz_mutex_leave(http_sessions->mutex);
}
Ejemplo n.º 12
0
int  iochans_count_total(void) {
    int total = 0;
    if (!g_mutex)
        return 0;
    yaz_mutex_enter(g_mutex);
    total = no_iochans_total;
    yaz_mutex_leave(g_mutex);
    return total;
}
Ejemplo n.º 13
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));
        }
    }
}
Ejemplo n.º 14
0
int http_session_use(int delta)
{
    int sessions;
    if (!g_http_session_mutex)
        yaz_mutex_create(&g_http_session_mutex);
    yaz_mutex_enter(g_http_session_mutex);
    g_http_sessions += delta;
    sessions = g_http_sessions;
    yaz_mutex_leave(g_http_session_mutex);
    yaz_log(YLOG_DEBUG, "%s sessions=%d", delta == 0 ? "" : (delta > 0 ? "INC" : "DEC"), sessions);
    return sessions;

}
Ejemplo n.º 15
0
static int iochan_use(int delta)
{
    int iochans;
    if (!g_mutex)
        yaz_mutex_create(&g_mutex);
    yaz_mutex_enter(g_mutex);
    no_iochans += delta;
    if (delta > 0)
        no_iochans_total += delta;
    iochans = no_iochans;
    yaz_mutex_leave(g_mutex);
    yaz_log(YLOG_DEBUG, "%s iochans=%d", delta == 0 ? "" : (delta > 0 ? "INC" : "DEC"), iochans);
    return iochans;
}
Ejemplo n.º 16
0
static int connection_use(int delta)
{
    int result;
    if (!g_mutex)
        yaz_mutex_create(&g_mutex);
    yaz_mutex_enter(g_mutex);
    no_connections += delta;
    result = no_connections;
    if (delta > 0)
        total_no_connections += delta;
    yaz_mutex_leave(g_mutex);
    if (delta == 0)
            return result;
    yaz_log(YLOG_LOG, "%s connections=%d", delta > 0 ? "INC" : "DEC",
            no_connections);
    return result;
}
Ejemplo n.º 17
0
void iochan_man_destroy(iochan_man_t *mp) {
    if (*mp) {
        IOCHAN c;
        if ((*mp)->sel_thread)
            sel_thread_destroy((*mp)->sel_thread);

        yaz_mutex_enter((*mp)->iochan_mutex);
        c = (*mp)->channel_list;
        (*mp)->channel_list = NULL;
        yaz_mutex_leave((*mp)->iochan_mutex);
        while (c) {
            c = iochan_destroy_real(c);
        }
        yaz_mutex_destroy(&(*mp)->iochan_mutex);
        xfree(*mp);
        *mp = 0;
    }
}
Ejemplo n.º 18
0
void connect_resolver_host(struct host *host, iochan_man_t iochan_man)
{
    struct connection *con;

start:
    yaz_mutex_enter(host->mutex);
    con = host->connections;
    while (con)
    {
        if (con->state == Conn_Closed)
        {
            if (!host->ipport) /* unresolved */
            {
                remove_connection_from_host(con);
                yaz_mutex_leave(host->mutex);
                connection_destroy(con);
                goto start;
                /* start all over .. at some point it will be NULL */
            }
            else if (!con->client)
            {
                remove_connection_from_host(con);
                yaz_mutex_leave(host->mutex);
                connection_destroy(con);
                /* start all over .. at some point it will be NULL */
                goto start;
            }
            else
            {
                yaz_mutex_leave(host->mutex);
                connection_connect(con, iochan_man);
                client_start_search(con->client);
                goto start;
            }
        }
        else
        {
            yaz_log(YLOG_LOG, "connect_resolver_host: state=%d", con->state);
            con = con->next;
        }
    }
    yaz_mutex_leave(host->mutex);
}
Ejemplo n.º 19
0
void http_server_destroy(http_server_t hs)
{
    if (hs)
    {
        int r;

        yaz_mutex_enter(hs->mutex); /* OK: hs->mutex may be NULL */
        r = --(hs->ref_count);
        yaz_mutex_leave(hs->mutex);

        if (r == 0)
        {
            http_sessions_destroy(hs->http_sessions);
            xfree(hs->proxy_addr);
            yaz_mutex_destroy(&hs->mutex);
            if (hs->record_file)
                fclose(hs->record_file);
            xfree(hs);
        }
    }
}
Ejemplo n.º 20
0
void sel_thread_destroy(sel_thread_t p)
{
    int i;
    yaz_mutex_enter(p->mutex);
    p->stop_flag = 1;
    yaz_cond_broadcast(p->input_data);
    yaz_mutex_leave(p->mutex);
    
    for (i = 0; i< p->no_threads; i++)
        yaz_thread_join(&p->thread_id[i], 0);

    if (p->work_destroy)
    {
        queue_trav(p->input_queue, p->work_destroy);
        queue_trav(p->output_queue, p->work_destroy);
    }

    yaz_spipe_destroy(p->spipe);
    yaz_cond_destroy(&p->input_data);
    yaz_mutex_destroy(&p->mutex);
    nmem_destroy(p->nmem);
}
Ejemplo n.º 21
0
void sel_thread_add(sel_thread_t p, void *data)
{
    struct work_item *work_p;

    yaz_mutex_enter(p->mutex);

    if (p->free_queue)
    {
        work_p = p->free_queue;
        p->free_queue = p->free_queue->next;
    }
    else
        work_p = nmem_malloc(p->nmem, sizeof(*work_p));

    work_p->data = data;
    work_p->next = p->input_queue;
    p->input_queue = work_p;
    input_queue_length++;
#if 0
    yaz_log(YLOG_DEBUG, "sel_thread_add: Input queue length after push: %d", input_queue_length);
#endif
    yaz_cond_signal(p->input_data);
    yaz_mutex_leave(p->mutex);
}
Ejemplo n.º 22
0
void pazpar2_incref(int *ref, YAZ_MUTEX mutex)
{
    yaz_mutex_enter(mutex);
    (*ref)++;
    yaz_mutex_leave(mutex);
}
Ejemplo n.º 23
0
static int event_loop(iochan_man_t man, IOCHAN *iochans) {
    do /* loop as long as there are active associations to process */
    {
        IOCHAN p, *nextp;
        IOCHAN start;
        IOCHAN inv_start;
        fd_set in, out, except;
        int res, max;
        static struct timeval to;
        struct timeval *timeout;

//        struct yaz_poll_fd *fds;
        int no_fds = 0;
        FD_ZERO(&in);
        FD_ZERO(&out);
        FD_ZERO(&except);
        timeout = &to; /* hang on select */
        to.tv_sec = 300;
        to.tv_usec = 0;

        // INV: start must no change through the loop

        yaz_mutex_enter(man->iochan_mutex);
        start = man->channel_list;
        yaz_mutex_leave(man->iochan_mutex);
        inv_start = start;
        for (p = start; p; p = p->next) {
            no_fds++;
        }
//        fds = (struct yaz_poll_fd *) xmalloc(no_fds * sizeof(*fds));

        max = 0;
        for (p = start; p; p = p->next) {
            if (p->thread_users > 0)
                continue;
            if (p->max_idle && p->max_idle < to.tv_sec)
                to.tv_sec = p->max_idle;
            if (p->fd < 0)
                continue;
            if (p->flags & EVENT_INPUT)
                FD_SET(p->fd, &in);
            if (p->flags & EVENT_OUTPUT)
                FD_SET(p->fd, &out);
            if (p->flags & EVENT_EXCEPT)
                FD_SET(p->fd, &except);
            if (p->fd > max)
                max = p->fd;
        }
        yaz_log(man->log_level, "max=%d sel_fd=%d", max, man->sel_fd);

        if (man->sel_fd != -1) {
            if (man->sel_fd > max)
                max = man->sel_fd;
            FD_SET(man->sel_fd, &in);
        }
        yaz_log(man->log_level, "select begin nofds=%d", max);
        res = select(max + 1, &in, &out, &except, timeout);
        yaz_log(man->log_level, "select returned res=%d", res);
        if (res < 0) {
            if (errno == EINTR)
                continue;
            else {
                yaz_log(YLOG_ERRNO | YLOG_WARN, "select");
                return 0;
            }
        }
        if (man->sel_fd != -1) {
            if (FD_ISSET(man->sel_fd, &in)) {
                IOCHAN chan;

                yaz_log(man->log_level, "eventl: sel input on sel_fd=%d",
                        man->sel_fd);
                while ((chan = sel_thread_result(man->sel_thread))) {
                    yaz_log(man->log_level,
                            "eventl: got thread result chan=%p name=%s", chan,
                            chan->name ? chan->name : "");
                    chan->thread_users--;
                }
            }
        }
        if (man->log_level) {
            int no = 0;
            for (p = start; p; p = p->next) {
                no++;
            }
            yaz_log(man->log_level, "%d channels", no);
        }
        for (p = start; p; p = p->next) {
            time_t now = time(0);

            if (p->destroyed) {
                yaz_log(man->log_level,
                        "eventl: skip destroyed chan=%p name=%s", p,
                        p->name ? p->name : "");
                continue;
            }
            if (p->thread_users > 0) {
                yaz_log(man->log_level,
                        "eventl: skip chan=%p name=%s users=%d", p,
                        p->name ? p->name : "", p->thread_users);
                continue;
            }
            p->this_event = 0;

            if (p->max_idle && now - p->last_event > p->max_idle) {
                p->last_event = now;
                p->this_event |= EVENT_TIMEOUT;
            }
            if (p->fd >= 0) {
                if (FD_ISSET(p->fd, &in)) {
                    p->last_event = now;
                    p->this_event |= EVENT_INPUT;
                }
                if (FD_ISSET(p->fd, &out)) {
                    p->last_event = now;
                    p->this_event |= EVENT_OUTPUT;
                }
                if (FD_ISSET(p->fd, &except)) {
                    p->last_event = now;
                    p->this_event |= EVENT_EXCEPT;
                }
            }
            run_fun(man, p);
        }
        assert(inv_start == start);
        yaz_mutex_enter(man->iochan_mutex);
        for (nextp = iochans; *nextp;) {
            IOCHAN p = *nextp;
            if (p->destroyed && p->thread_users == 0) {
                *nextp = iochan_destroy_real(p);
            } else
                nextp = &p->next;
        }
        yaz_mutex_leave(man->iochan_mutex);
    } while (*iochans);
    return 0;
}
Ejemplo n.º 24
0
// Ensure that client has a connection associated
int client_prep_connection(struct client *cl,
                           int operation_timeout, int session_timeout,
                           iochan_man_t iochan_man,
                           const struct timeval *abstime)
{
    struct connection *co;
    struct session_database *sdb = client_get_database(cl);
    const char *zproxy = session_setting_oneval(sdb, PZ_ZPROXY);
    const char *url = session_setting_oneval(sdb, PZ_URL);
    const char *sru = session_setting_oneval(sdb, PZ_SRU);
    struct host *host = 0;
    int default_port = *sru ? 80 : 210;

    if (zproxy && zproxy[0] == '\0')
        zproxy = 0;

    if (!url || !*url)
        url = sdb->database->id;

    host = find_host(client_get_session(cl)->service->server->database_hosts,
                     url, zproxy, default_port, iochan_man);

    yaz_log(YLOG_DEBUG, "client_prep_connection: target=%s url=%s",
            client_get_id(cl), url);
    if (!host)
        return 0;

    co = client_get_connection(cl);

    if (co)
    {
        assert(co->host);
        if (co->host == host && client_get_state(cl) == Client_Idle)
        {
            return 2;
        }
        client_incref(cl);
        connection_release(co);
        co = 0;
    }
    if (!co)
    {
        int max_connections = 0;
        int reuse_connections = 1;
        const char *v = session_setting_oneval(client_get_database(cl),
                                               PZ_MAX_CONNECTIONS);
        if (v && *v)
            max_connections = atoi(v);
        
        v = session_setting_oneval(client_get_database(cl),
                PZ_REUSE_CONNECTIONS);
        if (v && *v)
            reuse_connections = atoi(v);

        // See if someone else has an idle connection
        // We should look at timestamps here to select the longest-idle connection
        yaz_mutex_enter(host->mutex);
        while (1)
        {
            int num_connections = 0;
            for (co = host->connections; co; co = co->next)
                num_connections++;
            if (reuse_connections)
            {
                for (co = host->connections; co; co = co->next)
                {
                    if (connection_is_idle(co) &&
                        (!co->client || client_get_state(co->client) == Client_Idle) &&
                        !strcmp(ZOOM_connection_option_get(co->link, "user"),
                                session_setting_oneval(client_get_database(cl),
                                                       PZ_AUTHENTICATION)))
                    {
                        if (zproxy == 0 && co->zproxy == 0)
                            break;
                        if (zproxy && co->zproxy && !strcmp(zproxy, co->zproxy))
                            break;
                    }
                }
                if (co)
                {
                    yaz_log(YLOG_LOG, "num_connections = %d (reusing)", num_connections);
                    break;
                }
            }
            if (max_connections <= 0 || num_connections < max_connections)
            {
                yaz_log(YLOG_LOG, "num_connections = %d (new); max = %d",
                        num_connections, max_connections);
                break;
            }
            yaz_log(YLOG_LOG, "num_connections = %d (waiting) max = %d",
                    num_connections, max_connections);
            if (yaz_cond_wait(host->cond_ready, host->mutex, abstime))
            {
                yaz_log(YLOG_LOG, "out of connections %s", client_get_id(cl));
                client_set_state(cl, Client_Error);
                yaz_mutex_leave(host->mutex);
                return 0;
            }
        }
        if (co)
        {
            yaz_log(YLOG_LOG,  "%p Connection reuse. state: %d", co, co->state);
            connection_release(co);
            client_set_connection(cl, co);
            co->client = cl;
            /* ensure that connection is only assigned to this client
               by marking the client non Idle */
            client_set_state(cl, Client_Working);
            yaz_mutex_leave(host->mutex);
            co->operation_timeout = operation_timeout;
            co->session_timeout = session_timeout;
            /* tells ZOOM to reconnect if necessary. Disabled becuase
               the ZOOM_connection_connect flushes the task queue */
            ZOOM_connection_connect(co->link, 0, 0);
        }
        else
        {
            yaz_mutex_leave(host->mutex);
            co = connection_create(cl, host, operation_timeout, session_timeout,
                                   iochan_man);
        }
        assert(co->host);
    }

    if (co && co->link)
        return 1;
    else
        return 0;
}