Skip to content

Commit

Permalink
Add REUSE_PORT socket option
Browse files Browse the repository at this point in the history
This allows outgoing TCP connections to reuse a listening port as a source port.
This is useful for example when using "forced_socket" with the "uac_registrant"
module, or when using "force_send_socket()".

The behaviour of sockets that do not use the REUSE_PORT option is unchanged.
  • Loading branch information
jes committed Mar 24, 2023
1 parent baf0d2f commit cabe591
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 15 deletions.
6 changes: 4 additions & 2 deletions cfg.lex
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,9 @@ DOT \.
CR \n
ANY "any"
ANYCAST "anycast"
FRAG "frag"
ANYCAST ("anycast"|"ANYCAST")
FRAG ("frag"|"FRAG")
REUSE_PORT ("reuse_port"|"REUSE_PORT")
COM_LINE #
Expand Down Expand Up @@ -588,6 +589,7 @@ SPACE [ ]
<INITIAL>{CR} { count();/* return CR;*/ }
<INITIAL>{ANY} { count(); return ANY; }
<INITIAL>{ANYCAST} { count(); return ANYCAST; }
<INITIAL>{REUSE_PORT} { count(); return REUSE_PORT; }
<INITIAL>{FRAG} { count(); return FRAG; }
<INITIAL>{SLASH} { count(); return SLASH; }
<INITIAL>{SCALE_UP_TO} { count(); return SCALE_UP_TO; }
Expand Down
4 changes: 4 additions & 0 deletions cfg.y
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ extern int cfg_parse_only_routes;
%token ANY
%token ANYCAST
%token FRAG
%token REUSE_PORT
%token SCRIPTVARERR
%token SCALE_UP_TO
%token SCALE_DOWN_TO
Expand Down Expand Up @@ -643,6 +644,9 @@ socket_def_param: ANYCAST { IFOR();
| FRAG { IFOR();
p_tmp.flags |= SI_FRAG;
}
| REUSE_PORT { IFOR();
p_tmp.flags |= SI_REUSEPORT;
}
| USE_WORKERS NUMBER { IFOR();
p_tmp.workers=$2;
}
Expand Down
2 changes: 1 addition & 1 deletion ip_addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ union sockaddr_union{


enum si_flags { SI_NONE=0, SI_IS_IP=1, SI_IS_LO=2, SI_IS_MCAST=4,
SI_IS_ANYCAST=8, SI_FRAG=16 };
SI_IS_ANYCAST=8, SI_FRAG=16, SI_REUSEPORT=32 };

struct receive_info {
struct ip_addr src_ip;
Expand Down
2 changes: 1 addition & 1 deletion modules/cgrates/cgrates_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ static int cgrc_conn(struct cgr_conn *c)

tcp_con_get_profile(&c->engine->su, src_su, PROTO_TCP, &prof);

s = tcp_sync_connect_fd(src_su, &c->engine->su, PROTO_TCP, &prof);
s = tcp_sync_connect_fd(src_su, &c->engine->su, PROTO_TCP, &prof, 0);
if (s < 0) {
LM_ERR("cannot connect to %.*s:%d\n", c->engine->host.len,
c->engine->host.s, c->engine->port);
Expand Down
2 changes: 1 addition & 1 deletion modules/proto_ws/ws_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ static struct tcp_connection* ws_sync_connect(struct socket_info* send_sock,
goto error;
}

if (tcp_init_sock_opt(s, prof)<0){
if (tcp_init_sock_opt(s, prof, send_sock->flags)<0){
LM_ERR("tcp_init_sock_opt failed\n");
goto error;
}
Expand Down
21 changes: 19 additions & 2 deletions net/net_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,24 @@ static inline int init_sock_keepalive(int s, struct tcp_conn_profile *prof)
return 0;
}

static inline void set_sock_reuseport(int s)
{
int yes = 1;

if (setsockopt(s,SOL_SOCKET,SO_REUSEPORT,&yes,sizeof(yes))<0){
LM_WARN("setsockopt failed to set SO_REUSEPORT: %s\n",
strerror(errno));
}
if (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))<0){
LM_WARN("setsockopt failed to set SO_REUSEADDR: %s\n",
strerror(errno));
}
}

/*! \brief Set all socket/fd options: disable nagle, tos lowdelay,
* non-blocking
* \return -1 on error */
int tcp_init_sock_opt(int s, struct tcp_conn_profile *prof)
int tcp_init_sock_opt(int s, struct tcp_conn_profile *prof, enum si_flags socketflags)
{
int flags;
int optval;
Expand All @@ -235,6 +248,8 @@ int tcp_init_sock_opt(int s, struct tcp_conn_profile *prof)
}

init_sock_keepalive(s, prof);
if (socketflags & SI_REUSEPORT)
set_sock_reuseport(s);

/* non-blocking */
flags=fcntl(s, F_GETFL);
Expand Down Expand Up @@ -363,6 +378,8 @@ int tcp_init_listener(struct socket_info *si)
}

