SocketsOps.cc revision 04e5c324
140161064SShuo Chen// Copyright 2010, Shuo Chen.  All rights reserved.
240161064SShuo Chen// http://code.google.com/p/muduo/
340161064SShuo Chen//
440161064SShuo Chen// Use of this source code is governed by a BSD-style license
540161064SShuo Chen// that can be found in the License file.
640161064SShuo Chen
740161064SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
840161064SShuo Chen
940161064SShuo Chen#include "SocketsOps.h"
1040161064SShuo Chen#include "logging/Logging.h"
1140161064SShuo Chen
1240161064SShuo Chen#include <errno.h>
1340161064SShuo Chen#include <fcntl.h>
1440161064SShuo Chen#include <stdio.h>  // snprintf
1540161064SShuo Chen#include <strings.h>  // bzero
1640161064SShuo Chen#include <sys/socket.h>
1740161064SShuo Chen#include <unistd.h>
1840161064SShuo Chen
1940161064SShuo Chenusing namespace muduo;
2040161064SShuo Chen
2140161064SShuo Chennamespace
2240161064SShuo Chen{
2340161064SShuo Chen
2440161064SShuo Chentypedef struct sockaddr SA;
2540161064SShuo Chen
2640161064SShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr)
2740161064SShuo Chen{
2840161064SShuo Chen  return static_cast<const SA*>(implicit_cast<const void*>(addr));
2940161064SShuo Chen}
3040161064SShuo Chen
3140161064SShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr)
3240161064SShuo Chen{
3340161064SShuo Chen  return static_cast<SA*>(implicit_cast<void*>(addr));
3440161064SShuo Chen}
3540161064SShuo Chen
3640161064SShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd)
3740161064SShuo Chen{
3840161064SShuo Chen  // non-block
3940161064SShuo Chen  int flags = ::fcntl(sockfd, F_GETFL, 0);
4040161064SShuo Chen  flags |= O_NONBLOCK;
4140161064SShuo Chen  int ret = ::fcntl(sockfd, F_SETFL, flags);
4240161064SShuo Chen  // FIXME check
4340161064SShuo Chen
4440161064SShuo Chen  // close-on-exec
4540161064SShuo Chen  flags = ::fcntl(sockfd, F_GETFD, 0);
4640161064SShuo Chen  flags |= FD_CLOEXEC;
4740161064SShuo Chen  ret = ::fcntl(sockfd, F_SETFD, flags);
4840161064SShuo Chen  // FIXME check
4940161064SShuo Chen}
5040161064SShuo Chen
5140161064SShuo Chen}
5240161064SShuo Chen
5340161064SShuo Chenint sockets::createNonblockingOrDie()
5440161064SShuo Chen{
5540161064SShuo Chen  // socket
5640161064SShuo Chen#if VALGRIND
5740161064SShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
5840161064SShuo Chen  if (sockfd < 0)
5940161064SShuo Chen  {
6040161064SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
6140161064SShuo Chen  }
6240161064SShuo Chen
6340161064SShuo Chen  setNonBlockAndCloseOnExec(sockfd);
6440161064SShuo Chen#else
6540161064SShuo Chen  int sockfd = ::socket(AF_INET,
6640161064SShuo Chen                        SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
6740161064SShuo Chen                        IPPROTO_TCP);
6840161064SShuo Chen  if (sockfd < 0)
6940161064SShuo Chen  {
7040161064SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
7140161064SShuo Chen  }
7240161064SShuo Chen#endif
7340161064SShuo Chen  return sockfd;
7440161064SShuo Chen}
7540161064SShuo Chen
7604e5c324SShuo Chenint sockets::connect(int sockfd, const struct sockaddr_in& addr)
7704e5c324SShuo Chen{
7804e5c324SShuo Chen  return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr);
7904e5c324SShuo Chen}
8004e5c324SShuo Chen
8140161064SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
8240161064SShuo Chen{
8340161064SShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
8440161064SShuo Chen  if (ret < 0)
8540161064SShuo Chen  {
8640161064SShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
8740161064SShuo Chen  }
8840161064SShuo Chen}
8940161064SShuo Chen
9040161064SShuo Chenvoid sockets::listenOrDie(int sockfd)
9140161064SShuo Chen{
9240161064SShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
9340161064SShuo Chen  if (ret < 0)
9440161064SShuo Chen  {
9540161064SShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
9640161064SShuo Chen  }
9740161064SShuo Chen}
9840161064SShuo Chen
9940161064SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
10040161064SShuo Chen{
10140161064SShuo Chen  socklen_t addrlen = sizeof *addr;
10240161064SShuo Chen#if VALGRIND
10340161064SShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
10440161064SShuo Chen  setNonBlockAndCloseOnExec(connfd);
10540161064SShuo Chen#else
10640161064SShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
10740161064SShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
10840161064SShuo Chen#endif
10940161064SShuo Chen  if (connfd < 0)
11040161064SShuo Chen  {
11140161064SShuo Chen    int savedErrno = errno;
11240161064SShuo Chen    LOG_SYSERR << "Socket::accept";
11340161064SShuo Chen    switch (savedErrno)
11440161064SShuo Chen    {
11540161064SShuo Chen      case EAGAIN:
11640161064SShuo Chen      case ECONNABORTED:
11740161064SShuo Chen      case EINTR:
11840161064SShuo Chen      case EPROTO: // ???
11940161064SShuo Chen      case EPERM:
12040161064SShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
12140161064SShuo Chen        // expected errors
12240161064SShuo Chen        errno = savedErrno;
12340161064SShuo Chen        break;
12440161064SShuo Chen      case EBADF:
12540161064SShuo Chen      case EFAULT:
12640161064SShuo Chen      case EINVAL:
12740161064SShuo Chen      case ENFILE:
12840161064SShuo Chen      case ENOBUFS:
12940161064SShuo Chen      case ENOMEM:
13040161064SShuo Chen      case ENOTSOCK:
13140161064SShuo Chen      case EOPNOTSUPP:
13240161064SShuo Chen        // unexpected errors
13340161064SShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
13440161064SShuo Chen        break;
13540161064SShuo Chen      default:
13640161064SShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
13740161064SShuo Chen        break;
13840161064SShuo Chen    }
13940161064SShuo Chen  }
14040161064SShuo Chen  return connfd;
14140161064SShuo Chen}
14240161064SShuo Chen
14340161064SShuo Chenvoid sockets::close(int sockfd)
14440161064SShuo Chen{
14540161064SShuo Chen  if (::close(sockfd) < 0)
14640161064SShuo Chen  {
14740161064SShuo Chen    LOG_SYSERR << "sockets::close";
14840161064SShuo Chen  }
14940161064SShuo Chen}
15040161064SShuo Chen
15140161064SShuo Chenvoid sockets::shutdownWrite(int sockfd)
15240161064SShuo Chen{
15340161064SShuo Chen  if (::shutdown(sockfd, SHUT_WR) < 0)
15440161064SShuo Chen  {
15540161064SShuo Chen    LOG_SYSERR << "sockets::shutdownWrite";
15640161064SShuo Chen  }
15740161064SShuo Chen}
15840161064SShuo Chen
15940161064SShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
16040161064SShuo Chen                         const struct sockaddr_in& addr)
16140161064SShuo Chen{
16240161064SShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
16340161064SShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
16440161064SShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
16540161064SShuo Chen  snprintf(buf, size, "%s:%u", host, port);
16640161064SShuo Chen}
16740161064SShuo Chen
16840161064SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
16940161064SShuo Chen                           struct sockaddr_in* addr)
17040161064SShuo Chen{
17140161064SShuo Chen  addr->sin_family = AF_INET;
17240161064SShuo Chen  addr->sin_port = hostToNetwork16(port);
17340161064SShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
17440161064SShuo Chen  {
17540161064SShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
17640161064SShuo Chen  }
17740161064SShuo Chen}
17840161064SShuo Chen
17940161064SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
18040161064SShuo Chen{
18140161064SShuo Chen  struct sockaddr_in localaddr;
18240161064SShuo Chen  bzero(&localaddr, sizeof localaddr);
18340161064SShuo Chen  socklen_t addrlen = sizeof(localaddr);
18440161064SShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
18540161064SShuo Chen  {
18640161064SShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
18740161064SShuo Chen  }
18840161064SShuo Chen  return localaddr;
18940161064SShuo Chen}
19040161064SShuo Chen
19104e5c324SShuo Chenstruct sockaddr_in sockets::getPeerAddr(int sockfd)
19204e5c324SShuo Chen{
19304e5c324SShuo Chen  struct sockaddr_in peeraddr;
19404e5c324SShuo Chen  bzero(&peeraddr, sizeof peeraddr);
19504e5c324SShuo Chen  socklen_t addrlen = sizeof(peeraddr);
19604e5c324SShuo Chen  if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0)
19704e5c324SShuo Chen  {
19804e5c324SShuo Chen    LOG_SYSERR << "sockets::getPeerAddr";
19904e5c324SShuo Chen  }
20004e5c324SShuo Chen  return peeraddr;
20104e5c324SShuo Chen}
20204e5c324SShuo Chen
20340161064SShuo Chenint sockets::getSocketError(int sockfd)
20440161064SShuo Chen{
20540161064SShuo Chen  int optval;
20640161064SShuo Chen  socklen_t optlen = sizeof optval;
20740161064SShuo Chen
20840161064SShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
20940161064SShuo Chen  {
21040161064SShuo Chen    return errno;
21140161064SShuo Chen  }
21240161064SShuo Chen  else
21340161064SShuo Chen  {
21440161064SShuo Chen    return optval;
21540161064SShuo Chen  }
21640161064SShuo Chen}
21704e5c324SShuo Chen
21804e5c324SShuo Chenbool sockets::isSelfConnect(int sockfd)
21904e5c324SShuo Chen{
22004e5c324SShuo Chen  struct sockaddr_in localaddr = getLocalAddr(sockfd);
22104e5c324SShuo Chen  struct sockaddr_in peeraddr = getPeerAddr(sockfd);
22204e5c324SShuo Chen  return localaddr.sin_port == peeraddr.sin_port
22304e5c324SShuo Chen      && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr;
22404e5c324SShuo Chen}
225