core: Changed WS from being a flag on a TCP/TLS connection to a protocol in its own...
[sip-router] / udp_server.c
index a28e88c..3889a65 100644 (file)
  *  2005-06-26  failure to set mcast options is not an error anymore (andrei)
  *  2006-04-12  udp_send() switched to struct dest_info (andrei)
  *  2006-10-13  added STUN support (vlada)
+ *  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)
  */
 
 
+/** udp send and loop-receive functions.
+ * @file udp_server.c
+ * @ingroup core
+ * Module: @ref core
+ */
+
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 
 
 #include "udp_server.h"
+#include "compiler_opt.h"
 #include "globals.h"
 #include "config.h"
 #include "dprint.h"
 #include "receive.h"
 #include "mem/mem.h"
 #include "ip_addr.h"
+#include "cfg/cfg_struct.h"
+#include "events.h"
+#ifdef USE_RAW_SOCKS
+#include "raw_sock.h"
+#endif /* USE_RAW_SOCKS */
+
 
 #ifdef USE_STUN
   #include "ser_stun.h"
@@ -309,7 +326,7 @@ int udp_init(struct socket_info* sock_info)
                LOG(L_WARN, "WARNING: udp_init: setsockopt tos: %s\n", strerror(errno));
                /* continue since this is not critical */
        }
-#if defined (__linux__) && defined(UDP_ERRORS)
+#if defined (__OS_linux) && defined(UDP_ERRORS)
        optval=1;
        /* enable error receiving on unconnected sockets */
        if(setsockopt(sock_info->socket, SOL_IP, IP_RECVERR,
@@ -318,6 +335,16 @@ int udp_init(struct socket_info* sock_info)
                goto error;
        }
 #endif
+#if defined (__OS_linux)
+       /* if pmtu_discovery=1 then set DF bit and do Path MTU discovery
+        * disabled by default */
+       optval= (pmtu_discovery) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+       if(setsockopt(sock_info->socket, IPPROTO_IP, IP_MTU_DISCOVER,
+                       (void*)&optval, sizeof(optval)) ==-1){
+               LOG(L_ERR, "ERROR: udp_init: setsockopt: %s\n", strerror(errno));
+               goto error;
+       }
+#endif
 
 #ifdef USE_MCAST
        if ((sock_info->flags & SI_IS_MCAST) 
@@ -415,6 +442,10 @@ int udp_rcv_loop()
        ri.dst_ip=bind_address->address;
        ri.proto=PROTO_UDP;
        ri.proto_reserved1=ri.proto_reserved2=0;
+
+       /* initialize the config framework */
+       if (cfg_child_init()) goto error;
+
        for(;;){
 #ifdef DYN_BUF
                buf=pkg_malloc(BUF_SIZE+1);
@@ -445,6 +476,17 @@ int udp_rcv_loop()
                su2ip_addr(&ri.src_ip, from);
                ri.src_port=su_getport(from);
 
+               if(unlikely(sr_event_enabled(SREV_NET_DGRAM_IN)))
+               {
+                       void *sredp[3];
+                       sredp[0] = (void*)buf;
+                       sredp[1] = (void*)(&len);
+                       sredp[2] = (void*)(&ri);
+                       if(sr_event_exec(SREV_NET_DGRAM_IN, (void*)sredp)<0) {
+                               /* data handled by callback - continue to next packet */
+                               continue;
+                       }
+               }
 #ifndef NO_ZERO_CHECKS
 #ifdef USE_STUN
                /* STUN support can be switched off even if it's compiled */
@@ -459,7 +501,12 @@ int udp_rcv_loop()
 #ifdef USE_STUN
                }
 #endif
-#ifndef USE_STUN
+/* historically, zero-terminated packets indicated a bug in clients
+ * that calculated wrongly packet length and included string-terminating
+ * zero; today clients exist with legitimate binary payloads and we
+ * shall not check for zero-terminated payloads
+ */
+#ifdef TRASH_ZEROTERMINATED_PACKETS
                if (buf[len-1]==0) {
                        tmp=ip_addr2a(&ri.src_ip);
                        LOG(L_WARN, "WARNING: udp_rcv_loop: "
@@ -482,6 +529,8 @@ int udp_rcv_loop()
                        continue;
                }
                
+               /* update the local config */
+               cfg_update();
 #ifdef USE_STUN
                        /* STUN support can be switched off even if it's compiled */
                        if (stun_allow_stun && (unsigned char)*buf == 0x00) {
@@ -519,6 +568,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 */
@@ -527,24 +579,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,%d,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_iphdr_udp4_send(%d,%p,%u,...,%s:%d,%d):"
+                                       " %s(%d)\n", raw_udp4_send_sock, 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;
 }