PageRenderTime 26ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/release/src/router/udpxy/netop.c

https://gitlab.com/envieidoc/tomato
C | 528 lines | 387 code | 93 blank | 48 comment | 83 complexity | 98f1339586d6eeab403228d005cfa928 MD5 | raw file
  1. /* @(#) implementation of network operations for udpxy
  2. *
  3. * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com)
  4. *
  5. * This file is part of udpxy.
  6. *
  7. * udpxy is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * udpxy is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with udpxy. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <arpa/inet.h>
  23. #include <netinet/in.h>
  24. #include <assert.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #include <time.h>
  28. #include <errno.h>
  29. #include <stdio.h>
  30. #include <fcntl.h>
  31. #include "udpxy.h"
  32. #include "netop.h"
  33. #include "util.h"
  34. #include "mtrace.h"
  35. #include "osdef.h"
  36. extern FILE* g_flog; /* application log */
  37. /* set up (server) listening sockfd
  38. */
  39. int
  40. setup_listener( const char* ipaddr, int port, int* sockfd, int bklog )
  41. {
  42. #define LOWMARK 10 /* do not accept input of less than X octets */
  43. int rc, lsock, wmark = LOWMARK;
  44. struct sockaddr_in servaddr;
  45. const int ON = 1;
  46. extern const char IPv4_ALL[];
  47. assert( (port > 0) && sockfd && ipaddr );
  48. (void)IPv4_ALL;
  49. TRACE( (void)tmfprintf( g_flog, "Setting up listener for [%s:%d]\n",
  50. ipaddr[0] ? ipaddr : IPv4_ALL, port) );
  51. rc = ERR_INTERNAL;
  52. do {
  53. lsock = socket( AF_INET, SOCK_STREAM, 0 );
  54. if( -1 == lsock ) break;
  55. (void) memset( &servaddr, 0, sizeof(servaddr) );
  56. servaddr.sin_family = AF_INET;
  57. servaddr.sin_port = htons( (short)port );
  58. if( '\0' != ipaddr[0] ) {
  59. if( 1 != inet_aton(ipaddr, &servaddr.sin_addr) ) {
  60. TRACE( (void)tmfprintf( g_flog, "Invalid server IP: [%s]\n",
  61. ipaddr) );
  62. rc = ERR_PARAM;
  63. break;
  64. }
  65. }
  66. else {
  67. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  68. }
  69. rc = setsockopt( lsock, SOL_SOCKET, SO_REUSEADDR,
  70. &ON, sizeof(ON) );
  71. if( 0 != rc ) {
  72. mperror(g_flog, errno, "%s: setsockopt SO_REUSEADDR",
  73. __func__);
  74. break;
  75. }
  76. #define NONBLOCK 1
  77. rc = set_nblock (lsock, NONBLOCK);
  78. if (0 != rc) break;
  79. TRACE( (void)tmfprintf (g_flog, "Setting low watermark for "
  80. "server socket [%d] to [%d]\n", lsock, wmark) );
  81. rc = setsockopt (lsock, SOL_SOCKET, SO_RCVLOWAT,
  82. (char*)&wmark, sizeof(wmark));
  83. if (rc) {
  84. mperror (g_flog, errno, "%s: setsockopt SO_RCVLOWAT",
  85. __func__);
  86. break;
  87. }
  88. rc = bind( lsock, (struct sockaddr*)&servaddr, sizeof(servaddr) );
  89. if( 0 != rc ) break;
  90. rc = listen (lsock, (bklog > 0 ? bklog : 1));
  91. if( 0 != rc ) break;
  92. rc = 0;
  93. } while(0);
  94. if( 0 != rc ) {
  95. if(errno)
  96. mperror(g_flog, errno, "%s: socket/bind/listen error",
  97. __func__);
  98. if( lsock ) {
  99. (void) close( lsock );
  100. }
  101. }
  102. else {
  103. *sockfd = lsock;
  104. TRACE( (void)tmfprintf( g_flog, "Created server socket=[%d], backlog=[%d]\n",
  105. lsock, bklog) );
  106. }
  107. return rc;
  108. }
  109. /* add or drop membership in a multicast group
  110. */
  111. int
  112. set_multicast( int msockfd, const struct in_addr* mifaddr,
  113. int opname )
  114. {
  115. struct sockaddr_in addr;
  116. a_socklen_t len = sizeof(addr);
  117. struct ip_mreq mreq;
  118. int rc = 0;
  119. const char *opstr =
  120. ((IP_DROP_MEMBERSHIP == opname) ? "DROP" :
  121. ((IP_ADD_MEMBERSHIP == opname) ? "ADD" : ""));
  122. assert( opstr[0] );
  123. assert( (msockfd > 0) && mifaddr );
  124. (void) memset( &mreq, 0, sizeof(mreq) );
  125. (void) memcpy( &mreq.imr_interface, mifaddr,
  126. sizeof(struct in_addr) );
  127. (void) memset( &addr, 0, sizeof(addr) );
  128. rc = getsockname( msockfd, (struct sockaddr*)&addr, &len );
  129. if( 0 != rc ) {
  130. mperror( g_flog, errno, "%s: getsockname", __func__ );
  131. return -1;
  132. }
  133. (void) memcpy( &mreq.imr_multiaddr, &addr.sin_addr,
  134. sizeof(struct in_addr) );
  135. rc = setsockopt( msockfd, IPPROTO_IP, opname,
  136. &mreq, sizeof(mreq) );
  137. if( 0 != rc ) {
  138. mperror( g_flog, errno, "%s: setsockopt MCAST option: %s",
  139. __func__, opstr );
  140. return rc;
  141. }
  142. TRACE( (void)tmfprintf( g_flog, "multicast-group [%s]\n",
  143. opstr ) );
  144. return rc;
  145. }
  146. /* set up the socket to receive multicast data
  147. *
  148. */
  149. int
  150. setup_mcast_listener( struct sockaddr_in* sa,
  151. const struct in_addr* mifaddr,
  152. int* mcastfd,
  153. int sockbuflen )
  154. {
  155. int sockfd, rc;
  156. int ON = 1;
  157. int buflen = sockbuflen;
  158. size_t rcvbuf_len = 0;
  159. assert( sa && mifaddr && mcastfd && (sockbuflen >= 0) );
  160. TRACE( (void)tmfprintf( g_flog, "Setting up multicast listener\n") );
  161. rc = ERR_INTERNAL;
  162. do {
  163. sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
  164. if( -1 == sockfd ) {
  165. mperror(g_flog, errno, "%s: socket", __func__);
  166. break;
  167. }
  168. if (buflen != 0) {
  169. rc = get_rcvbuf( sockfd, &rcvbuf_len );
  170. if (0 != rc) break;
  171. if ((size_t)buflen > rcvbuf_len) {
  172. rc = set_rcvbuf( sockfd, buflen );
  173. if (0 != rc) break;
  174. }
  175. }
  176. else {
  177. TRACE( (void)tmfprintf( g_flog, "Must not adjust buffer size "
  178. "for mcast socket [%d]\n", sockfd ) );
  179. }
  180. rc = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR,
  181. &ON, sizeof(ON) );
  182. if( 0 != rc ) {
  183. mperror(g_flog, errno, "%s: setsockopt SO_REUSEADDR",
  184. __func__);
  185. break;
  186. }
  187. #ifdef SO_REUSEPORT
  188. /* On some systems (such as FreeBSD) SO_REUSEADDR
  189. just isn't enough to subscribe to N same channels for different clients.
  190. */
  191. rc = setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT,
  192. &ON, sizeof(ON) );
  193. if( 0 != rc ) {
  194. mperror(g_flog, errno, "%s: setsockopt SO_REUSEPORT",
  195. __func__);
  196. break;
  197. }
  198. #endif /* SO_REUSEPORT */
  199. rc = bind( sockfd, (struct sockaddr*)sa, sizeof(*sa) );
  200. if( 0 != rc ) {
  201. mperror(g_flog, errno, "%s: bind", __func__);
  202. break;
  203. }
  204. rc = set_multicast( sockfd, mifaddr, IP_ADD_MEMBERSHIP );
  205. if( 0 != rc )
  206. break;
  207. } while(0);
  208. if( 0 == rc ) {
  209. *mcastfd = sockfd;
  210. TRACE( (void)tmfprintf( g_flog, "Mcast listener socket=[%d] set up\n",
  211. sockfd) );
  212. }
  213. else {
  214. (void)close(sockfd);
  215. }
  216. return rc;
  217. }
  218. /* unsubscribe from multicast and close the reader socket
  219. */
  220. void
  221. close_mcast_listener( int msockfd, const struct in_addr* mifaddr )
  222. {
  223. assert( mifaddr );
  224. if( msockfd <= 0 ) return;
  225. (void) set_multicast( msockfd, mifaddr, IP_DROP_MEMBERSHIP );
  226. (void) close( msockfd );
  227. TRACE( (void)tmfprintf( g_flog, "Mcast listener socket=[%d] closed\n",
  228. msockfd) );
  229. return;
  230. }
  231. /* drop from and add into a multicast group
  232. */
  233. int
  234. renew_multicast( int msockfd, const struct in_addr* mifaddr )
  235. {
  236. int rc = 0;
  237. rc = set_multicast( msockfd, mifaddr, IP_DROP_MEMBERSHIP );
  238. if( 0 != rc ) return rc;
  239. rc = set_multicast( msockfd, mifaddr, IP_ADD_MEMBERSHIP );
  240. return rc;
  241. }
  242. /* set send/receive timeouts on socket(s)
  243. */
  244. int
  245. set_timeouts( int rsock, int ssock,
  246. u_short rcv_tmout_sec, u_short rcv_tmout_usec,
  247. u_short snd_tmout_sec, u_short snd_tmout_usec )
  248. {
  249. struct timeval rtv, stv;
  250. int rc = 0;
  251. if( rsock ) {
  252. rtv.tv_sec = rcv_tmout_sec;
  253. rtv.tv_usec = rcv_tmout_usec;
  254. rc = setsockopt( rsock, SOL_SOCKET, SO_RCVTIMEO, &rtv, sizeof(rtv) );
  255. if( -1 == rc ) {
  256. mperror(g_flog, errno, "%s: setsockopt - SO_RCVTIMEO",
  257. __func__);
  258. return ERR_INTERNAL;
  259. }
  260. TRACE( (void)tmfprintf (g_flog, "socket %d: RCV timeout set to %ld sec, %ld usec\n",
  261. rsock, rtv.tv_sec, rtv.tv_usec) );
  262. }
  263. if( ssock ) {
  264. stv.tv_sec = snd_tmout_sec;
  265. stv.tv_usec = snd_tmout_usec;
  266. rc = setsockopt( ssock, SOL_SOCKET, SO_SNDTIMEO, &stv, sizeof(stv) );
  267. if( -1 == rc ) {
  268. mperror(g_flog, errno, "%s: setsockopt - SO_SNDTIMEO", __func__);
  269. return ERR_INTERNAL;
  270. }
  271. TRACE( (void)tmfprintf (g_flog, "socket %d: SEND timeout set to %ld sec, %ld usec\n",
  272. rsock, rtv.tv_sec, rtv.tv_usec) );
  273. }
  274. return rc;
  275. }
  276. /* set socket's send/receive buffer size
  277. */
  278. static int
  279. set_sockbuf_size( int sockfd, int option, const size_t len,
  280. const char* bufname )
  281. {
  282. size_t data_len = len;
  283. int rc = 0;
  284. assert( bufname );
  285. rc = setsockopt( sockfd, SOL_SOCKET, option,
  286. &data_len, sizeof(data_len) );
  287. if( 0 != rc ) {
  288. mperror(g_flog, errno, "%s: setsockopt %s [%d]",
  289. __func__, bufname, option);
  290. return -1;
  291. }
  292. else {
  293. TRACE( (void)tmfprintf( g_flog,
  294. "%s buffer size set to [%u] bytes for socket [%d]\n",
  295. bufname, data_len, sockfd ) );
  296. }
  297. return rc;
  298. }
  299. /* set socket's send buffer value
  300. */
  301. int
  302. set_sendbuf( int sockfd, const size_t len )
  303. {
  304. return set_sockbuf_size( sockfd, SO_SNDBUF, len, "send" );
  305. }
  306. /* set socket's send buffer value
  307. */
  308. int
  309. set_rcvbuf( int sockfd, const size_t len )
  310. {
  311. return set_sockbuf_size( sockfd, SO_RCVBUF, len, "receive" );
  312. }
  313. static int
  314. get_sockbuf_size( int sockfd, int option, size_t* const len,
  315. const char* bufname )
  316. {
  317. int rc = 0;
  318. size_t buflen = 0;
  319. socklen_t varsz = sizeof(buflen);
  320. assert( sockfd && len && bufname );
  321. rc = getsockopt( sockfd, SOL_SOCKET, option, &buflen, &varsz );
  322. if (0 != rc) {
  323. mperror( g_flog, errno, "%s: getsockopt (%s) [%d]", __func__,
  324. bufname, option);
  325. return -1;
  326. }
  327. else {
  328. TRACE( (void)tmfprintf( g_flog,
  329. "current %s buffer size is [%u] bytes for socket [%d]\n",
  330. bufname, buflen, sockfd ) );
  331. *len = buflen;
  332. }
  333. return rc;
  334. }
  335. /* get socket's send buffer size
  336. */
  337. int
  338. get_sendbuf( int sockfd, size_t* const len )
  339. {
  340. return get_sockbuf_size( sockfd, SO_SNDBUF, len, "send" );
  341. }
  342. /* get socket's receive buffer size
  343. */
  344. int
  345. get_rcvbuf( int sockfd, size_t* const len )
  346. {
  347. return get_sockbuf_size( sockfd, SO_RCVBUF, len, "receive" );
  348. }
  349. /* set/clear file/socket's mode as non-blocking
  350. */
  351. int
  352. set_nblock( int fd, int set )
  353. {
  354. int flags = 0;
  355. flags = fcntl( fd, F_GETFL, 0 );
  356. if( flags < 0 ) {
  357. mperror( g_flog, errno, "%s: fcntl() getting flags on fd=[%d]",
  358. __func__, fd );
  359. return -1;
  360. }
  361. if( set )
  362. flags |= O_NONBLOCK;
  363. else
  364. flags &= ~O_NONBLOCK;
  365. if( fcntl( fd, F_SETFL, flags ) < 0 ) {
  366. mperror( g_flog, errno, "%s: fcntl() %s non-blocking mode "
  367. "on fd=[%d]", __func__, (set ? "setting" : "clearing"),
  368. fd );
  369. return -1;
  370. }
  371. return 0;
  372. }
  373. static int
  374. sock_info (int peer, int sockfd, char* addr, size_t alen, int* port)
  375. {
  376. int rc = 0;
  377. union {
  378. struct sockaddr sa;
  379. char data [sizeof(struct sockaddr_in6)];
  380. } gsa;
  381. socklen_t len;
  382. const void* dst = NULL;
  383. struct sockaddr_in6 *sa6 = NULL;
  384. struct sockaddr_in *sa4 = NULL;
  385. len = sizeof (gsa.data);
  386. rc = peer ? getpeername (sockfd, (struct sockaddr*)gsa.data, &len):
  387. getsockname (sockfd, (struct sockaddr*)gsa.data, &len);
  388. if (0 != rc) {
  389. rc = errno;
  390. (void) fprintf (g_flog, "getsockname error [%d]: %s\n",
  391. rc, strerror (rc));
  392. return rc;
  393. }
  394. switch (gsa.sa.sa_family) {
  395. case AF_INET:
  396. sa4 = (struct sockaddr_in*)&gsa.sa;
  397. if (addr) {
  398. dst = inet_ntop (gsa.sa.sa_family, &(sa4->sin_addr),
  399. addr, (socklen_t)alen);
  400. }
  401. if (port) *port = (int) ntohs (sa4->sin_port);
  402. break;
  403. case AF_INET6:
  404. sa6 = (struct sockaddr_in6*)&gsa.sa;
  405. if (addr) {
  406. dst = inet_ntop (gsa.sa.sa_family, &(sa6->sin6_addr),
  407. addr, (socklen_t)alen);
  408. }
  409. if (port) *port = (int) ntohs (sa6->sin6_port);
  410. break;
  411. default:
  412. (void) tmfprintf (g_flog, "%s: unsupported socket family: %d\n",
  413. __func__, (int)gsa.sa.sa_family);
  414. return EAFNOSUPPORT;
  415. }
  416. if (addr && !dst) {
  417. rc = errno;
  418. (void) tmfprintf (g_flog, "%s: inet_pton error [%d]: %s\n",
  419. __func__, rc, strerror (rc));
  420. return rc;
  421. }
  422. return rc;
  423. }
  424. enum {e_host = 0, e_peer = 1};
  425. int
  426. get_sockinfo (int sockfd, char* addr, size_t alen, int* port)
  427. {
  428. return sock_info (e_host, sockfd, addr, alen, port);
  429. }
  430. int
  431. get_peerinfo (int sockfd, char* addr, size_t alen, int* port)
  432. {
  433. return sock_info (e_peer, sockfd, addr, alen, port);
  434. }
  435. /* __EOF__ */