init_sock_keepalive(si->socket, &tcp_con_df_profile);
if (si->flags & SI_REUSEPORT)
set_sock_reuseport(si->socket);
if (bind(si->socket, &addr->s, sockaddru_len(*addr))==-1){
LM_ERR("bind(%x, %p, %d) on %s:%d : %s\n",
si->socket, &addr->s,
Expand Down Expand Up @@ -1071,7 +1088,7 @@ static inline int handle_new_connect(struct socket_info* si)
}

tcp_con_get_profile(&su, &si->su, si->proto, &prof);
if (tcp_init_sock_opt(new_sock, &prof)<0){
if (tcp_init_sock_opt(new_sock, &prof, si->flags)<0){
LM_ERR("tcp_init_sock_opt failed\n");
close(new_sock);
return 1; /* success, because the accept was successful */
Expand Down
2 changes: 1 addition & 1 deletion net/net_tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ mi_response_t *mi_tcp_list_conns(const mi_params_t *params,
int tcp_init_listener(struct socket_info *si);

/* helper function to set all TCP related options to a socket */
int tcp_init_sock_opt(int s, struct tcp_conn_profile *prof);
int tcp_init_sock_opt(int s, struct tcp_conn_profile *prof, enum si_flags socketflags);

/********************** TCP conn management functions ************************/

Expand Down
14 changes: 8 additions & 6 deletions net/tcp_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ int tcp_connect_blocking(int fd, const struct sockaddr *servaddr,
}

int tcp_sync_connect_fd(union sockaddr_union* src, union sockaddr_union* dst,
enum sip_protos proto, struct tcp_conn_profile *prof)
enum sip_protos proto, struct tcp_conn_profile *prof, enum si_flags flags)
{
int s;
union sockaddr_union my_name;
Expand All @@ -153,15 +153,16 @@ int tcp_sync_connect_fd(union sockaddr_union* src, union sockaddr_union* dst,
goto error;
}

if (tcp_init_sock_opt(s, prof)<0){
if (tcp_init_sock_opt(s, prof, flags)<0){
LM_ERR("tcp_init_sock_opt failed\n");
goto error;
}

if (src) {
my_name_len = sockaddru_len(*src);
memcpy( &my_name, src, my_name_len);
su_setport( &my_name, 0);
if (!(flags & SI_REUSEPORT))
su_setport( &my_name, 0);
if (bind(s, &my_name.s, my_name_len )!=0) {
LM_ERR("bind failed (%d) %s\n", errno,strerror(errno));
goto error;
Expand All @@ -187,7 +188,7 @@ struct tcp_connection* tcp_sync_connect(struct socket_info* send_sock,
struct tcp_connection* con;
int s;

s = tcp_sync_connect_fd(&send_sock->su, server, send_sock->proto, prof);
s = tcp_sync_connect_fd(&send_sock->su, server, send_sock->proto, prof, send_sock->flags);
if (s < 0)
return NULL;

Expand Down Expand Up @@ -231,14 +232,15 @@ int tcp_async_connect(struct socket_info* send_sock,
return -1;
}

if (tcp_init_sock_opt(fd, prof)<0){
if (tcp_init_sock_opt(fd, prof, send_sock->flags)<0){
LM_ERR("tcp_init_sock_opt failed\n");
goto error;
}

my_name_len = sockaddru_len(send_sock->su);
memcpy( &my_name, &send_sock->su, my_name_len);
su_setport( &my_name, 0);
if (!(send_sock->flags & SI_REUSEPORT))
su_setport( &my_name, 0);
if (bind(fd, &my_name.s, my_name_len )!=0) {
LM_ERR("bind failed (%d) %s\n", errno,strerror(errno));
goto error;
Expand Down
2 changes: 1 addition & 1 deletion net/tcp_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ int tcp_connect_blocking_timeout(int fd, const struct sockaddr *servaddr,


int tcp_sync_connect_fd(union sockaddr_union* src, union sockaddr_union* dst,
enum sip_protos proto, struct tcp_conn_profile *prof);
enum sip_protos proto, struct tcp_conn_profile *prof, enum si_flags flags);

struct tcp_connection* tcp_sync_connect(struct socket_info* send_sock,
union sockaddr_union* server, struct tcp_conn_profile *prof,
Expand Down

0 comments on commit cabe591

Please sign in to comment.