SocketsOps.cc revision 129fe122
12a18e699SShuo Chen// Copyright 2010, Shuo Chen.  All rights reserved.
22a18e699SShuo Chen// http://code.google.com/p/muduo/
32a18e699SShuo Chen//
42a18e699SShuo Chen// Use of this source code is governed by a BSD-style license
52a18e699SShuo Chen// that can be found in the License file.
62a18e699SShuo Chen
72a18e699SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
82a18e699SShuo Chen
92a18e699SShuo Chen#include "SocketsOps.h"
102a18e699SShuo Chen#include "logging/Logging.h"
112a18e699SShuo Chen
122a18e699SShuo Chen#include <errno.h>
132a18e699SShuo Chen#include <fcntl.h>
142a18e699SShuo Chen#include <stdio.h>  // snprintf
152a18e699SShuo Chen#include <strings.h>  // bzero
162a18e699SShuo Chen#include <sys/socket.h>
172a18e699SShuo Chen#include <unistd.h>
182a18e699SShuo Chen
192a18e699SShuo Chenusing namespace muduo;
202a18e699SShuo Chen
212a18e699SShuo Chennamespace
222a18e699SShuo Chen{
232a18e699SShuo Chen
242a18e699SShuo Chentypedef struct sockaddr SA;
252a18e699SShuo Chen
262a18e699SShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr)
272a18e699SShuo Chen{
282a18e699SShuo Chen  return static_cast<const SA*>(implicit_cast<const void*>(addr));
292a18e699SShuo Chen}
302a18e699SShuo Chen
312a18e699SShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr)
322a18e699SShuo Chen{
332a18e699SShuo Chen  return static_cast<SA*>(implicit_cast<void*>(addr));
342a18e699SShuo Chen}
352a18e699SShuo Chen
362a18e699SShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd)
372a18e699SShuo Chen{
382a18e699SShuo Chen  // non-block
392a18e699SShuo Chen  int flags = ::fcntl(sockfd, F_GETFL, 0);
402a18e699SShuo Chen  flags |= O_NONBLOCK;
412a18e699SShuo Chen  int ret = ::fcntl(sockfd, F_SETFL, flags);
422a18e699SShuo Chen  // FIXME check
432a18e699SShuo Chen
442a18e699SShuo Chen  // close-on-exec
452a18e699SShuo Chen  flags = ::fcntl(sockfd, F_GETFD, 0);
462a18e699SShuo Chen  flags |= FD_CLOEXEC;
472a18e699SShuo Chen  ret = ::fcntl(sockfd, F_SETFD, flags);
482a18e699SShuo Chen  // FIXME check
492a18e699SShuo Chen}
502a18e699SShuo Chen
512a18e699SShuo Chen}
522a18e699SShuo Chen
532a18e699SShuo Chenint sockets::createNonblockingOrDie()
542a18e699SShuo Chen{
552a18e699SShuo Chen  // socket
562a18e699SShuo Chen#if VALGRIND
572a18e699SShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
582a18e699SShuo Chen  if (sockfd < 0)
592a18e699SShuo Chen  {
602a18e699SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
612a18e699SShuo Chen  }
622a18e699SShuo Chen
632a18e699SShuo Chen  setNonBlockAndCloseOnExec(sockfd);
642a18e699SShuo Chen#else
652a18e699SShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
662a18e699SShuo Chen  if (sockfd < 0)
672a18e699SShuo Chen  {
682a18e699SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
692a18e699SShuo Chen  }
702a18e699SShuo Chen#endif
712a18e699SShuo Chen  return sockfd;
722a18e699SShuo Chen}
732a18e699SShuo Chen
742a18e699SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
752a18e699SShuo Chen{
762a18e699SShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
772a18e699SShuo Chen  if (ret < 0)
782a18e699SShuo Chen  {
792a18e699SShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
802a18e699SShuo Chen  }
812a18e699SShuo Chen}
822a18e699SShuo Chen
832a18e699SShuo Chenvoid sockets::listenOrDie(int sockfd)
842a18e699SShuo Chen{
852a18e699SShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
862a18e699SShuo Chen  if (ret < 0)
872a18e699SShuo Chen  {
882a18e699SShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
892a18e699SShuo Chen  }
902a18e699SShuo Chen}
912a18e699SShuo Chen
922a18e699SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
932a18e699SShuo Chen{
942a18e699SShuo Chen  socklen_t addrlen = sizeof *addr;
952a18e699SShuo Chen#if VALGRIND
962a18e699SShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
972a18e699SShuo Chen  setNonBlockAndCloseOnExec(connfd);
982a18e699SShuo Chen#else
992a18e699SShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
1002a18e699SShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1012a18e699SShuo Chen#endif
1022a18e699SShuo Chen  if (connfd < 0)
1032a18e699SShuo Chen  {
1042a18e699SShuo Chen    int savedErrno = errno;
1052a18e699SShuo Chen    LOG_SYSERR << "Socket::accept";
1062a18e699SShuo Chen    switch (savedErrno)
1072a18e699SShuo Chen    {
1082a18e699SShuo Chen      case EAGAIN:
1092a18e699SShuo Chen      case ECONNABORTED:
1102a18e699SShuo Chen      case EINTR:
1112a18e699SShuo Chen      case EPROTO: // ???
1122a18e699SShuo Chen      case EPERM:
1132a18e699SShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
1142a18e699SShuo Chen        // expected errors
1152a18e699SShuo Chen        errno = savedErrno;
1162a18e699SShuo Chen        break;
1172a18e699SShuo Chen      case EBADF:
1182a18e699SShuo Chen      case EFAULT:
1192a18e699SShuo Chen      case EINVAL:
1202a18e699SShuo Chen      case ENFILE:
1212a18e699SShuo Chen      case ENOBUFS:
1222a18e699SShuo Chen      case ENOMEM:
1232a18e699SShuo Chen      case ENOTSOCK:
1242a18e699SShuo Chen      case EOPNOTSUPP:
1252a18e699SShuo Chen        // unexpected errors
1262a18e699SShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
1272a18e699SShuo Chen        break;
1282a18e699SShuo Chen      default:
1292a18e699SShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
1302a18e699SShuo Chen        break;
1312a18e699SShuo Chen    }
1322a18e699SShuo Chen  }
1332a18e699SShuo Chen  return connfd;
1342a18e699SShuo Chen}
1352a18e699SShuo Chen
1362a18e699SShuo Chenvoid sockets::close(int sockfd)
1372a18e699SShuo Chen{
1382a18e699SShuo Chen  if (::close(sockfd) < 0)
1392a18e699SShuo Chen  {
1402a18e699SShuo Chen    LOG_SYSERR << "sockets::close";
1412a18e699SShuo Chen  }
1422a18e699SShuo Chen}
1432a18e699SShuo Chen
144129fe122SShuo Chenvoid sockets::shutdownWrite(int sockfd)
145129fe122SShuo Chen{
146129fe122SShuo Chen  if (::shutdown(sockfd, SHUT_WR) < 0)
147129fe122SShuo Chen  {
148129fe122SShuo Chen    LOG_SYSERR << "sockets::shutdownWrite";
149129fe122SShuo Chen  }
150129fe122SShuo Chen}
151129fe122SShuo Chen
1522a18e699SShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
1532a18e699SShuo Chen                         const struct sockaddr_in& addr)
1542a18e699SShuo Chen{
1552a18e699SShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
1562a18e699SShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
1572a18e699SShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
1582a18e699SShuo Chen  snprintf(buf, size, "%s:%u", host, port);
1592a18e699SShuo Chen}
1602a18e699SShuo Chen
1612a18e699SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
1622a18e699SShuo Chen                           struct sockaddr_in* addr)
1632a18e699SShuo Chen{
1642a18e699SShuo Chen  addr->sin_family = AF_INET;
1652a18e699SShuo Chen  addr->sin_port = hostToNetwork16(port);
1662a18e699SShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
1672a18e699SShuo Chen  {
1682a18e699SShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
1692a18e699SShuo Chen  }
1702a18e699SShuo Chen}
1712a18e699SShuo Chen
1722a18e699SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
1732a18e699SShuo Chen{
1742a18e699SShuo Chen  struct sockaddr_in localaddr;
1752a18e699SShuo Chen  bzero(&localaddr, sizeof localaddr);
1762a18e699SShuo Chen  socklen_t addrlen = sizeof(localaddr);
1772a18e699SShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
1782a18e699SShuo Chen  {
1792a18e699SShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
1802a18e699SShuo Chen  }
1812a18e699SShuo Chen  return localaddr;
1822a18e699SShuo Chen}
1832a18e699SShuo Chen
1842a18e699SShuo Chenint sockets::getSocketError(int sockfd)
1852a18e699SShuo Chen{
1862a18e699SShuo Chen  int optval;
1872a18e699SShuo Chen  socklen_t optlen = sizeof optval;
1882a18e699SShuo Chen
1892a18e699SShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
1902a18e699SShuo Chen  {
1912a18e699SShuo Chen    return errno;
1922a18e699SShuo Chen  }
1932a18e699SShuo Chen  else
1942a18e699SShuo Chen  {
1952a18e699SShuo Chen    return optval;
1962a18e699SShuo Chen  }
1972a18e699SShuo Chen}
198