1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2009 Index Data
3 * See the file LICENSE for details.
7 * \brief Small HTTP server
11 #include <yaz/comstack.h>
14 #include <yaz/sock_man.h>
15 #include <yaz/tpool.h>
22 cs_ses_type_accepting,
27 enum cs_ses_type type;
40 struct cs_session *ses;
45 struct cs_session *listeners;
48 yaz_sock_man_t sock_man;
51 yaz_srv_session_handler_t *session_handler;
52 yaz_srv_gdu_handler_t *gdu_handler;
55 static void cs_session_init(struct cs_session *ses, enum cs_ses_type type)
61 ses->cs_get_mask = yaz_poll_read;
62 ses->input_buffer = 0;
66 static void cs_session_destroy(struct cs_session *ses)
68 xfree(ses->input_buffer);
70 yaz_sock_chan_destroy(ses->chan);
75 void yaz_srv_destroy(yaz_srv_t p)
81 yaz_tpool_destroy(p->tpool);
82 for (i = 0; i < p->num_listeners; i++)
84 cs_session_destroy(p->listeners + i);
86 yaz_sock_man_destroy(p->sock_man);
87 nmem_destroy(p->nmem);
91 yaz_srv_t yaz_srv_create(const char **listeners_str)
93 NMEM nmem = nmem_create();
94 yaz_srv_t p = nmem_malloc(nmem, sizeof(*p));
96 for (i = 0; listeners_str[i]; i++)
101 p->session_handler = 0;
103 p->num_listeners = i;
105 nmem_malloc(nmem, p->num_listeners * sizeof(*p->listeners));
106 p->sock_man = yaz_sock_man_new();
108 for (i = 0; i < p->num_listeners; i++)
111 const char *where = listeners_str[i];
112 COMSTACK l = cs_create_host(where, CS_FLAGS_NUMERICHOST, &ap);
114 cs_session_init(p->listeners +i, cs_ses_type_listener);
117 yaz_log(YLOG_WARN|YLOG_ERRNO, "cs_create_host(%s) failed", where);
121 if (cs_bind(l, ap, CS_SERVER) < 0)
123 if (cs_errno(l) == CSYSERR)
124 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to bind to %s", where);
126 yaz_log(YLOG_FATAL, "Failed to bind to %s: %s", where,
132 p->listeners[i].cs = l; /* success */
133 p->listeners[i].chan =
134 yaz_sock_chan_new(p->sock_man,
137 yaz_poll_read | yaz_poll_except);
142 /* check if all are OK */
143 for (i = 0; i < p->num_listeners; i++)
144 if (!p->listeners[i].cs)
152 static void new_session(yaz_srv_t p, COMSTACK new_line)
154 struct cs_session *ses = xmalloc(sizeof(*ses));
156 ((new_line->io_pending & CS_WANT_WRITE) ? yaz_poll_write : 0) |
157 ((new_line->io_pending & CS_WANT_READ) ? yaz_poll_read : 0);
161 yaz_log(YLOG_LOG, "type accepting");
162 cs_session_init(ses, cs_ses_type_accepting);
166 yaz_log(YLOG_LOG, "type normal");
167 cs_session_init(ses, cs_ses_type_normal);
168 mask = yaz_poll_read;
169 ses->user = p->session_handler(ses);
172 ses->chan = yaz_sock_chan_new(p->sock_man, cs_fileno(new_line), ses, mask);
175 void yaz_pkg_destroy(yaz_pkg_t pkg)
179 odr_destroy(pkg->odr);
184 void work_handler(void *data)
186 yaz_pkg_t pkg = (yaz_pkg_t) data;
188 pkg->srv->gdu_handler(pkg, pkg->ses->user);
189 yaz_pkg_destroy(pkg);
192 void work_destroy(void *data)
194 yaz_pkg_t pkg = (yaz_pkg_t) data;
195 yaz_pkg_destroy(pkg);
199 void yaz_srv_run(yaz_srv_t p, yaz_srv_session_handler_t session_handler,
200 yaz_srv_gdu_handler_t gdu_handler)
202 yaz_sock_chan_t chan;
204 p->session_handler = session_handler;
205 p->gdu_handler = gdu_handler;
208 p->tpool = yaz_tpool_create(work_handler, work_destroy, 20);
209 while ((chan = yaz_sock_man_wait(p->sock_man)))
211 unsigned output_mask = yaz_sock_get_mask(chan);
212 struct cs_session *ses = yaz_sock_chan_get_data(chan);
218 case cs_ses_type_listener:
219 if (yaz_sock_get_mask(chan) & yaz_poll_read)
221 int ret = cs_listen(ses->cs, 0, 0);
224 yaz_log(YLOG_WARN|YLOG_ERRNO, "listen failed");
228 yaz_log(YLOG_WARN, "cs_listen incomplete");
232 COMSTACK new_line = cs_accept(ses->cs);
235 yaz_log(YLOG_LOG, "new session");
236 new_session(p, new_line);
240 yaz_log(YLOG_WARN|YLOG_ERRNO, "accept failed");
245 case cs_ses_type_accepting:
246 if (!cs_accept(ses->cs))
248 yaz_log(YLOG_WARN|YLOG_ERRNO, "cs_accept failed");
249 cs_session_destroy(ses);
255 ((ses->cs->io_pending & CS_WANT_WRITE) ? yaz_poll_write : 0) |
256 ((ses->cs->io_pending & CS_WANT_READ) ? yaz_poll_read : 0);
259 ses->type = cs_ses_type_accepting;
263 ses->type = cs_ses_type_normal;
264 mask = yaz_poll_read;
266 yaz_sock_chan_set_mask(ses->chan, mask);
269 case cs_ses_type_normal:
270 if ((ses->cs_put_mask & yaz_poll_read) == 0 &&
271 output_mask & ses->cs_get_mask)
273 /* receiving package */
274 unsigned new_mask = yaz_poll_read;
275 yaz_log(YLOG_LOG, "Receive");
278 int res = cs_get(ses->cs, &ses->input_buffer, &ses->input_len);
281 yaz_log(YLOG_WARN, "Connection closed by client");
282 cs_session_destroy(ses);
289 if (ses->cs->io_pending & CS_WANT_WRITE)
290 new_mask |= yaz_poll_write;
294 { /* complete package */
295 yaz_pkg_t pkg = xmalloc(sizeof(*pkg));
296 yaz_log(YLOG_LOG, "COMPLETE PACKAGE");
300 pkg->odr = odr_createmem(ODR_DECODE);
301 odr_setbuf(pkg->odr, ses->input_buffer, res, 0);
302 if (!z_GDU(pkg->odr, &pkg->gdu, 0, 0))
304 yaz_log(YLOG_WARN, "decoding failed");
305 odr_destroy(pkg->odr);
310 yaz_tpool_add(p->tpool, pkg);
313 } while (cs_more(ses->cs));
314 yaz_sock_chan_set_mask(chan, new_mask);
316 if (ses && (output_mask & ses->cs_put_mask))
317 { /* sending package */
318 yaz_log(YLOG_LOG, "Sending");
324 Z_GDU **yaz_pkg_get_gdu(yaz_pkg_t pkg)
329 ODR yaz_pkg_get_odr(yaz_pkg_t pkg)
334 void yaz_pkg_close(yaz_pkg_t pkg)
336 struct cs_session *ses = pkg->ses;
339 cs_session_destroy(ses);
345 void yaz_pkg_stop_server(yaz_pkg_t pkg)
347 pkg->srv->stop_flag = 1;
350 yaz_pkg_t yaz_pkg_create(yaz_pkg_t request_pkg)
352 yaz_pkg_t pkg = xmalloc(sizeof(*pkg));
355 pkg->odr = odr_createmem(ODR_ENCODE);
356 pkg->ses = request_pkg->ses;
357 pkg->srv = request_pkg->srv;
361 Z_GDU *zget_wrap_APDU(ODR o, Z_APDU *apdu)
363 Z_GDU *gdu = odr_malloc(o, sizeof(*gdu));
364 gdu->which = Z_GDU_Z3950;
369 void yaz_pkg_send(yaz_pkg_t pkg)
371 yaz_log(YLOG_WARN, "send.. UNFINISHED");
377 * c-file-style: "Stroustrup"
378 * indent-tabs-mode: nil
380 * vim: shiftwidth=4 tabstop=8 expandtab