/* This file is part of Pazpar2.
- Copyright (C) 2006-2010 Index Data
+ Copyright (C) 2006-2011 Index Data
Pazpar2 is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
#include <yaz/nmem.h>
#include <yaz/mutex.h>
-#include "pazpar2.h"
+#include "ppmutex.h"
+#include "session.h"
#include "http.h"
#define MAX_HTTP_HEADER 4096
struct http_server
{
struct http_buf *http_buf_freelist;
+ int http_buf_freelist_count;
+ int http_buf_freelist_max;
+
struct http_channel *http_channel_freelist;
+ int http_channel_freelist_count;
+ int http_channel_freelist_max;
YAZ_MUTEX mutex;
int listener_socket;
int ref_count;
{
r = hs->http_buf_freelist;
hs->http_buf_freelist = hs->http_buf_freelist->next;
+ hs->http_buf_freelist_count--;
}
yaz_mutex_leave(hs->mutex);
if (!r)
static void http_buf_destroy(http_server_t hs, struct http_buf *b)
{
yaz_mutex_enter(hs->mutex);
- b->next = hs->http_buf_freelist;
- hs->http_buf_freelist = b;
+ if (hs->http_buf_freelist_max > 0 && hs->http_buf_freelist_count >= hs->http_buf_freelist_max) {
+ xfree(b);
+ while ((b = hs->http_buf_freelist)) {
+ xfree(b);
+ hs->http_buf_freelist = hs->http_buf_freelist->next;
+ }
+ hs->http_buf_freelist_count = 0;
+ }
+ else {
+ b->next = hs->http_buf_freelist;
+ hs->http_buf_freelist = b;
+ hs->http_buf_freelist_count++;
+ yaz_log(YLOG_DEBUG, "Free %d http buffers on server.", hs->http_buf_freelist_count);
+ }
yaz_mutex_leave(hs->mutex);
}
p->first_response = 1;
c->proxy = p;
// We will add EVENT_OUTPUT below
- p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT);
+ p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT, "http_proxy");
iochan_setdata(p->iochan, p);
iochan_add(ser->iochan_man, p->iochan);
static void http_io(IOCHAN i, int event)
{
struct http_channel *hc = iochan_getdata(i);
-
- switch (event)
+ while (event)
{
- int res, reqlen;
- struct http_buf *htbuf;
-
- case EVENT_INPUT:
+ 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_command(hc);
}
}
- break;
- case EVENT_OUTPUT:
+ }
+ else if (event == EVENT_OUTPUT)
+ {
+ event = 0;
if (hc->oqueue)
{
struct http_buf *wb = hc->oqueue;
- res = send(iochan_getfd(hc->iochan), wb->buf + wb->offset, wb->len, 0);
+ 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");
wb->len -= res;
wb->offset += res;
}
- if (!hc->oqueue) {
+ if (!hc->oqueue)
+ {
if (!hc->keep_alive)
{
http_channel_destroy(i);
{
iochan_clearflag(i, EVENT_OUTPUT);
if (hc->iqueue)
- iochan_setevent(hc->iochan, EVENT_INPUT);
+ event = EVENT_INPUT;
}
}
}
-
if (!hc->oqueue && hc->proxy && !hc->proxy->iochan)
http_channel_destroy(i); // Server closed; we're done
- break;
- default:
+ }
+ else
+ {
yaz_log(YLOG_WARN, "Unexpected event on connection");
http_channel_destroy(i);
+ event = 0;
+ }
}
}
http_server = s->http_server; /* save it for destroy (decref) */
yaz_mutex_enter(s->http_server->mutex);
- s->next = s->http_server->http_channel_freelist;
- s->http_server->http_channel_freelist = s;
+ if (s->http_server->http_channel_freelist_max > 0 && s->http_server->http_channel_freelist_count >= s->http_server->http_channel_freelist_max) {
+ while ((s->next = s->http_server->http_channel_freelist)) {
+ nmem_destroy(s->next->nmem);
+ wrbuf_destroy(s->next->wrbuf);
+ xfree(s->next);
+ s->http_server->http_channel_freelist = s->http_server->http_channel_freelist->next;
+ }
+ s->http_server->http_channel_freelist_count = 0;
+ }
+ else {
+ s->next = s->http_server->http_channel_freelist;
+ s->http_server->http_channel_freelist = s;
+ s->http_server->http_channel_freelist_count++;
+ yaz_log(YLOG_DEBUG, "Free %d channels on server.", s->http_server->http_channel_freelist_count);
+ }
yaz_mutex_leave(s->http_server->mutex);
http_server_destroy(http_server);
yaz_mutex_enter(hs->mutex);
r = hs->http_channel_freelist;
- if (r)
+ if (r) {
hs->http_channel_freelist = r->next;
+ hs->http_channel_freelist_count--;
+ }
yaz_mutex_leave(hs->mutex);
if (r)
enable_nonblock(s);
yaz_log(YLOG_DEBUG, "New command connection");
- c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT);
+ 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);
server->http_server->listener_socket = l;
- c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT);
+ c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT, "http_server");
iochan_setdata(c, server);
iochan_add(server->iochan_man, c);
hs->mutex = 0;
hs->proxy_addr = 0;
hs->ref_count = 1;
- hs->http_buf_freelist = 0;
- hs->http_channel_freelist = 0;
hs->http_sessions = 0;
+
+ hs->http_channel_freelist = 0;
+ hs->http_channel_freelist_count = 0;
+ /* Disable max check */
+ hs->http_channel_freelist_max = 0;
+
+ hs->http_buf_freelist = 0;
+ hs->http_buf_freelist_count = 0;
+ /* Disable max check */
+ hs->http_buf_freelist_max = 0;
return hs;
}
{
int r;
- if (hs->mutex)
- {
- yaz_mutex_enter(hs->mutex);
- r = --(hs->ref_count);
- yaz_mutex_leave(hs->mutex);
- }
- else
- r = --(hs->ref_count);
+ yaz_mutex_enter(hs->mutex); /* OK: hs->mutex may be NULL */
+ r = --(hs->ref_count);
+ yaz_mutex_leave(hs->mutex);
if (r == 0)
{
assert(server);
assert(server->http_server->mutex == 0);
- yaz_mutex_create(&server->http_server->mutex);
+ pazpar2_mutex_create(&server->http_server->mutex, "http_server");
server->http_server->http_sessions = http_sessions_create();
}