udp_server.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 Fhg Fokus
  5. *
  6. * This file is part of ser, a free SIP server.
  7. *
  8. * ser is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * For a license to use the ser software under conditions
  14. * other than those described here, or to purchase support for this
  15. * software, please contact iptel.org by e-mail at the following addresses:
  16. * [email protected]
  17. *
  18. * ser is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  26. */
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <sys/types.h>
  30. #include <sys/socket.h>
  31. #include <netinet/in.h>
  32. #include <errno.h>
  33. #include <arpa/inet.h>
  34. #ifdef __linux__
  35. #include <linux/types.h>
  36. #include <linux/errqueue.h>
  37. #endif
  38. #include "udp_server.h"
  39. #include "globals.h"
  40. #include "config.h"
  41. #include "dprint.h"
  42. #include "receive.h"
  43. #include "mem/mem.h"
  44. #include "ip_addr.h"
  45. #ifdef DEBUG_DMALLOC
  46. #include <mem/dmalloc.h>
  47. #endif
  48. #ifdef DBG_MSG_QA
  49. /* message quality assurance -- frequently, bugs in ser have
  50. been indicated by zero characters or long whitespaces
  51. in generated messages; this debugging option aborts if
  52. any such message is sighted
  53. */
  54. static int dbg_msg_qa(char *buf, int len)
  55. {
  56. #define _DBG_WS_LEN 3
  57. #define _DBG_WS " "
  58. char *scan;
  59. int my_len;
  60. int space_cnt;
  61. enum { QA_ANY, QA_SPACE, QA_EOL1 } state;
  62. /* is there a zero character inthere ? */
  63. if (memchr(buf, 0, len)) {
  64. LOG(L_CRIT, "BUG: message with 0 in it\n");
  65. return 0;
  66. }
  67. my_len=len;
  68. scan=buf;
  69. state=QA_ANY;
  70. space_cnt=0;
  71. while(my_len) {
  72. switch(*scan) {
  73. case ' ': if (state==QA_SPACE) {
  74. space_cnt++;
  75. if (space_cnt==4) {
  76. LOG(L_CRIT, "BUG(propably): DBG_MSG_QA: "
  77. "too many spaces\n");
  78. return 0;
  79. }
  80. } else space_cnt=0;
  81. state=QA_SPACE;
  82. break;
  83. case '\r': /* ignore */
  84. space_cnt=0;
  85. break;
  86. case '\n': /* don't proceed to body on EoH */
  87. if (state==QA_EOL1) goto qa_passed;
  88. space_cnt=0;
  89. state=QA_EOL1;
  90. break;
  91. default: space_cnt=0;
  92. state=QA_ANY;
  93. break;
  94. }
  95. scan++;
  96. my_len--;
  97. }
  98. qa_passed:
  99. return 1;
  100. }
  101. #endif
  102. int probe_max_receive_buffer( int udp_sock )
  103. {
  104. int optval;
  105. int ioptval;
  106. unsigned int ioptvallen;
  107. int foptval;
  108. unsigned int foptvallen;
  109. int voptval;
  110. unsigned int voptvallen;
  111. int phase=0;
  112. /* jku: try to increase buffer size as much as we can */
  113. ioptvallen=sizeof(ioptval);
  114. if (getsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF, (void*) &ioptval,
  115. &ioptvallen) == -1 )
  116. {
  117. LOG(L_ERR, "ERROR: udp_init: getsockopt: %s\n", strerror(errno));
  118. return -1;
  119. }
  120. if ( ioptval==0 )
  121. {
  122. LOG(L_DBG, "DEBUG: udp_init: SO_RCVBUF initialy set to 0; resetting to %d\n",
  123. BUFFER_INCREMENT );
  124. ioptval=BUFFER_INCREMENT;
  125. } else LOG(L_INFO, "INFO: udp_init: SO_RCVBUF is initially %d\n", ioptval );
  126. for (optval=ioptval; ; ) {
  127. /* increase size; double in initial phase, add linearly later */
  128. if (phase==0) optval <<= 1; else optval+=BUFFER_INCREMENT;
  129. if (optval > maxbuffer){
  130. if (phase==1) break;
  131. else { phase=1; optval >>=1; continue; }
  132. }
  133. LOG(L_DBG, "DEBUG: udp_init: trying SO_RCVBUF: %d\n", optval );
  134. if (setsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF,
  135. (void*)&optval, sizeof(optval)) ==-1){
  136. /* Solaris returns -1 if asked size too big; Linux ignores */
  137. LOG(L_DBG, "DEBUG: udp_init: SOL_SOCKET failed"
  138. " for %d, phase %d: %s\n", optval, phase, strerror(errno));
  139. /* if setting buffer size failed and still in the aggressive
  140. phase, try less agressively; otherwise give up
  141. */
  142. if (phase==0) { phase=1; optval >>=1 ; continue; }
  143. else break;
  144. }
  145. /* verify if change has taken effect */
  146. /* Linux note -- otherwise I would never know that; funny thing: Linux
  147. doubles size for which we asked in setsockopt
  148. */
  149. voptvallen=sizeof(voptval);
  150. if (getsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF, (void*) &voptval,
  151. &voptvallen) == -1 )
  152. {
  153. LOG(L_ERR, "ERROR: udp_init: getsockopt: %s\n", strerror(errno));
  154. return -1;
  155. } else {
  156. LOG(L_DBG, "DEBUG: setting SO_RCVBUF; set=%d,verify=%d\n",
  157. optval, voptval);
  158. if (voptval<optval) {
  159. LOG(L_DBG, "DEBUG: setting SO_RCVBUF has no effect\n");
  160. /* if setting buffer size failed and still in the aggressive
  161. phase, try less agressively; otherwise give up
  162. */
  163. if (phase==0) { phase=1; optval >>=1 ; continue; }
  164. else break;
  165. }
  166. }
  167. } /* for ... */
  168. foptvallen=sizeof(foptval);
  169. if (getsockopt( udp_sock, SOL_SOCKET, SO_RCVBUF, (void*) &foptval,
  170. &foptvallen) == -1 )
  171. {
  172. LOG(L_ERR, "ERROR: udp_init: getsockopt: %s\n", strerror(errno));
  173. return -1;
  174. }
  175. LOG(L_INFO, "INFO: udp_init: SO_RCVBUF is finally %d\n", foptval );
  176. return 0;
  177. /* EoJKU */
  178. }
  179. int udp_init(struct socket_info* sock_info)
  180. {
  181. union sockaddr_union* addr;
  182. int optval;
  183. addr=&sock_info->su;
  184. /*
  185. addr=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
  186. if (addr==0){
  187. LOG(L_ERR, "ERROR: udp_init: out of memory\n");
  188. goto error;
  189. }
  190. */
  191. sock_info->proto=PROTO_UDP;
  192. if (init_su(addr, &sock_info->address, htons(sock_info->port_no))<0){
  193. LOG(L_ERR, "ERROR: udp_init: could not init sockaddr_union\n");
  194. goto error;
  195. }
  196. sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_DGRAM, 0);
  197. if (sock_info->socket==-1){
  198. LOG(L_ERR, "ERROR: udp_init: socket: %s\n", strerror(errno));
  199. goto error;
  200. }
  201. /* set sock opts? */
  202. optval=1;
  203. if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR ,
  204. (void*)&optval, sizeof(optval)) ==-1){
  205. LOG(L_ERR, "ERROR: udp_init: setsockopt: %s\n", strerror(errno));
  206. goto error;
  207. }
  208. #if defined (__linux__) && defined(UDP_ERRORS)
  209. optval=1;
  210. /* enable error receiving on unconnected sockets */
  211. if(setsockopt(sock_info->socket, SOL_IP, IP_RECVERR,
  212. (void*)&optval, sizeof(optval)) ==-1){
  213. LOG(L_ERR, "ERROR: udp_init: setsockopt: %s\n", strerror(errno));
  214. goto error;
  215. }
  216. #endif
  217. if ( probe_max_receive_buffer(sock_info->socket)==-1) goto error;
  218. if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){
  219. LOG(L_ERR, "ERROR: udp_init: bind(%x, %p, %d) on %s: %s\n",
  220. sock_info->socket, &addr->s,
  221. sockaddru_len(*addr),
  222. sock_info->address_str.s,
  223. strerror(errno));
  224. #ifdef USE_IPV6
  225. if (addr->s.sa_family==AF_INET6)
  226. LOG(L_ERR, "ERROR: udp_init: might be caused by using a link "
  227. " local address, try site local or global\n");
  228. #endif
  229. goto error;
  230. }
  231. /* free(addr);*/
  232. return 0;
  233. error:
  234. /* if (addr) free(addr);*/
  235. return -1;
  236. }
  237. int udp_rcv_loop()
  238. {
  239. unsigned len;
  240. #ifdef DYN_BUF
  241. char* buf;
  242. #else
  243. static char buf [BUF_SIZE+1];
  244. #endif
  245. union sockaddr_union* from;
  246. unsigned int fromlen;
  247. struct receive_info ri;
  248. from=(union sockaddr_union*) malloc(sizeof(union sockaddr_union));
  249. if (from==0){
  250. LOG(L_ERR, "ERROR: udp_rcv_loop: out of memory\n");
  251. goto error;
  252. }
  253. memset(from, 0 , sizeof(union sockaddr_union));
  254. ri.bind_address=bind_address; /* this will not change, we do it only once*/
  255. ri.dst_port=bind_address->port_no;
  256. ri.dst_ip=bind_address->address;
  257. ri.proto=PROTO_UDP;
  258. ri.proto_reserved1=ri.proto_reserved2=0;
  259. for(;;){
  260. #ifdef DYN_BUF
  261. buf=pkg_malloc(BUF_SIZE+1);
  262. if (buf==0){
  263. LOG(L_ERR, "ERROR: udp_rcv_loop: could not allocate receive"
  264. " buffer\n");
  265. goto error;
  266. }
  267. #endif
  268. fromlen=sockaddru_len(bind_address->su);
  269. len=recvfrom(bind_address->socket, buf, BUF_SIZE, 0, &from->s,
  270. &fromlen);
  271. if (len==-1){
  272. LOG(L_ERR, "ERROR: udp_rcv_loop:recvfrom:[%d] %s\n",
  273. errno, strerror(errno));
  274. if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK)||
  275. (errno==ECONNREFUSED))
  276. continue; /* goto skip;*/
  277. else goto error;
  278. }
  279. /*debugging, make print* msg work */
  280. buf[len+1]=0;
  281. #ifndef NO_ZERO_CHECKS
  282. if (len==0) {
  283. LOG(L_WARN, "WARNING: empty packet received\n");
  284. continue;
  285. }
  286. if (buf[len-1]==0) {
  287. LOG(L_WARN, "WARNING: upstream bug - 0-terminated packet\n");
  288. len--;
  289. }
  290. #endif
  291. #ifdef DBG_MSG_QA
  292. if (!dbg_msg_qa(buf, len)) {
  293. LOG(L_WARN, "WARNING: an incoming message didn't pass test,"
  294. " drop it: %.*s\n", len, buf );
  295. continue;
  296. }
  297. #endif
  298. ri.src_su=*from;
  299. su2ip_addr(&ri.src_ip, from);
  300. ri.src_port=su_getport(from);
  301. /* receive_msg must free buf too!*/
  302. receive_msg(buf, len, &ri);
  303. /* skip: do other stuff */
  304. }
  305. /*
  306. if (from) free(from);
  307. return 0;
  308. */
  309. error:
  310. if (from) free(from);
  311. return -1;
  312. }
  313. /* which socket to use? main socket or new one? */
  314. int udp_send(struct socket_info *source, char *buf, unsigned len,
  315. union sockaddr_union* to)
  316. {
  317. int n;
  318. int tolen;
  319. #ifdef DBG_MSG_QA
  320. /* aborts on error, does nothing otherwise */
  321. if (!dbg_msg_qa( buf, len )) {
  322. LOG(L_ERR, "ERROR: udp_send: dbg_msg_qa failed\n");
  323. abort();
  324. }
  325. #endif
  326. tolen=sockaddru_len(*to);
  327. again:
  328. n=sendto(source->socket, buf, len, 0, &to->s, tolen);
  329. #ifdef XL_DEBUG
  330. LOG(L_INFO, "INFO: send status: %d\n", n);
  331. #endif
  332. if (n==-1){
  333. LOG(L_ERR, "ERROR: udp_send: sendto(sock,%p,%d,0,%p,%d): %s(%d)\n",
  334. buf,len,to,tolen,
  335. strerror(errno),errno);
  336. if (errno==EINTR) goto again;
  337. if (errno==EINVAL) {
  338. LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
  339. "one possible reason is the server is bound to localhost and\n"
  340. "attempts to send to the net\n");
  341. }
  342. }
  343. return n;
  344. }