11bc8a9dfSShuo Chen // Copyright 2010, Shuo Chen.  All rights reserved.
21bc8a9dfSShuo Chen // http://code.google.com/p/muduo/
31bc8a9dfSShuo Chen //
41bc8a9dfSShuo Chen // Use of this source code is governed by a BSD-style license
51bc8a9dfSShuo Chen // that can be found in the License file.
61bc8a9dfSShuo Chen 
71bc8a9dfSShuo Chen // Author: Shuo Chen (chenshuo at chenshuo dot com)
81bc8a9dfSShuo Chen 
91bc8a9dfSShuo Chen #include "SocketsOps.h"
101bc8a9dfSShuo Chen #include "logging/Logging.h"
111bc8a9dfSShuo Chen 
121bc8a9dfSShuo Chen #include <errno.h>
131bc8a9dfSShuo Chen #include <fcntl.h>
141bc8a9dfSShuo Chen #include <stdio.h>  // snprintf
151bc8a9dfSShuo Chen #include <strings.h>  // bzero
161bc8a9dfSShuo Chen #include <sys/socket.h>
171bc8a9dfSShuo Chen #include <unistd.h>
181bc8a9dfSShuo Chen 
191bc8a9dfSShuo Chen using namespace muduo;
201bc8a9dfSShuo Chen 
211bc8a9dfSShuo Chen namespace
221bc8a9dfSShuo Chen {
231bc8a9dfSShuo Chen 
241bc8a9dfSShuo Chen typedef struct sockaddr SA;
251bc8a9dfSShuo Chen 
261bc8a9dfSShuo Chen const SA* sockaddr_cast(const struct sockaddr_in* addr)
271bc8a9dfSShuo Chen {
281bc8a9dfSShuo Chen   return static_cast<const SA*>(implicit_cast<const void*>(addr));
291bc8a9dfSShuo Chen }
301bc8a9dfSShuo Chen 
311bc8a9dfSShuo Chen SA* sockaddr_cast(struct sockaddr_in* addr)
321bc8a9dfSShuo Chen {
331bc8a9dfSShuo Chen   return static_cast<SA*>(implicit_cast<void*>(addr));
341bc8a9dfSShuo Chen }
351bc8a9dfSShuo Chen 
361bc8a9dfSShuo Chen void setNonBlockAndCloseOnExec(int sockfd)
371bc8a9dfSShuo Chen {
381bc8a9dfSShuo Chen   // non-block
391bc8a9dfSShuo Chen   int flags = ::fcntl(sockfd, F_GETFL, 0);
401bc8a9dfSShuo Chen   flags |= O_NONBLOCK;
411bc8a9dfSShuo Chen   int ret = ::fcntl(sockfd, F_SETFL, flags);
421bc8a9dfSShuo Chen   // FIXME check
431bc8a9dfSShuo Chen 
441bc8a9dfSShuo Chen   // close-on-exec
451bc8a9dfSShuo Chen   flags = ::fcntl(sockfd, F_GETFD, 0);
461bc8a9dfSShuo Chen   flags |= FD_CLOEXEC;
471bc8a9dfSShuo Chen   ret = ::fcntl(sockfd, F_SETFD, flags);
481bc8a9dfSShuo Chen   // FIXME check
491bc8a9dfSShuo Chen }
501bc8a9dfSShuo Chen 
511bc8a9dfSShuo Chen }
521bc8a9dfSShuo Chen 
531bc8a9dfSShuo Chen int sockets::createNonblockingOrDie()
541bc8a9dfSShuo Chen {
551bc8a9dfSShuo Chen   // socket
561bc8a9dfSShuo Chen #if VALGRIND
571bc8a9dfSShuo Chen   int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
581bc8a9dfSShuo Chen   if (sockfd < 0)
591bc8a9dfSShuo Chen   {
601bc8a9dfSShuo Chen     LOG_SYSFATAL << "sockets::createNonblockingOrDie";
611bc8a9dfSShuo Chen   }
621bc8a9dfSShuo Chen 
631bc8a9dfSShuo Chen   setNonBlockAndCloseOnExec(sockfd);
641bc8a9dfSShuo Chen #else
650f776063SShuo Chen   int sockfd = ::socket(AF_INET,
660f776063SShuo Chen                         SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
670f776063SShuo Chen                         IPPROTO_TCP);
681bc8a9dfSShuo Chen   if (sockfd < 0)
691bc8a9dfSShuo Chen   {
701bc8a9dfSShuo Chen     LOG_SYSFATAL << "sockets::createNonblockingOrDie";
711bc8a9dfSShuo Chen   }
721bc8a9dfSShuo Chen #endif
731bc8a9dfSShuo Chen   return sockfd;
741bc8a9dfSShuo Chen }
751bc8a9dfSShuo Chen 
761bc8a9dfSShuo Chen void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
771bc8a9dfSShuo Chen {
781bc8a9dfSShuo Chen   int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
791bc8a9dfSShuo Chen   if (ret < 0)
801bc8a9dfSShuo Chen   {
811bc8a9dfSShuo Chen     LOG_SYSFATAL << "sockets::bindOrDie";
821bc8a9dfSShuo Chen   }
831bc8a9dfSShuo Chen }
841bc8a9dfSShuo Chen 
851bc8a9dfSShuo Chen void sockets::listenOrDie(int sockfd)
861bc8a9dfSShuo Chen {
871bc8a9dfSShuo Chen   int ret = ::listen(sockfd, SOMAXCONN);
881bc8a9dfSShuo Chen   if (ret < 0)
891bc8a9dfSShuo Chen   {
901bc8a9dfSShuo Chen     LOG_SYSFATAL << "sockets::listenOrDie";
911bc8a9dfSShuo Chen   }
921bc8a9dfSShuo Chen }
931bc8a9dfSShuo Chen 
941bc8a9dfSShuo Chen int sockets::accept(int sockfd, struct sockaddr_in* addr)
951bc8a9dfSShuo Chen {
961bc8a9dfSShuo Chen   socklen_t addrlen = sizeof *addr;
971bc8a9dfSShuo Chen #if VALGRIND
981bc8a9dfSShuo Chen   int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
991bc8a9dfSShuo Chen   setNonBlockAndCloseOnExec(connfd);
1001bc8a9dfSShuo Chen #else
1011bc8a9dfSShuo Chen   int connfd = ::accept4(sockfd, sockaddr_cast(addr),
1021bc8a9dfSShuo Chen                          &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1031bc8a9dfSShuo Chen #endif
1041bc8a9dfSShuo Chen   if (connfd < 0)
1051bc8a9dfSShuo Chen   {
1061bc8a9dfSShuo Chen     int savedErrno = errno;
1071bc8a9dfSShuo Chen     LOG_SYSERR << "Socket::accept";
1081bc8a9dfSShuo Chen     switch (savedErrno)
1091bc8a9dfSShuo Chen     {
1101bc8a9dfSShuo Chen       case EAGAIN:
1111bc8a9dfSShuo Chen       case ECONNABORTED:
1121bc8a9dfSShuo Chen       case EINTR:
1131bc8a9dfSShuo Chen       case EPROTO: // ???
1141bc8a9dfSShuo Chen       case EPERM:
1151bc8a9dfSShuo Chen       case EMFILE: // per-process lmit of open file desctiptor ???
1161bc8a9dfSShuo Chen         // expected errors
1171bc8a9dfSShuo Chen         errno = savedErrno;
1181bc8a9dfSShuo Chen         break;
1191bc8a9dfSShuo Chen       case EBADF:
1201bc8a9dfSShuo Chen       case EFAULT:
1211bc8a9dfSShuo Chen       case EINVAL:
1221bc8a9dfSShuo Chen       case ENFILE:
1231bc8a9dfSShuo Chen       case ENOBUFS:
1241bc8a9dfSShuo Chen       case ENOMEM:
1251bc8a9dfSShuo Chen       case ENOTSOCK:
1261bc8a9dfSShuo Chen       case EOPNOTSUPP:
1271bc8a9dfSShuo Chen         // unexpected errors
1281bc8a9dfSShuo Chen         LOG_FATAL << "unexpected error of ::accept " << savedErrno;
1291bc8a9dfSShuo Chen         break;
1301bc8a9dfSShuo Chen       default:
1311bc8a9dfSShuo Chen         LOG_FATAL << "unknown error of ::accept " << savedErrno;
1321bc8a9dfSShuo Chen         break;
1331bc8a9dfSShuo Chen     }
1341bc8a9dfSShuo Chen   }
1351bc8a9dfSShuo Chen   return connfd;
1361bc8a9dfSShuo Chen }
1371bc8a9dfSShuo Chen 
1381bc8a9dfSShuo Chen void sockets::close(int sockfd)
1391bc8a9dfSShuo Chen {
1401bc8a9dfSShuo Chen   if (::close(sockfd) < 0)
1411bc8a9dfSShuo Chen   {
1421bc8a9dfSShuo Chen     LOG_SYSERR << "sockets::close";
1431bc8a9dfSShuo Chen   }
1441bc8a9dfSShuo Chen }
1451bc8a9dfSShuo Chen 
1461bc8a9dfSShuo Chen+void sockets::shutdownWrite(int sockfd)
1471bc8a9dfSShuo Chen+{
1481bc8a9dfSShuo Chen+  if (::shutdown(sockfd, SHUT_WR) < 0)
1491bc8a9dfSShuo Chen+  {
1501bc8a9dfSShuo Chen+    LOG_SYSERR << "sockets::shutdownWrite";
1511bc8a9dfSShuo Chen+  }
1521bc8a9dfSShuo Chen+}
1531bc8a9dfSShuo Chen+
1541bc8a9dfSShuo Chen void sockets::toHostPort(char* buf, size_t size,
1551bc8a9dfSShuo Chen                          const struct sockaddr_in& addr)
1561bc8a9dfSShuo Chen {
1571bc8a9dfSShuo Chen   char host[INET_ADDRSTRLEN] = "INVALID";
1581bc8a9dfSShuo Chen   ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
1591bc8a9dfSShuo Chen   uint16_t port = sockets::networkToHost16(addr.sin_port);
1601bc8a9dfSShuo Chen   snprintf(buf, size, "%s:%u", host, port);
1611bc8a9dfSShuo Chen }
1621bc8a9dfSShuo Chen 
1631bc8a9dfSShuo Chen void sockets::fromHostPort(const char* ip, uint16_t port,
1641bc8a9dfSShuo Chen                            struct sockaddr_in* addr)
1651bc8a9dfSShuo Chen {
1661bc8a9dfSShuo Chen   addr->sin_family = AF_INET;
1671bc8a9dfSShuo Chen   addr->sin_port = hostToNetwork16(port);
1681bc8a9dfSShuo Chen   if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
1691bc8a9dfSShuo Chen   {
1701bc8a9dfSShuo Chen     LOG_SYSERR << "sockets::fromHostPort";
1711bc8a9dfSShuo Chen   }
1721bc8a9dfSShuo Chen }
1731bc8a9dfSShuo Chen 
1741bc8a9dfSShuo Chen struct sockaddr_in sockets::getLocalAddr(int sockfd)
1751bc8a9dfSShuo Chen {
1761bc8a9dfSShuo Chen   struct sockaddr_in localaddr;
1771bc8a9dfSShuo Chen   bzero(&localaddr, sizeof localaddr);
1781bc8a9dfSShuo Chen   socklen_t addrlen = sizeof(localaddr);
1791bc8a9dfSShuo Chen   if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
1801bc8a9dfSShuo Chen   {
1811bc8a9dfSShuo Chen     LOG_SYSERR << "sockets::getLocalAddr";
1821bc8a9dfSShuo Chen   }
1831bc8a9dfSShuo Chen   return localaddr;
1841bc8a9dfSShuo Chen }
1851bc8a9dfSShuo Chen 
1861bc8a9dfSShuo Chen int sockets::getSocketError(int sockfd)
1871bc8a9dfSShuo Chen {
1881bc8a9dfSShuo Chen   int optval;
1891bc8a9dfSShuo Chen   socklen_t optlen = sizeof optval;
1901bc8a9dfSShuo Chen 
1911bc8a9dfSShuo Chen   if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
1921bc8a9dfSShuo Chen   {
1931bc8a9dfSShuo Chen     return errno;
1941bc8a9dfSShuo Chen   }
1951bc8a9dfSShuo Chen   else
1961bc8a9dfSShuo Chen   {
1971bc8a9dfSShuo Chen     return optval;
1981bc8a9dfSShuo Chen   }
1991bc8a9dfSShuo Chen }
200