ctorrent stat collector
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
5.0KB

  1. /***************************************************************************
  2. * Copyright (C) 07/2007 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <netinet/ip.h>
  24. #include <arpa/inet.h>
  25. #include <fcntl.h>
  26. #include <errno.h>
  27. #include "event.h"
  28. #include "logging.h"
  29. #include "sockaddr.h"
  30. int tcp_listen(struct sockaddr_in *sa)
  31. {
  32. int sock = socket(AF_INET, SOCK_STREAM, 0);
  33. if (sock < 0 ) {
  34. log_print(LOG_ERROR, "tcp_listen_socket(): socket()");
  35. return -1;
  36. }
  37. int i = 1;
  38. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) {
  39. log_print(LOG_ERROR, "tcp_listen_socket(): setsockopt(SO_REUSEADDR)");
  40. close(sock);
  41. return -1;
  42. }
  43. if (bind(sock, (struct sockaddr *)sa, sizeof(*sa))) {
  44. log_print(LOG_ERROR, "tcp_listen_socket(): bind(%s)", get_sockaddr_buf(sa));
  45. close(sock);
  46. return -1;
  47. }
  48. if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
  49. log_print(LOG_WARN, "tcp_listen_socket(): fcntl(FD_CLOEXEC)");
  50. return -1;
  51. }
  52. if (listen(sock, 8)) {
  53. log_print(LOG_ERROR, "tcp_listen_socket(): listen()");
  54. close(sock);
  55. return -1;
  56. }
  57. return sock;
  58. }
  59. int tcp_accept(int fd, struct sockaddr_in *sa)
  60. {
  61. unsigned int i = sizeof(struct sockaddr_in);
  62. int sock = accept(fd, (struct sockaddr *)sa, &i);
  63. if (sock < 0) {
  64. log_print(LOG_WARN, "tcp_accept(): accept()");
  65. return -1;
  66. }
  67. if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
  68. log_print(LOG_WARN, "tcp_accept(): fcntl(FD_CLOEXEC)");
  69. close(sock);
  70. return -1;
  71. }
  72. return sock;
  73. }
  74. int tcp_connect(struct sockaddr_in *sa)
  75. {
  76. int sock = socket(AF_INET, SOCK_STREAM, 0);
  77. if (sock < 0 ) {
  78. log_print(LOG_ERROR, "tcp_connect_socket(): socket()");
  79. return -1;
  80. }
  81. if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
  82. log_print(LOG_WARN, "tcp_connect_socket(): fcntl(FD_CLOEXEC)");
  83. return -1;
  84. }
  85. int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa));
  86. if (ret != 0) {
  87. log_print(LOG_ERROR, "tcp_connect(): connect(%s)", get_sockaddr_buf(sa));
  88. close(sock);
  89. return -1;
  90. }
  91. return sock;
  92. }
  93. int tcp_connect_nonblock(struct sockaddr_in *sa)
  94. {
  95. int sock = socket(AF_INET, SOCK_STREAM, 0);
  96. if (sock < 0 ) {
  97. log_print(LOG_ERROR, "tcp_connect_nonblock(): socket()");
  98. return -1;
  99. }
  100. if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
  101. log_print(LOG_WARN, "tcp_connect_nonblock(): fcntl(FD_CLOEXEC)");
  102. return -1;
  103. }
  104. int flags = fcntl(sock, F_GETFL, 0);
  105. if (flags < 0) {
  106. log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_GETFL)");
  107. close(sock);
  108. return -1;
  109. }
  110. /* non-blocking connect() */
  111. if (fcntl(sock, F_SETFL, flags | O_NONBLOCK)) {
  112. log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_SETFL)");
  113. close(sock);
  114. return -1;
  115. }
  116. int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa));
  117. if (ret && errno != EINPROGRESS) {
  118. log_print(LOG_ERROR, "tcp_connect_nonblock(): connect(%s)", get_sockaddr_buf(sa));
  119. close(sock);
  120. return -1;
  121. }
  122. /* reset EINPROGRESS */
  123. errno = 0;
  124. /* all further actions are blocking */
  125. if (fcntl(sock, F_SETFL, flags)) {
  126. log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_SETFL)");
  127. close(sock);
  128. return -1;
  129. }
  130. return sock;
  131. }
  132. int tcp_connect_error(int fd)
  133. {
  134. int err;
  135. unsigned int err_size = sizeof(err);
  136. if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_size)) {
  137. log_print(LOG_ERROR, "tcp_connect_error(): getsockopt(SO_ERROR)");
  138. return -1;
  139. }
  140. if (err) {
  141. errno = err;
  142. return -1;
  143. }
  144. return 0;
  145. }
  146. struct event_fd * tcp_listen_event(const char *address, void *accept_handler, void *accept_privdata)
  147. {
  148. struct sockaddr_in addr;
  149. if (parse_sockaddr(address, &addr) < 0) {
  150. log_print(LOG_WARN, "tcp_listen_event(): invalid address");
  151. return NULL;
  152. }
  153. int sock = tcp_listen(&addr);
  154. if (sock < 0) {
  155. log_print(LOG_WARN, "tcp_listen_event(): tcp_listen()");
  156. return NULL;
  157. }
  158. return event_add_readfd(NULL, sock, accept_handler, accept_privdata);
  159. }