00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <sys/types.h>
00039 #include <sys/socket.h>
00040 #include <netinet/in.h>
00041 #include <netinet/in_systm.h>
00042 #include <netinet/ip.h>
00043 #include <errno.h>
00044 #include <arpa/inet.h>
00045 #ifdef __linux__
00046 #include <linux/types.h>
00047 #include <linux/errqueue.h>
00048 #endif
00049
00050
00051 #include "udp_server.h"
00052 #include "globals.h"
00053 #include "config.h"
00054 #include "dprint.h"
00055 #include "receive.h"
00056 #include "mem/mem.h"
00057 #include "ip_addr.h"
00058
00059
00060 #ifdef DBG_MSG_QA
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 static int dbg_msg_qa(char *buf, int len)
00072 {
00073 #define _DBG_WS_LEN 3
00074 #define _DBG_WS " "
00075
00076 char *scan;
00077 int my_len, space_cnt;
00078 enum { QA_ANY, QA_SPACE, QA_EOL1 } state;
00079
00080 my_len=len;
00081 scan=buf;
00082 state=QA_ANY;
00083 space_cnt=0;
00084
00085 while(my_len) {
00086 switch(*scan) {
00087 case ' ': if (state==QA_SPACE) {
00088 space_cnt++;
00089 if (space_cnt==4) {
00090 LM_CRIT("too many spaces\n");
00091 return 0;
00092 }
00093 } else space_cnt=0;
00094 state=QA_SPACE;
00095 break;
00096
00097 case '\r':
00098 space_cnt=0;
00099 break;
00100
00101 case '\n':
00102 if (state==QA_EOL1) goto qa_passed;
00103 space_cnt=0;
00104 state=QA_EOL1;
00105 break;
00106
00107 default: space_cnt=0;
00108 state=QA_ANY;
00109 break;
00110 }
00111 scan++;
00112 my_len--;
00113 }
00114
00115
00116 qa_passed:
00117 return 1;
00118 }
00119
00120 #endif
00121
00122
00123
00124
00125
00126
00127
00128
00129 int probe_max_receive_buffer(int udp_sock)
00130 {
00131 unsigned int optval, ioptval, ioptvallen, foptval, foptvallen, voptval, voptvallen;
00132 int phase=0;
00133
00134
00135 ioptvallen=sizeof(ioptval);
00136 if (getsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF, (void*) &ioptval,
00137 &ioptvallen) == -1 )
00138 {
00139 LM_ERR("getsockopt: %s\n", strerror(errno));
00140 return -1;
00141 }
00142 if ( ioptval==0 )
00143 {
00144 LM_DBG(" getsockopt: SO_RCVBUF initially set to 0; resetting to %d\n",
00145 BUFFER_INCREMENT );
00146 ioptval=BUFFER_INCREMENT;
00147 } else LM_DBG("getsockopt SO_RCVBUF is initially %d\n", ioptval );
00148 for (optval=ioptval; ; ) {
00149
00150 if (phase==0) optval <<= 1; else optval+=BUFFER_INCREMENT;
00151 if (optval > maxbuffer){
00152 if (phase==1) break;
00153 else { phase=1; optval >>=1; continue; }
00154 }
00155 LM_DBG("trying SO_RCVBUF: %d\n", optval );
00156 if (setsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF,
00157 (void*)&optval, sizeof(optval)) ==-1){
00158
00159 LM_DBG("setsockopt: SOL_SOCKET failed"
00160 " for %d, phase %d: %s\n", optval, phase, strerror(errno));
00161
00162
00163 if (phase==0) { phase=1; optval >>=1 ; continue; }
00164 else break;
00165 }
00166
00167
00168
00169 voptvallen=sizeof(voptval);
00170 if (getsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF, (void*) &voptval,
00171 &voptvallen) == -1 )
00172 {
00173 LM_ERR("getsockopt: %s\n", strerror(errno));
00174 return -1;
00175 } else {
00176 LM_DBG("setting SO_RCVBUF; set=%d,verify=%d\n",
00177 optval, voptval);
00178 if (voptval<optval) {
00179 LM_DBG("setting SO_RCVBUF has no effect\n");
00180
00181
00182 if (phase==0) { phase=1; optval >>=1 ; continue; }
00183 else break;
00184 }
00185 }
00186
00187 }
00188 foptvallen=sizeof(foptval);
00189 if (getsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF, (void*) &foptval,
00190 &foptvallen) == -1 )
00191 {
00192 LM_ERR("getsockopt: %s\n", strerror(errno));
00193 return -1;
00194 }
00195 LM_INFO("using a UDP receive buffer of %d kb\n", (foptval/1024));
00196
00197 return 0;
00198 }
00199
00200
00201 #ifdef USE_MCAST
00202
00203
00204
00205
00206
00207
00208
00209 static int setup_mcast_rcvr(int sock, union sockaddr_union* addr)
00210 {
00211 struct ip_mreq mreq;
00212 #ifdef USE_IPV6
00213 struct ipv6_mreq mreq6;
00214 #endif
00215
00216 if (addr->s.sa_family==AF_INET){
00217 memcpy(&mreq.imr_multiaddr, &addr->sin.sin_addr,
00218 sizeof(struct in_addr));
00219 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
00220
00221 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq,
00222 sizeof(mreq))==-1){
00223 LM_ERR("setsockopt: %s\n", strerror(errno));
00224 return -1;
00225 }
00226
00227 #ifdef USE_IPV6
00228 } else if (addr->s.sa_family==AF_INET6){
00229 memcpy(&mreq6.ipv6mr_multiaddr, &addr->sin6.sin6_addr,
00230 sizeof(struct in6_addr));
00231 mreq6.ipv6mr_interface = 0;
00232 #ifdef __OS_linux
00233 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6,
00234 #else
00235 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
00236 #endif
00237 sizeof(mreq6))==-1){
00238 LM_ERR("setsockopt:%s\n", strerror(errno));
00239 return -1;
00240 }
00241
00242 #endif
00243 } else {
00244 LM_ERR("unsupported protocol family\n");
00245 return -1;
00246 }
00247 return 0;
00248 }
00249
00250 #endif
00251
00252
00253
00254
00255
00256
00257 int udp_init(struct socket_info* sock_info)
00258 {
00259 union sockaddr_union* addr;
00260 int optval;
00261 #ifdef USE_MCAST
00262 unsigned char m_optval;
00263 #endif
00264
00265 addr=&sock_info->su;
00266 sock_info->proto=PROTO_UDP;
00267 if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
00268 LM_ERR("could not init sockaddr_union\n");
00269 goto error;
00270 }
00271
00272 sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_DGRAM, 0);
00273 if (sock_info->socket==-1){
00274 LM_ERR("socket: %s\n", strerror(errno));
00275 goto error;
00276 }
00277
00278 optval=1;
00279 if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR ,
00280 (void*)&optval, sizeof(optval)) ==-1){
00281 LM_ERR("setsockopt: %s\n", strerror(errno));
00282 goto error;
00283 }
00284
00285 optval=tos;
00286 if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval,
00287 sizeof(optval)) ==-1){
00288 LM_WARN("setsockopt tos: %s\n", strerror(errno));
00289
00290 }
00291 #if defined (__linux__) && defined(UDP_ERRORS)
00292 optval=1;
00293
00294 if(setsockopt(sock_info->socket, SOL_IP, IP_RECVERR,
00295 (void*)&optval, sizeof(optval)) ==-1){
00296 LM_ERR("setsockopt: %s\n", strerror(errno));
00297 goto error;
00298 }
00299 #endif
00300
00301 #ifdef USE_MCAST
00302 if ((sock_info->flags & SI_IS_MCAST)
00303 && (setup_mcast_rcvr(sock_info->socket, addr)<0)){
00304 goto error;
00305 }
00306
00307 if (addr->s.sa_family==AF_INET){
00308 m_optval = mcast_loopback;
00309 if (setsockopt(sock_info->socket, IPPROTO_IP, IP_MULTICAST_LOOP,
00310 &m_optval, sizeof(m_optval))==-1){
00311 LM_WARN("setsockopt(IP_MULTICAST_LOOP): %s\n", strerror(errno));
00312
00313
00314 }
00315 if (mcast_ttl>=0){
00316 m_optval = mcast_ttl;
00317 if (setsockopt(sock_info->socket, IPPROTO_IP, IP_MULTICAST_TTL,
00318 &m_optval, sizeof(m_optval))==-1){
00319 LM_ERR("setsockopt (IP_MULTICAST_TTL): %s\n", strerror(errno));
00320 goto error;
00321 }
00322 }
00323 #ifdef USE_IPV6
00324 } else if (addr->s.sa_family==AF_INET6){
00325 if (setsockopt(sock_info->socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
00326 &mcast_loopback, sizeof(mcast_loopback))==-1){
00327 LM_WARN("setsockopt (IPV6_MULTICAST_LOOP): %s\n", strerror(errno));
00328
00329
00330 }
00331 if (mcast_ttl>=0){
00332 if (setsockopt(sock_info->socket, IPPROTO_IP, IPV6_MULTICAST_HOPS,
00333 &mcast_ttl, sizeof(mcast_ttl))==-1){
00334 LM_ERR("setssckopt (IPV6_MULTICAST_HOPS): %s\n",
00335 strerror(errno));
00336 goto error;
00337 }
00338 }
00339 #endif
00340 } else {
00341 LM_ERR("unsupported protocol family %d\n", addr->s.sa_family);
00342 goto error;
00343 }
00344 #endif
00345
00346 if (probe_max_receive_buffer(sock_info->socket)==-1) goto error;
00347
00348 if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
00349 LM_ERR("bind(%x, %p, %d) on %s: %s\n", sock_info->socket, &addr->s,
00350 (unsigned)sockaddru_len(*addr), sock_info->address_str.s,
00351 strerror(errno));
00352 #ifdef USE_IPV6
00353 if (addr->s.sa_family==AF_INET6)
00354 LM_ERR("might be caused by using a link "
00355 " local address, try site local or global\n");
00356 #endif
00357 goto error;
00358 }
00359 return 0;
00360
00361 error:
00362 return -1;
00363 }
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 int udp_rcv_loop(void)
00376 {
00377 int len;
00378 #ifdef DYN_BUF
00379 char* buf;
00380 #else
00381 static char buf [BUF_SIZE+1];
00382 #endif
00383 char *tmp;
00384 union sockaddr_union* from;
00385 unsigned int fromlen;
00386 struct receive_info ri;
00387
00388 from=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union));
00389 if (from==0){
00390 LM_ERR("out of pkg memory\n");
00391 goto error;
00392 }
00393 memset(from, 0 , sizeof(union sockaddr_union));
00394 ri.bind_address=bind_address;
00395 ri.dst_port=bind_address->port_no;
00396 ri.dst_ip=bind_address->address;
00397 ri.proto=PROTO_UDP;
00398 ri.proto_reserved1=ri.proto_reserved2=0;
00399 for(;;){
00400 #ifdef DYN_BUF
00401 buf=pkg_malloc(BUF_SIZE+1);
00402 if (buf==0){
00403 LM_ERR("could not allocate receive buffer\n");
00404 goto error;
00405 }
00406 #endif
00407 fromlen=sockaddru_len(bind_address->su);
00408 len=recvfrom(bind_address->socket, buf, BUF_SIZE, 0, &from->s,
00409 &fromlen);
00410 if (len==-1){
00411 if (errno==EAGAIN){
00412 LM_DBG("packet with bad checksum received\n");
00413 continue;
00414 }
00415 LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno));
00416 if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
00417 continue;
00418 else goto error;
00419 }
00420
00421 buf[len]=0;
00422
00423 ri.src_su=*from;
00424 su2ip_addr(&ri.src_ip, from);
00425 ri.src_port=su_getport(from);
00426
00427 #ifndef NO_ZERO_CHECKS
00428 if (len<MIN_UDP_PACKET) {
00429 tmp=ip_addr2a(&ri.src_ip);
00430 LM_DBG("probing packet received from %s %d\n",
00431 tmp, htons(ri.src_port));
00432 continue;
00433 }
00434 #endif
00435 #ifdef DBG_MSG_QA
00436 if (!dbg_msg_qa(buf, len)) {
00437 LM_WARN("an incoming message didn't pass test,"
00438 " drop it: %.*s\n", len, buf );
00439 continue;
00440 }
00441 #endif
00442 if (ri.src_port==0){
00443 tmp=ip_addr2a(&ri.src_ip);
00444 LM_INFO("dropping 0 port packet from %s\n", tmp);
00445 continue;
00446 }
00447
00448
00449 receive_msg(buf, len, &ri);
00450
00451
00452 }
00453
00454 error:
00455 if (from) pkg_free(from);
00456 return -1;
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469 int udp_send(struct socket_info *source, char *buf, unsigned len,
00470 union sockaddr_union* to)
00471 {
00472 int n, tolen;
00473
00474 #ifdef DBG_MSG_QA
00475
00476 if (!dbg_msg_qa( buf, len )) {
00477 LM_ERR("dbg_msg_qa failed\n");
00478 abort();
00479 }
00480 #endif
00481
00482 tolen=sockaddru_len(*to);
00483 again:
00484 n=sendto(source->socket, buf, len, 0, &to->s, tolen);
00485 #ifdef XL_DEBUG
00486 LM_INFO("status: %d\n", n);
00487 #endif
00488 if (n==-1){
00489 LM_ERR("sendto(sock,%p,%d,0,%p,%d): %s(%d)\n", buf,len,to,tolen,
00490 strerror(errno),errno);
00491 if (errno==EINTR) goto again;
00492 if (errno==EINVAL) {
00493 LM_CRIT("invalid sendtoparameters\n"
00494 "one possible reason is the server is bound to localhost and\n"
00495 "attempts to send to the net\n");
00496 }
00497 }
00498 return n;
00499 }