00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <libplumbing/config.h>
00019 #include <cassert>
00020 #include <cerrno>
00021 #include <cstring>
00022 #include <fcntl.h>
00023 #include <sys/select.h>
00024 #include <sys/socket.h>
00025 #include <netinet/in.h>
00026 #include <libexplain/accept.h>
00027 #include <libexplain/bind.h>
00028 #include <libexplain/fcntl.h>
00029 #include <libexplain/listen.h>
00030 #include <libexplain/setsockopt.h>
00031 #include <libexplain/socket.h>
00032
00033 #include <libplumbing/reactor.h>
00034 #include <libplumbing/endpoint/listener.h>
00035
00036
00037 plumbing::endpoint_listener::~endpoint_listener()
00038 {
00039 }
00040
00041
00042 plumbing::endpoint_listener::endpoint_listener(reactor &a_svc,
00043 int a_port_number, int a_repeat_count) :
00044 endpoint(-1),
00045 svc(a_svc),
00046 port_number(a_port_number),
00047 repeat_count(a_repeat_count)
00048 {
00049 }
00050
00051
00052 plumbing::endpoint_listener::endpoint_listener(reactor &a_svc,
00053 const std::string &a_port_number, int a_repeat_count) :
00054 endpoint(-1),
00055 svc(a_svc),
00056 port_number(parse_port_number_or_die(a_port_number, true)),
00057 repeat_count(a_repeat_count)
00058 {
00059 }
00060
00061
00062 int
00063 plumbing::endpoint_listener::get_read_file_descriptor()
00064 {
00065 create_listening_socket();
00066 return endpoint::get_read_file_descriptor();
00067 }
00068
00069
00070 void
00071 plumbing::endpoint_listener::create_listening_socket()
00072 {
00073 if (fd >= 0)
00074 return;
00075 if (port_number < 0)
00076 {
00077 port_number = get_default_port();
00078 assert(port_number > 0);
00079 assert(port_number < 65536);
00080 }
00081
00082
00083
00084
00085 fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
00086 if (fd < 0)
00087 fatal_error("%s", explain_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
00088
00089
00090
00091
00092 int one = 1;
00093 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
00094 {
00095 fatal_error
00096 (
00097 "%s",
00098 explain_setsockopt
00099 (
00100 fd,
00101 SOL_SOCKET,
00102 SO_REUSEADDR,
00103 &one,
00104 sizeof(one)
00105 )
00106 );
00107 }
00108
00109
00110
00111
00112 struct sockaddr_in addr;
00113 memset(&addr, 0, sizeof(addr));
00114 addr.sin_family = AF_INET;
00115 addr.sin_addr.s_addr = htonl(INADDR_ANY);
00116 addr.sin_port = htons(port_number);
00117 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
00118 {
00119 fatal_error
00120 (
00121 "%s",
00122 explain_bind(fd, (struct sockaddr *)&addr, sizeof(addr))
00123 );
00124 }
00125
00126
00127
00128
00129 if (listen(fd, 5) < 0)
00130 {
00131 fatal_error("%s", explain_listen(fd, 5));
00132 }
00133
00134
00135
00136
00137 int flags = fcntl(fd, F_GETFD);
00138 if (flags < 0)
00139 fatal_error("%s", explain_fcntl(fd, F_GETFD, 0));
00140 flags |= O_NONBLOCK;
00141 if (fcntl(fd, F_SETFD, flags) < 0)
00142 fatal_error("%s", explain_fcntl(fd, F_SETFD, flags));
00143 }
00144
00145
00146 void
00147 plumbing::endpoint_listener::process_read()
00148 {
00149 struct sockaddr addr;
00150 memset(&addr, 0, sizeof(addr));
00151 socklen_t addrlen = sizeof(addr);
00152 int cfd = accept(fd, &addr, &addrlen);
00153 if (cfd < 0)
00154 {
00155 if (errno == EAGAIN)
00156 return;
00157 fatal_error("%s", explain_accept(fd, &addr, &addrlen));
00158 }
00159
00160
00161
00162
00163
00164
00165 if (repeat_count != -1)
00166 {
00167 --repeat_count;
00168 if (repeat_count <= 0)
00169 {
00170 kill_me_now();
00171
00172
00173
00174
00175
00176 repeat_count = 0;
00177 }
00178 }
00179
00180 endpoint::pointer ep = endpoint_factory(cfd, &addr, addrlen);
00181 add_endpoint(ep);
00182 }
00183
00184
00185 void
00186 plumbing::endpoint_listener::add_endpoint(const endpoint::pointer &ep)
00187 {
00188 svc.add_endpoint(ep);
00189 }
00190
00191
00192 void
00193 plumbing::endpoint_listener::process_write()
00194 {
00195
00196 assert(false);
00197 }
00198
00199
00200