open5gs/lib/sbi/server.c

214 lines
5.8 KiB
C

/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 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, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-app.h"
#include "ogs-sbi.h"
extern const ogs_sbi_server_actions_t ogs_mhd_server_actions;
extern const ogs_sbi_server_actions_t ogs_nghttp2_server_actions;
ogs_sbi_server_actions_t ogs_sbi_server_actions;
bool ogs_sbi_server_actions_initialized = false;
static OGS_POOL(server_pool, ogs_sbi_server_t);
void ogs_sbi_server_init(int num_of_session_pool, int num_of_stream_pool)
{
if (ogs_sbi_server_actions_initialized == false) {
#if 1 /* Use HTTP2 */
ogs_sbi_server_actions = ogs_nghttp2_server_actions;
#else
ogs_sbi_server_actions = ogs_mhd_server_actions;
#endif
}
ogs_sbi_server_actions.init(num_of_session_pool, num_of_stream_pool);
ogs_list_init(&ogs_sbi_self()->server_list);
ogs_pool_init(&server_pool, ogs_app()->pool.nf);
}
void ogs_sbi_server_final(void)
{
ogs_sbi_server_remove_all();
ogs_pool_final(&server_pool);
ogs_sbi_server_actions.cleanup();
}
ogs_sbi_server_t *ogs_sbi_server_add(
ogs_sockaddr_t *addr, ogs_sockopt_t *option)
{
ogs_sbi_server_t *server = NULL;
ogs_assert(addr);
ogs_pool_alloc(&server_pool, &server);
ogs_assert(server);
memset(server, 0, sizeof(ogs_sbi_server_t));
ogs_assert(OGS_OK == ogs_copyaddrinfo(&server->node.addr, addr));
if (option)
server->node.option = ogs_memdup(option, sizeof *option);
ogs_list_add(&ogs_sbi_self()->server_list, server);
return server;
}
void ogs_sbi_server_remove(ogs_sbi_server_t *server)
{
ogs_assert(server);
ogs_list_remove(&ogs_sbi_self()->server_list, server);
ogs_assert(server->node.addr);
ogs_freeaddrinfo(server->node.addr);
if (server->node.option)
ogs_free(server->node.option);
if (server->advertise)
ogs_freeaddrinfo(server->advertise);
ogs_pool_free(&server_pool, server);
}
void ogs_sbi_server_remove_all(void)
{
ogs_sbi_server_t *server = NULL, *next_server = NULL;
ogs_list_for_each_safe(&ogs_sbi_self()->server_list, next_server, server)
ogs_sbi_server_remove(server);
}
void ogs_sbi_server_set_advertise(
ogs_sbi_server_t *server, int family, ogs_sockaddr_t *advertise)
{
ogs_sockaddr_t *addr = NULL;
ogs_assert(server);
ogs_assert(advertise);
ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise));
if (family != AF_UNSPEC)
ogs_filteraddrinfo(&addr, family);
if (addr)
server->advertise = addr;
}
int ogs_sbi_server_start_all(
int (*cb)(ogs_sbi_request_t *request, void *data))
{
ogs_sbi_server_t *server = NULL, *next_server = NULL;
ogs_list_for_each_safe(&ogs_sbi_self()->server_list, next_server, server)
if (ogs_sbi_server_actions.start(server, cb) != OGS_OK)
return OGS_ERROR;
return OGS_OK;
}
void ogs_sbi_server_stop_all(void)
{
ogs_sbi_server_t *server = NULL, *next_server = NULL;
ogs_list_for_each_safe(&ogs_sbi_self()->server_list, next_server, server)
ogs_sbi_server_actions.stop(server);
}
bool ogs_sbi_server_send_rspmem_persistent(
ogs_sbi_stream_t *stream, ogs_sbi_response_t *response)
{
return ogs_sbi_server_actions.send_rspmem_persistent(stream, response);
}
bool ogs_sbi_server_send_response(
ogs_sbi_stream_t *stream, ogs_sbi_response_t *response)
{
return ogs_sbi_server_actions.send_response(stream, response);
}
bool ogs_sbi_server_send_problem(
ogs_sbi_stream_t *stream, OpenAPI_problem_details_t *problem)
{
ogs_sbi_message_t message;
ogs_sbi_response_t *response = NULL;
ogs_assert(stream);
ogs_assert(problem);
memset(&message, 0, sizeof(message));
message.http.content_type = (char*)"application/problem+json";
message.ProblemDetails = problem;
response = ogs_sbi_build_response(&message, problem->status);
ogs_assert(response);
ogs_sbi_server_send_response(stream, response);
return true;
}
bool ogs_sbi_server_send_error(ogs_sbi_stream_t *stream,
int status, ogs_sbi_message_t *message,
const char *title, const char *detail)
{
OpenAPI_problem_details_t problem;
ogs_assert(stream);
memset(&problem, 0, sizeof(problem));
if (message) {
problem.type = ogs_msprintf("/%s/%s",
message->h.service.name, message->h.api.version);
ogs_expect_or_return_val(problem.type, false);
if (message->h.resource.component[1])
problem.instance = ogs_msprintf("/%s/%s",
message->h.resource.component[0],
message->h.resource.component[1]);
else
problem.instance =
ogs_msprintf("/%s", message->h.resource.component[0]);
ogs_expect_or_return_val(problem.instance, NULL);
}
if (status) {
problem.is_status = true;
problem.status = status;
}
problem.title = (char*)title;
problem.detail = (char*)detail;
ogs_sbi_server_send_problem(stream, &problem);
if (problem.type)
ogs_free(problem.type);
if (problem.instance)
ogs_free(problem.instance);
return true;
}
ogs_sbi_server_t *ogs_sbi_server_from_stream(ogs_sbi_stream_t *stream)
{
return ogs_sbi_server_actions.from_stream(stream);
}