00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "IPSocket.h"
00040 #include "NetUtils.h"
00041 #include "debug/Log.h"
00042 #include "debug/DebugUtils.h"
00043
00044 #include <string.h>
00045 #include <unistd.h>
00046 #include <fcntl.h>
00047 #include <errno.h>
00048 #include <sys/ioctl.h>
00049 #include <sys/types.h>
00050 #include <sys/socket.h>
00051 #include <sys/uio.h>
00052 #include <sys/poll.h>
00053 #include <netinet/in.h>
00054 #include <netinet/tcp.h>
00055 #include <arpa/inet.h>
00056
00057 namespace oasys {
00058
00059 IPSocket::IPSocket(int socktype, const char* logbase)
00060 : Logger("IPSocket", logbase)
00061 {
00062 state_ = INIT;
00063 local_addr_ = INADDR_ANY;
00064 local_port_ = 0;
00065 remote_addr_ = INADDR_NONE;
00066 remote_port_ = 0;
00067 fd_ = -1;
00068 socktype_ = socktype;
00069 logfd_ = true;
00070 }
00071
00072 IPSocket::IPSocket(int socktype, int sock,
00073 in_addr_t remote_addr, u_int16_t remote_port,
00074 const char* logbase)
00075 : Logger("IPSocket", "%s/%d", logbase, sock)
00076 {
00077 fd_ = sock;
00078 socktype_ = socktype;
00079
00080 state_ = ESTABLISHED;
00081 local_addr_ = INADDR_NONE;
00082 local_port_ = 0;
00083 remote_addr_ = remote_addr;
00084 remote_port_ = remote_port;
00085
00086 configure();
00087 }
00088
00089 IPSocket::~IPSocket()
00090 {
00091 close();
00092 }
00093
00094 void
00095 IPSocket::init_socket()
00096 {
00097
00098 ASSERT(state_ == INIT || state_ == FINI);
00099 ASSERT(fd_ == -1);
00100 state_ = INIT;
00101
00102 fd_ = socket(PF_INET, socktype_, 0);
00103 if (fd_ == -1) {
00104 logf(LOG_ERR, "error creating socket: %s", strerror(errno));
00105 return;
00106 }
00107
00108 if (logfd_)
00109 Logger::logpath_appendf("/%d", fd_);
00110
00111 logf(LOG_DEBUG, "created socket %d", fd_);
00112
00113 configure();
00114 }
00115
00116 const char*
00117 IPSocket::statetoa(state_t state)
00118 {
00119 switch (state) {
00120 case INIT: return "INIT";
00121 case LISTENING: return "LISTENING";
00122 case CONNECTING: return "CONNECTING";
00123 case ESTABLISHED: return "ESTABLISHED";
00124 case RDCLOSED: return "RDCLOSED";
00125 case WRCLOSED: return "WRCLOSED";
00126 case CLOSED: return "CLOSED";
00127 case FINI: return "FINI";
00128 }
00129 ASSERT(0);
00130 return NULL;
00131 }
00132
00133 void
00134 IPSocket::set_state(state_t state)
00135 {
00136 logf(LOG_DEBUG, "state %s -> %s", statetoa(state_), statetoa(state));
00137 state_ = state;
00138 }
00139
00140 int
00141 IPSocket::bind(in_addr_t local_addr, u_int16_t local_port)
00142 {
00143 struct sockaddr_in sa;
00144
00145 if (fd_ == -1) init_socket();
00146
00147 local_addr_ = local_addr;
00148 local_port_ = local_port;
00149
00150 logf(LOG_DEBUG, "binding to %s:%d", intoa(local_addr), local_port);
00151
00152 memset(&sa, 0, sizeof(sa));
00153 sa.sin_family = AF_INET;
00154 sa.sin_addr.s_addr = local_addr_;
00155 sa.sin_port = htons(local_port_);
00156 if (::bind(fd_, (struct sockaddr*) &sa, sizeof(sa)) != 0) {
00157 int err = errno;
00158 logf(LOG_ERR, "error binding to %s:%d: %s",
00159 intoa(local_addr_), local_port_, strerror(err));
00160 return -1;
00161 }
00162
00163 return 0;
00164 }
00165
00166 int
00167 IPSocket::connect()
00168 {
00169 struct sockaddr_in sa;
00170
00171 if (ESTABLISHED == state_)
00172 return 0;
00173
00174 if (fd_ == -1) init_socket();
00175
00176 log_debug("connecting to %s:%d", intoa(remote_addr_), remote_port_);
00177
00178 memset(&sa, 0, sizeof(sa));
00179 sa.sin_family = AF_INET;
00180 sa.sin_addr.s_addr = remote_addr_;
00181 sa.sin_port = htons(remote_port_);
00182
00183 set_state(CONNECTING);
00184
00185 if (::connect(fd_, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
00186 if (errno == EISCONN)
00187 log_debug("already connected to %s:%d",
00188 intoa(remote_addr_), remote_port_);
00189 else if (errno == EINPROGRESS) {
00190 log_debug("delayed connect to %s:%d (EINPROGRESS)",
00191 intoa(remote_addr_), remote_port_);
00192 } else {
00193 log_debug("error connecting to %s:%d: %s",
00194 intoa(remote_addr_), remote_port_, strerror(errno));
00195 }
00196
00197 return -1;
00198 }
00199
00200 set_state(ESTABLISHED);
00201
00202 return 0;
00203 }
00204
00205 int
00206 IPSocket::async_connect_result()
00207 {
00208 ASSERT(state_ == CONNECTING);
00209
00210 int result;
00211 socklen_t len = sizeof(result);
00212 logf(LOG_DEBUG, "getting connect result");
00213 if (::getsockopt(fd_, SOL_SOCKET, SO_ERROR, &result, &len) != 0) {
00214 logf(LOG_ERR, "error getting connect result: %s", strerror(errno));
00215 return errno;
00216 }
00217
00218 if (result == 0) {
00219 set_state(ESTABLISHED);
00220 }
00221
00222 return result;
00223 }
00224
00225 int
00226 IPSocket::connect(in_addr_t remote_addr, u_int16_t remote_port)
00227 {
00228 remote_addr_ = remote_addr;
00229 remote_port_ = remote_port;
00230
00231 return connect();
00232 }
00233
00234 void
00235 IPSocket::configure()
00236 {
00237 if (params_.reuseaddr_) {
00238 int y = 1;
00239 logf(LOG_DEBUG, "setting SO_REUSEADDR");
00240 if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &y, sizeof y) != 0) {
00241 logf(LOG_WARN, "error setting SO_REUSEADDR: %s",
00242 strerror(errno));
00243 }
00244 }
00245
00246 if (params_.reuseport_) {
00247 #ifdef SO_REUSEPORT
00248 int y = 1;
00249 logf(LOG_DEBUG, "setting SO_REUSEPORT");
00250 if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEPORT, &y, sizeof y) != 0) {
00251 logf(LOG_WARN, "error setting SO_REUSEPORT: %s",
00252 strerror(errno));
00253 }
00254 #else
00255 logf(LOG_WARN, "error setting SO_REUSEPORT: not implemented");
00256 #endif
00257 }
00258
00259 if (socktype_ == SOCK_STREAM && params_.tcp_nodelay_) {
00260 int y = 1;
00261 logf(LOG_DEBUG, "setting TCP_NODELAY");
00262 if (::setsockopt(fd_, IPPROTO_IP, TCP_NODELAY, &y, sizeof y) != 0) {
00263 logf(LOG_WARN, "error setting TCP_NODELAY: %s",
00264 strerror(errno));
00265 }
00266 }
00267
00268 if (params_.recv_bufsize_ > 0) {
00269 logf(LOG_DEBUG, "setting SO_RCVBUF to %d",
00270 params_.recv_bufsize_);
00271
00272 if (::setsockopt(fd_, SOL_SOCKET, SO_RCVBUF,
00273 ¶ms_.recv_bufsize_,
00274 sizeof (params_.recv_bufsize_)) < 0)
00275 {
00276 logf(LOG_WARN, "error setting SO_RCVBUF to %d: %s",
00277 params_.recv_bufsize_, strerror(errno));
00278 }
00279 }
00280
00281 if (params_.send_bufsize_ > 0) {
00282 logf(LOG_WARN, "setting SO_SNDBUF to %d",
00283 params_.send_bufsize_);
00284
00285 if (::setsockopt(fd_, SOL_SOCKET, SO_SNDBUF,
00286 ¶ms_.send_bufsize_,
00287 sizeof params_.send_bufsize_) < 0)
00288 {
00289 logf(LOG_WARN, "error setting SO_SNDBUF to %d: %s",
00290 params_.send_bufsize_, strerror(errno));
00291 }
00292 }
00293 }
00294
00295 int
00296 IPSocket::close()
00297 {
00298 logf(LOG_DEBUG, "closing socket in state %s", statetoa(state_));
00299
00300 if (fd_ == -1) {
00301 ASSERT(state_ == INIT || state_ == FINI);
00302 return 0;
00303 }
00304
00305 if (::close(fd_) != 0) {
00306 logf(LOG_ERR, "error closing socket in state %s: %s",
00307 statetoa(state_), strerror(errno));
00308 return -1;
00309 }
00310
00311 set_state(FINI);
00312 fd_ = -1;
00313 return 0;
00314 }
00315
00316 int
00317 IPSocket::shutdown(int how)
00318 {
00319 const char* howstr;
00320
00321 switch (how) {
00322 case SHUT_RD: howstr = "R"; break;
00323 case SHUT_WR: howstr = "W"; break;
00324 case SHUT_RDWR: howstr = "RW"; break;
00325
00326 default:
00327 logf(LOG_ERR, "shutdown invalid mode %d", how);
00328 return -1;
00329 }
00330
00331 logf(LOG_DEBUG, "shutdown(%s) state %s", howstr, statetoa(state_));
00332
00333 if (state_ == INIT || state_ == FINI) {
00334 ASSERT(fd_ == -1);
00335 return 0;
00336 }
00337
00338 if (::shutdown(fd_, how) != 0) {
00339 logf(LOG_ERR, "error in shutdown(%s) state %s: %s",
00340 howstr, statetoa(state_), strerror(errno));
00341 }
00342
00343 if (state_ == ESTABLISHED) {
00344 if (how == SHUT_RD) { set_state(RDCLOSED); }
00345 if (how == SHUT_WR) { set_state(WRCLOSED); }
00346 if (how == SHUT_RDWR) { set_state(CLOSED); }
00347
00348 } else if (state_ == RDCLOSED && how == SHUT_WR) {
00349 set_state(CLOSED);
00350
00351 } else if (state_ == WRCLOSED && how == SHUT_RD) {
00352 set_state(CLOSED);
00353
00354 } else {
00355 logf(LOG_ERR, "invalid state %s for shutdown(%s)",
00356 statetoa(state_), howstr);
00357 return -1;
00358 }
00359
00360 return 0;
00361 }
00362
00363 int
00364 IPSocket::send(const char* bp, size_t len, int flags)
00365 {
00366 return IO::send(fd_, bp, len, flags, get_notifier(), logpath_);
00367 }
00368
00369 int
00370 IPSocket::sendto(char* bp, size_t len, int flags,
00371 in_addr_t addr, u_int16_t port)
00372 {
00373 struct sockaddr_in sa;
00374 memset(&sa, 0, sizeof(sa));
00375 sa.sin_family = AF_INET;
00376 sa.sin_addr.s_addr = addr;
00377 sa.sin_port = htons(port);
00378
00379 return IO::sendto(fd_, bp, len, flags, (sockaddr*)&sa,
00380 sizeof(sa), get_notifier(), logpath_);
00381 }
00382
00383 int
00384 IPSocket::sendmsg(const struct msghdr* msg, int flags)
00385 {
00386 return IO::sendmsg(fd_, msg, flags, get_notifier(), logpath_);
00387 }
00388
00389 int
00390 IPSocket::recv(char* bp, size_t len, int flags)
00391 {
00392 return IO::recv(fd_, bp, len, flags,
00393 get_notifier(), logpath_);
00394 }
00395
00396 int
00397 IPSocket::recvfrom(char* bp, size_t len, int flags,
00398 in_addr_t *addr, u_int16_t *port)
00399 {
00400 struct sockaddr_in sa;
00401 socklen_t sl = sizeof(sa);
00402 memset(&sa, 0, sizeof(sa));
00403
00404 int cc = IO::recvfrom(fd_, bp, len, flags, (sockaddr*)&sa, &sl,
00405 get_notifier(), logpath_);
00406
00407 if (cc < 0) {
00408 if (cc != IOINTR)
00409 logf(LOG_ERR, "error in recvfrom(): %s", strerror(errno));
00410 return cc;
00411 }
00412
00413 if (addr)
00414 *addr = sa.sin_addr.s_addr;
00415
00416 if (port)
00417 *port = htons(sa.sin_port);
00418
00419 return cc;
00420 }
00421
00422 int
00423 IPSocket::recvmsg(struct msghdr* msg, int flags)
00424 {
00425 return IO::recvmsg(fd_, msg, flags, get_notifier(), logpath_);
00426 }
00427
00428 int
00429 IPSocket::poll_sockfd(int events, int* revents, int timeout_ms)
00430 {
00431 short s_events = events;
00432 short s_revents;
00433
00434 int cc = IO::poll_single(fd_, s_events, &s_revents, timeout_ms,
00435 get_notifier(), logpath_);
00436
00437 if (revents != 0) {
00438 *revents = s_revents;
00439 }
00440
00441 return cc;
00442 }
00443
00444 }