197 lines
5.2 KiB
C
197 lines
5.2 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 "core-config-private.h"
|
|
|
|
#if HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#if HAVE_NETINET_TCP_H
|
|
#include <netinet/tcp.h>
|
|
#endif
|
|
|
|
#include "ogs-core.h"
|
|
|
|
#undef OGS_LOG_DOMAIN
|
|
#define OGS_LOG_DOMAIN __ogs_sock_domain
|
|
|
|
void ogs_sockopt_init(ogs_sockopt_t *option)
|
|
{
|
|
ogs_assert(option);
|
|
|
|
memset(option, 0, sizeof *option);
|
|
|
|
option->sctp.spp_hbinterval = 5000; /* 5 seconds */
|
|
option->sctp.spp_sackdelay = 200; /* 200 ms */
|
|
option->sctp.srto_initial = 3000; /* 3 seconds */
|
|
option->sctp.srto_min = 1000; /* 1 seconds */
|
|
option->sctp.srto_max = 5000; /* 5 seconds */
|
|
option->sctp.sinit_num_ostreams = OGS_DEFAULT_SCTP_MAX_NUM_OF_OSTREAMS;
|
|
option->sctp.sinit_max_instreams = 65535;
|
|
option->sctp.sinit_max_attempts = 4;
|
|
option->sctp.sinit_max_init_timeo = 8000; /* 8 seconds */
|
|
|
|
option->sctp_nodelay = true;
|
|
option->tcp_nodelay = true;
|
|
}
|
|
|
|
int ogs_nonblocking(ogs_socket_t fd)
|
|
{
|
|
#ifdef _WIN32
|
|
int rc;
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
|
|
u_long io_mode = 1;
|
|
rc = ioctlsocket(fd, FIONBIO, &io_mode);
|
|
if (rc != OGS_OK) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "ioctlsocket failed");
|
|
return OGS_ERROR;
|
|
}
|
|
#else
|
|
int rc;
|
|
int flags;
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
|
|
flags = fcntl(fd, F_GETFL, NULL);
|
|
if (flags < 0) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "F_GETFL failed");
|
|
return OGS_ERROR;
|
|
}
|
|
if (!(flags & O_NONBLOCK)) {
|
|
rc = fcntl(fd, F_SETFL, (flags | O_NONBLOCK));
|
|
if (rc != OGS_OK) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "F_SETFL failed");
|
|
return OGS_ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return OGS_OK;
|
|
}
|
|
|
|
int ogs_closeonexec(ogs_socket_t fd)
|
|
{
|
|
#ifndef _WIN32
|
|
int rc;
|
|
int flags;
|
|
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
flags = fcntl(fd, F_GETFD, NULL);
|
|
if (flags < 0) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "F_GETFD failed");
|
|
return OGS_ERROR;
|
|
}
|
|
if (!(flags & FD_CLOEXEC)) {
|
|
rc = fcntl(fd, F_SETFD, (flags | FD_CLOEXEC));
|
|
if (rc != OGS_OK) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "F_SETFD failed");
|
|
return OGS_ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return OGS_OK;
|
|
}
|
|
|
|
int ogs_listen_reusable(ogs_socket_t fd, int on)
|
|
{
|
|
#if defined(SO_REUSEADDR) && !defined(_WIN32)
|
|
int rc;
|
|
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
|
|
ogs_debug("Turn on SO_REUSEADDR");
|
|
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(int));
|
|
if (rc != OGS_OK) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
|
"setsockopt(SOL_SOCKET, SO_REUSEADDR) failed");
|
|
return OGS_ERROR;
|
|
}
|
|
#endif
|
|
|
|
return OGS_OK;
|
|
}
|
|
|
|
int ogs_tcp_nodelay(ogs_socket_t fd, int on)
|
|
{
|
|
#if defined(TCP_NODELAY) && !defined(_WIN32)
|
|
int rc;
|
|
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
|
|
ogs_debug("Turn on TCP_NODELAY");
|
|
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(int));
|
|
if (rc != OGS_OK) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
|
"setsockopt(IPPROTO_TCP, TCP_NODELAY) failed");
|
|
return OGS_ERROR;
|
|
}
|
|
#endif
|
|
|
|
return OGS_OK;
|
|
}
|
|
|
|
int ogs_so_linger(ogs_socket_t fd, int l_linger)
|
|
{
|
|
#if defined(SO_LINGER) && !defined(_WIN32)
|
|
struct linger l;
|
|
int rc;
|
|
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
|
|
memset(&l, 0, sizeof(l));
|
|
l.l_onoff = 1;
|
|
l.l_linger = l_linger;
|
|
|
|
ogs_debug("SO_LINGER:[%d]", l_linger);
|
|
rc = setsockopt(fd, SOL_SOCKET, SO_LINGER,
|
|
(void *)&l, sizeof(struct linger));
|
|
if (rc != OGS_OK) {
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
|
"setsockopt(SOL_SOCKET, SO_LINGER) failed");
|
|
return OGS_ERROR;
|
|
}
|
|
#endif
|
|
|
|
return OGS_OK;
|
|
}
|
|
|
|
int ogs_bind_to_device(ogs_socket_t fd, const char *device)
|
|
{
|
|
#if defined(SO_BINDTODEVICE) && !defined(_WIN32)
|
|
int rc;
|
|
|
|
ogs_assert(fd != INVALID_SOCKET);
|
|
ogs_assert(device);
|
|
|
|
ogs_debug("SO_BINDTODEVICE:[%s]", device);
|
|
rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1);
|
|
if (rc != OGS_OK) {
|
|
int err = ogs_errno;
|
|
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
|
|
"setsockopt(SOL_SOCKET, SO_BINDTODEVICE, %s) failed", device);
|
|
if (err == OGS_EPERM)
|
|
ogs_error("You need to grant CAP_NET_RAW privileges to use SO_BINDTODEVICE.");
|
|
return OGS_ERROR;
|
|
}
|
|
#endif
|
|
|
|
return OGS_OK;
|
|
}
|