blob: e526c84dc0c66faf594ae1a4567b372ebd057b1c [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program 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 Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "server.h"
#define THIS_FILE "server.c"
struct pj_stun_server
{
pj_stun_server_info si;
pj_pool_t *pool;
pj_bool_t thread_quit_flag;
pj_thread_t **threads;
unsigned usage_cnt;
pj_stun_usage *usage[32];
};
PJ_DEF(pj_status_t) pj_stun_perror( const char *sender,
const char *title,
pj_status_t status)
{
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(3,(sender, "%s: %s", title, errmsg));
return status;
}
static int worker_thread(void *p)
{
pj_stun_server *srv = (pj_stun_server*)p;
while (!srv->thread_quit_flag) {
pj_time_val timeout = { 0, 50 };
pj_timer_heap_poll(srv->si.timer_heap, NULL);
pj_ioqueue_poll(srv->si.ioqueue, &timeout);
}
return 0;
}
PJ_DEF(pj_status_t) pj_stun_server_create(pj_pool_factory *pf,
unsigned thread_cnt,
pj_stun_server **p_srv)
{
pj_pool_t *pool;
pj_stun_server *srv;
unsigned i;
pj_status_t status;
pool = pj_pool_create(pf, "server%p", 4000, 4000, NULL);
srv = PJ_POOL_ZALLOC_T(pool, pj_stun_server);
srv->pool = pool;
srv->si.pf = pf;
status = pj_ioqueue_create(srv->pool, PJ_IOQUEUE_MAX_HANDLES,
&srv->si.ioqueue);
if (status != PJ_SUCCESS)
goto on_error;
status = pj_timer_heap_create(srv->pool, 1024, &srv->si.timer_heap);
if (status != PJ_SUCCESS)
goto on_error;
pj_stun_config_init(&srv->si.stun_cfg, srv->si.pf, 0, srv->si.ioqueue,
srv->si.timer_heap);
srv->si.thread_cnt = thread_cnt;
srv->threads = (pj_thread_t**)
pj_pool_calloc(pool, thread_cnt, sizeof(pj_thread_t*));
for (i=0; i<thread_cnt; ++i) {
status = pj_thread_create(pool, "worker%p", &worker_thread,
srv, 0, 0, &srv->threads[i]);
if (status != PJ_SUCCESS)
goto on_error;
}
*p_srv = srv;
return PJ_SUCCESS;
on_error:
pj_stun_server_destroy(srv);
return status;
}
PJ_DEF(pj_stun_server_info*) pj_stun_server_get_info(pj_stun_server *srv)
{
return &srv->si;
}
pj_status_t pj_stun_server_register_usage(pj_stun_server *srv,
pj_stun_usage *usage)
{
unsigned i;
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
if (srv->usage[i] == usage)
return PJ_SUCCESS;
}
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
if (srv->usage[i] == NULL)
break;
}
if (i == PJ_ARRAY_SIZE(srv->usage))
return PJ_ETOOMANY;
srv->usage[i] = usage;
++srv->usage_cnt;
return PJ_SUCCESS;
}
pj_status_t pj_stun_server_unregister_usage(pj_stun_server *srv,
pj_stun_usage *usage)
{
unsigned i;
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
if (srv->usage[i] == usage)
break;
}
if (i != PJ_ARRAY_SIZE(srv->usage)) {
srv->usage[i] = NULL;
--srv->usage_cnt;
return PJ_SUCCESS;
}
return PJ_ENOTFOUND;
}
PJ_DEF(pj_status_t) pj_stun_server_destroy(pj_stun_server *srv)
{
unsigned i;
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
if (!srv->usage[i])
continue;
pj_stun_usage_destroy(srv->usage[i]);
pj_stun_server_unregister_usage(srv, srv->usage[i]);
}
srv->thread_quit_flag = PJ_TRUE;
for (i=0; i<srv->si.thread_cnt; ++i) {
pj_thread_join(srv->threads[i]);
srv->threads[i] = NULL;
}
pj_timer_heap_destroy(srv->si.timer_heap);
pj_ioqueue_destroy(srv->si.ioqueue);
pj_pool_release(srv->pool);
return PJ_SUCCESS;
}