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