Module: sip-router
Branch: andrei/raw_sock
Commit: 22e7e32e343724a42abc4c0c1b7986e88e50111b
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=22e7e32…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Tue Jun 15 16:36:14 2010 +0200
raw sockets: udp send will use now raw sockets if enabled
A raw socket, that will be used for sending, is now initialized on
startup. The operation can succeed only if sr is started as root
or with CAP_NET_RAW.
If the initialization fails and the raw sockets are forced on from
the config (udp4_raw = 1), ser won't start. If the raw socket are
in auto mode (udp4_raw = -1), sr will start, but with the raw
socket send part disabled (normal udp send will be used).
If the raw socket part is not disabled at startup, it can be
turned anytime on/off via the runtime cfg. framework.
Note: the raw socket send is supported only over ipv4 and for now
only on linux.
---
main.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
udp_server.c | 69 ++++++++++++++++++++++++++++++++++++--------------
2 files changed, 119 insertions(+), 29 deletions(-)
diff --git a/main.c b/main.c
index 7d28bcd..a90e855 100644
--- a/main.c
+++ b/main.c
@@ -73,16 +73,15 @@
* 2008-08-08 sctp support (andrei)
* 2008-08-19 -l support for mmultihomed addresses/addresses lists
* (e.g. -l (eth0, 1.2.3.4, foo.bar) ) (andrei)
- * 2010-04-19 added daemon_status_fd pipe to communicate the parent process with
- the main process in daemonize mode, so the parent process can return
- the proper exit status code (ibc)
+ * 2010-04-19 added daemon_status_fd pipe to communicate the parent process
+ * with the main process in daemonize mode, so the parent process
+ * can return the proper exit status code (ibc)
*/
-/*!
- * \file
- * \brief SIP-router core ::
- * \ingroup core
- * Module: \ref core
+/** intializations and startup.
+ * @file main.c
+ * @ingroup core
+ * Module: @ref core
*/
/*! \defgroup core SIP-router core
@@ -148,6 +147,9 @@
#include "nonsip_hooks.h"
#include "ut.h"
#include "signals.h"
+#ifdef USE_RAW_SOCKS
+#include "raw_sock.h"
+#endif /* USE_RAW_SOCKS */
#ifdef USE_TCP
#include "poll_types.h"
#include "tcp_init.h"
@@ -439,6 +441,9 @@ struct socket_info* bind_address=0; /* pointer to the crt. proc.
listening address*/
struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
struct socket_info* sendipv6; /* same as above for ipv6 */
+#ifdef USE_RAW_SOCKS
+int raw_udp4_send_sock = -1; /* raw socket used for sending udp4 packets */
+#endif /* USE_RAW_SOCKS */
#ifdef USE_TCP
struct socket_info* sendipv4_tcp;
struct socket_info* sendipv6_tcp;
@@ -1237,9 +1242,35 @@ int main_loop()
/* only one address, we ignore all the others */
if (udp_init(udp_listen)==-1) goto error;
bind_address=udp_listen;
- if (bind_address->address.af==AF_INET)
+ if (bind_address->address.af==AF_INET) {
sendipv4=bind_address;
- else
+#ifdef USE_RAW_SOCKS
+ /* always try to have a raw socket opened if we are using ipv4 */
+ raw_udp4_send_sock = raw_socket(IPPROTO_RAW, 0, 0, 1);
+ if (raw_udp4_send_sock < 0) {
+ if ( default_core_cfg.udp4_raw > 0) {
+ /* force use raw socket failed */
+ ERR("could not initialize raw udp send socket (ipv4):"
+ " %s (%d)\n", strerror(errno), errno);
+ if (errno == EPERM)
+ ERR("could not initialize raw socket on startup"
+ " due to inadequate permissions, please"
+ " restart as root or with CAP_NET_RAW\n");
+ goto error;
+ }
+ default_core_cfg.udp4_raw = 0; /* disabled */
+ } else {
+ register_fds(1);
+ if (default_core_cfg.udp4_raw < 0) {
+ /* auto-detect => use it */
+ default_core_cfg.udp4_raw = 1; /* enabled */
+ DBG("raw socket possible => turning it on\n");
+ }
+ }
+#else
+ default_core.cfg.udp4_raw = 0;
+#endif /* USE_RAW_SOCKS */
+ } else
sendipv6=bind_address;
if (udp_listen->next){
LOG(L_WARN, "WARNING: using only the first listen address"
@@ -1363,6 +1394,34 @@ int main_loop()
/* children_no per each socket */
cfg_register_child(children_no);
}
+#ifdef USE_RAW_SOCKS
+ /* always try to have a raw socket opened if we are using ipv4 */
+ if (sendipv4) {
+ raw_udp4_send_sock = raw_socket(IPPROTO_RAW, 0, 0, 1);
+ if (raw_udp4_send_sock < 0) {
+ if ( default_core_cfg.udp4_raw > 0) {
+ /* force use raw socket failed */
+ ERR("could not initialize raw udp send socket (ipv4):"
+ " %s (%d)\n", strerror(errno), errno);
+ if (errno == EPERM)
+ ERR("could not initialize raw socket on startup"
+ " due to inadequate permissions, please"
+ " restart as root or with CAP_NET_RAW\n");
+ goto error;
+ }
+ default_core_cfg.udp4_raw = 0; /* disabled */
+ } else {
+ register_fds(1);
+ if (default_core_cfg.udp4_raw < 0) {
+ /* auto-detect => use it */
+ default_core_cfg.udp4_raw = 1; /* enabled */
+ DBG("raw socket possible => turning it on\n");
+ }
+ }
+ }
+#else
+ default_core_cfg.udp4_raw = 0;
+#endif /* USE_RAW_SOCKS */
#ifdef USE_SCTP
if (!sctp_disable){
for(si=sctp_listen; si; si=si->next){
diff --git a/udp_server.c b/udp_server.c
index a54a4fe..d4a9d7b 100644
--- a/udp_server.c
+++ b/udp_server.c
@@ -41,14 +41,14 @@
* 2007-08-28 disable/set MTU discover option for the udp sockets
* (in linux it's enabled by default which produces udp packets
* with the DF flag ser) (patch from hscholz)
+ * 2010-06-15 support for using raw sockets for sending (andrei)
*/
-/*!
- * \file
- * \brief SIP-router core ::
- * \ingroup core
- * Module: \ref core
+/** udp send and loop-receive functions.
+ * @file udp_server.c
+ * @ingroup core
+ * Module: @ref core
*/
#include <stdlib.h>
@@ -67,6 +67,7 @@
#include "udp_server.h"
+#include "compiler_opt.h"
#include "globals.h"
#include "config.h"
#include "dprint.h"
@@ -74,6 +75,10 @@
#include "mem/mem.h"
#include "ip_addr.h"
#include "cfg/cfg_struct.h"
+#ifdef USE_RAW_SOCKS
+#include "raw_sock.h"
+#endif /* USE_RAW_SOCKS */
+
#ifdef USE_STUN
#include "ser_stun.h"
@@ -551,6 +556,9 @@ int udp_send(struct dest_info* dst, char *buf, unsigned len)
int n;
int tolen;
struct ip_addr ip; /* used only on error, for debugging */
+#ifdef USE_RAW_SOCKS
+ int mtu;
+#endif /* USE_RAW_SOCKS */
#ifdef DBG_MSG_QA
/* aborts on error, does nothing otherwise */
@@ -559,24 +567,47 @@ int udp_send(struct dest_info* dst, char *buf, unsigned len)
abort();
}
#endif
-
- tolen=sockaddru_len(dst->to);
+#ifdef USE_RAW_SOCKS
+ if (likely( ! (raw_udp4_send_sock >= 0 &&
+ cfg_get(core, core_cfg, udp4_raw) &&
+ dst->send_sock->address.af == AF_INET) )) {
+#endif /* USE_RAW_SOCKS */
+ /* normal send over udp socket */
+ tolen=sockaddru_len(dst->to);
again:
- n=sendto(dst->send_sock->socket, buf, len, 0, &dst->to.s, tolen);
+ n=sendto(dst->send_sock->socket, buf, len, 0, &dst->to.s, tolen);
#ifdef XL_DEBUG
- LOG(L_INFO, "INFO: send status: %d\n", n);
+ LOG(L_INFO, "INFO: send status: %d\n", n);
#endif
- if (n==-1){
- su2ip_addr(&ip, &dst->to);
- LOG(L_ERR, "ERROR: udp_send: sendto(sock,%p,%u,0,%s:%d,%d): %s(%d)\n",
- buf,len, ip_addr2a(&ip), su_getport(&dst->to), tolen,
- strerror(errno),errno);
- if (errno==EINTR) goto again;
- if (errno==EINVAL) {
- LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
- "one possible reason is the server is bound to localhost and\n"
- "attempts to send to the net\n");
+ if (unlikely(n==-1)){
+ su2ip_addr(&ip, &dst->to);
+ LOG(L_ERR, "ERROR: udp_send: sendto(sock,%p,%u,0,%s:%d,%d):"
+ " %s(%d)\n", buf,len, ip_addr2a(&ip),
+ su_getport(&dst->to), tolen, strerror(errno), errno);
+ if (errno==EINTR) goto again;
+ if (errno==EINVAL) {
+ LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
+ "one possible reason is the server is bound to localhost and\n"
+ "attempts to send to the net\n");
+ }
+ }
+#ifdef USE_RAW_SOCKS
+ } else {
+ /* send over a raw socket */
+ mtu = cfg_get(core, core_cfg, udp4_raw_mtu);
+raw_again:
+ n=raw_iphdr_udp4_send(raw_udp4_send_sock, buf, len,
+ &dst->send_sock->su,
+ &dst->to,
+ mtu);
+ if (unlikely(n==-1)){
+ su2ip_addr(&ip, &dst->to);
+ LOG(L_ERR, "ERROR: raw_udp4_send(sock,%p,%u,...,%s:%d,%d):"
+ " %s(%d)\n", buf,len, ip_addr2a(&ip),
+ su_getport(&dst->to), mtu, strerror(errno), errno);
+ if (errno==EINTR) goto raw_again;
}
}
+#endif /* USE_RAW_SOCKS */
return n;
}