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
65b4a5ce52SShuo Chen  int sockfd = ::socket(AF_INET,
66b4a5ce52SShuo Chen                        SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
67b4a5ce52SShuo Chen                        IPPROTO_TCP);
682a18e699SShuo Chen  if (sockfd < 0)
692a18e699SShuo Chen  {
702a18e699SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
712a18e699SShuo Chen  }
722a18e699SShuo Chen#endif
732a18e699SShuo Chen  return sockfd;
742a18e699SShuo Chen}
752a18e699SShuo Chen
762a18e699SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
772a18e699SShuo Chen{
782a18e699SShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
792a18e699SShuo Chen  if (ret < 0)
802a18e699SShuo Chen  {
812a18e699SShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
822a18e699SShuo Chen  }
832a18e699SShuo Chen}
842a18e699SShuo Chen
852a18e699SShuo Chenvoid sockets::listenOrDie(int sockfd)
862a18e699SShuo Chen{
872a18e699SShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
882a18e699SShuo Chen  if (ret < 0)
892a18e699SShuo Chen  {
902a18e699SShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
912a18e699SShuo Chen  }
922a18e699SShuo Chen}
932a18e699SShuo Chen
942a18e699SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
952a18e699SShuo Chen{
962a18e699SShuo Chen  socklen_t addrlen = sizeof *addr;
972a18e699SShuo Chen#if VALGRIND
982a18e699SShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
992a18e699SShuo Chen  setNonBlockAndCloseOnExec(connfd);
1002a18e699SShuo Chen#else
1012a18e699SShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
1022a18e699SShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1032a18e699SShuo Chen#endif
1042a18e699SShuo Chen  if (connfd < 0)
1052a18e699SShuo Chen  {
1062a18e699SShuo Chen    int savedErrno = errno;
1072a18e699SShuo Chen    LOG_SYSERR << "Socket::accept";
1082a18e699SShuo Chen    switch (savedErrno)
1092a18e699SShuo Chen    {
1102a18e699SShuo Chen      case EAGAIN:
1112a18e699SShuo Chen      case ECONNABORTED:
1122a18e699SShuo Chen      case EINTR:
1132a18e699SShuo Chen      case EPROTO: // ???
1142a18e699SShuo Chen      case EPERM:
1152a18e699SShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
1162a18e699SShuo Chen        // expected errors
1172a18e699SShuo Chen        errno = savedErrno;
1182a18e699SShuo Chen        break;
1192a18e699SShuo Chen      case EBADF:
1202a18e699SShuo Chen      case EFAULT:
1212a18e699SShuo Chen      case EINVAL:
1222a18e699SShuo Chen      case ENFILE:
1232a18e699SShuo Chen      case ENOBUFS:
1242a18e699SShuo Chen      case ENOMEM:
1252a18e699SShuo Chen      case ENOTSOCK:
1262a18e699SShuo Chen      case EOPNOTSUPP:
1272a18e699SShuo Chen        // unexpected errors
1282a18e699SShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
1292a18e699SShuo Chen        break;
1302a18e699SShuo Chen      default:
1312a18e699SShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
1322a18e699SShuo Chen        break;
1332a18e699SShuo Chen    }
1342a18e699SShuo Chen  }
1352a18e699SShuo Chen  return connfd;
1362a18e699SShuo Chen}
1372a18e699SShuo Chen
1382a18e699SShuo Chenvoid sockets::close(int sockfd)
1392a18e699SShuo Chen{
1402a18e699SShuo Chen  if (::close(sockfd) < 0)
1412a18e699SShuo Chen  {
1422a18e699SShuo Chen    LOG_SYSERR << "sockets::close";
1432a18e699SShuo Chen  }
1442a18e699SShuo Chen}
1452a18e699SShuo Chen
146129fe122SShuo Chenvoid sockets::shutdownWrite(int sockfd)
147129fe122SShuo Chen{
148129fe122SShuo Chen  if (::shutdown(sockfd, SHUT_WR) < 0)
149129fe122SShuo Chen  {
150129fe122SShuo Chen    LOG_SYSERR << "sockets::shutdownWrite";
151129fe122SShuo Chen  }
152129fe122SShuo Chen}
153129fe122SShuo Chen
1542a18e699SShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
1552a18e699SShuo Chen                         const struct sockaddr_in& addr)
1562a18e699SShuo Chen{
1572a18e699SShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
1582a18e699SShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
1592a18e699SShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
1602a18e699SShuo Chen  snprintf(buf, size, "%s:%u", host, port);
1612a18e699SShuo Chen}
1622a18e699SShuo Chen
1632a18e699SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
1642a18e699SShuo Chen                           struct sockaddr_in* addr)
1652a18e699SShuo Chen{
1662a18e699SShuo Chen  addr->sin_family = AF_INET;
1672a18e699SShuo Chen  addr->sin_port = hostToNetwork16(port);
1682a18e699SShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
1692a18e699SShuo Chen  {
1702a18e699SShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
1712a18e699SShuo Chen  }
1722a18e699SShuo Chen}
1732a18e699SShuo Chen
1742a18e699SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
1752a18e699SShuo Chen{
1762a18e699SShuo Chen  struct sockaddr_in localaddr;
1772a18e699SShuo Chen  bzero(&localaddr, sizeof localaddr);
1782a18e699SShuo Chen  socklen_t addrlen = sizeof(localaddr);
1792a18e699SShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
1802a18e699SShuo Chen  {
1812a18e699SShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
1822a18e699SShuo Chen  }
1832a18e699SShuo Chen  return localaddr;
1842a18e699SShuo Chen}
1852a18e699SShuo Chen
1862a18e699SShuo Chenint sockets::getSocketError(int sockfd)
1872a18e699SShuo Chen{
1882a18e699SShuo Chen  int optval;
1892a18e699SShuo Chen  socklen_t optlen = sizeof optval;
1902a18e699SShuo Chen
1912a18e699SShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
1922a18e699SShuo Chen  {
1932a18e699SShuo Chen    return errno;
1942a18e699SShuo Chen  }
1952a18e699SShuo Chen  else
1962a18e699SShuo Chen  {
1972a18e699SShuo Chen    return optval;
1982a18e699SShuo Chen  }
1992a18e699SShuo Chen}
200