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 <arpa/inet.h>
00023 #include <netdb.h>
00024 #include <netinet/in.h>
00025 #include <sys/socket.h>
00026 #include <libexplain/close.h>
00027 #include <libexplain/getpeername.h>
00028
00029 #include <libplumbing/reactor.h>
00030 #include <libplumbing/endpoint.h>
00031 #include <libplumbing/logging.h>
00032 #include <libplumbing/time_value.h>
00033
00034
00035 plumbing::endpoint::~endpoint()
00036 {
00037 close();
00038 }
00039
00040
00041 void
00042 plumbing::endpoint::close()
00043 {
00044 for (;;)
00045 {
00046 if (::close(fd) == 0)
00047 break;
00048 if (errno == EBADF)
00049 break;
00050 log().warning("%s", explain_errno_close(errno, fd));
00051 usleep(10);
00052 }
00053 fd = -1;
00054 }
00055
00056
00057 plumbing::endpoint::endpoint(int a_fd) :
00058 fd(a_fd),
00059 ready_to_die(false)
00060 {
00061
00062 set_peer_name();
00063 }
00064
00065
00066 plumbing::endpoint::endpoint(int a_fd, const void *sadr, int sadr_len) :
00067 fd(a_fd),
00068 ready_to_die(false)
00069 {
00070
00071 set_peer_name(sadr, sadr_len);
00072 }
00073
00074
00075 void
00076 plumbing::endpoint::set_peer_name(const char *s)
00077 {
00078 if (s && *s)
00079 peer_name = s;
00080 }
00081
00082
00083 void
00084 plumbing::endpoint::set_peer_name(const std::string &s)
00085 {
00086 if (!s.empty())
00087 peer_name = s;
00088 }
00089
00090
00091 void
00092 plumbing::endpoint::set_peer_name(const void *addr_p, int addr_len)
00093 {
00094 if (addr_len != sizeof(sockaddr_in))
00095 return;
00096 sockaddr_in *addr = (sockaddr_in *)addr_p;
00097 in_addr_t *ap = &addr->sin_addr.s_addr;
00098 hostent *he = gethostbyaddr(ap, sizeof(*ap), AF_INET);
00099 if (!he)
00100 {
00101 set_peer_name(inet_ntoa(addr->sin_addr));
00102 return;
00103 }
00104 set_peer_name(he->h_name);
00105 }
00106
00107
00108 void
00109 plumbing::endpoint::set_peer_name()
00110 {
00111 if (fd < 0)
00112 return;
00113 struct sockaddr_in sa;
00114 memset(&sa, 0, sizeof(sa));
00115 unsigned sa_len = sizeof(sa);
00116 if (getpeername(fd, (struct sockaddr *)&sa, &sa_len))
00117 {
00118 if (errno != ENOTSOCK)
00119 {
00120 warning
00121 (
00122 "%s",
00123 explain_errno_getpeername
00124 (
00125 errno,
00126 fd,
00127 (struct sockaddr *)&sa,
00128 &sa_len
00129 )
00130 );
00131 }
00132 }
00133 set_peer_name(&sa, sa_len);
00134 }
00135
00136
00137 bool
00138 plumbing::endpoint::is_ready_to_die()
00139 const
00140 {
00141 return ready_to_die;
00142 }
00143
00144
00145 void
00146 plumbing::endpoint::kill_me_now()
00147 {
00148 ready_to_die = true;
00149 }
00150
00151
00152 int
00153 plumbing::endpoint::get_read_file_descriptor()
00154 {
00155 return fd;
00156 }
00157
00158
00159 int
00160 plumbing::endpoint::get_write_file_descriptor()
00161 {
00162 return -1;
00163 }
00164
00165
00166 void
00167 plumbing::endpoint::process_read()
00168 {
00169 assert(!"derived class must override this method");
00170 }
00171
00172
00173 void
00174 plumbing::endpoint::process_write()
00175 {
00176 assert(!"derived class must override this method");
00177 }
00178
00179
00180 void
00181 plumbing::endpoint::fatal_error(const char *fmt, ...)
00182 {
00183 va_list ap;
00184 va_start(ap, fmt);
00185 fatal_error_v(fmt, ap);
00186 va_end(ap);
00187 }
00188
00189
00190 void
00191 plumbing::endpoint::fatal_error_v(const char *fmt, va_list ap)
00192 {
00193 const char *name = get_peer_name();
00194 if (!name || !*name)
00195 {
00196 log().fatal_error_v(fmt, ap);
00197 return;
00198 }
00199
00200 char buffer[1000];
00201 vsnprintf(buffer, sizeof(buffer), fmt, ap);
00202 log().fatal_error("%s: %s", name, buffer);
00203 }
00204
00205
00206 void
00207 plumbing::endpoint::warning(const char *fmt, ...)
00208 {
00209 va_list ap;
00210 va_start(ap, fmt);
00211 warning_v(fmt, ap);
00212 va_end(ap);
00213 }
00214
00215
00216 void
00217 plumbing::endpoint::warning_v(const char *fmt, va_list ap)
00218 {
00219 const char *name = get_peer_name();
00220 if (!name || !*name)
00221 {
00222 log().warning_v(fmt, ap);
00223 return;
00224 }
00225
00226 char buffer[1000];
00227 vsnprintf(buffer, sizeof(buffer), fmt, ap);
00228 log().warning("%s: %s", name, buffer);
00229 }
00230
00231
00232 plumbing::time_value
00233 plumbing::endpoint::get_maximum_sleep()
00234 const
00235 {
00236 return time_value(60);
00237 }
00238
00239
00240 void
00241 plumbing::endpoint::process_timeout()
00242 {
00243 }
00244
00245
00246 int
00247 plumbing::endpoint::parse_port_number(const std::string &text)
00248 {
00249 struct servent *sp = getservbyname(text.c_str(), "tcp");
00250 if (sp)
00251 return ntohs(sp->s_port);
00252 char *ep = 0;
00253 long n = strtol(text.c_str(), &ep, 0);
00254 if (ep == text.c_str() || *ep)
00255 return -1;
00256 return n;
00257 }
00258
00259
00260 int
00261 plumbing::endpoint::parse_port_number_or_die(const std::string &text,
00262 bool empty_is_ok)
00263 {
00264 if (text.empty() && empty_is_ok)
00265 return -1;
00266 int n = parse_port_number(text);
00267 if (n < 0)
00268 {
00269 log().fatal_error
00270 (
00271 "unable to interpret \"%s\" as a port number",
00272 text.c_str()
00273 );
00274 }
00275 return n;
00276 }
00277
00278
00279