// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // Author: Shuo Chen (chenshuo at chenshuo dot com) #include "SocketsOps.h" #include "logging/Logging.h" #include #include #include // snprintf #include // bzero #include #include using namespace muduo; namespace { typedef struct sockaddr SA; const SA* sockaddr_cast(const struct sockaddr_in* addr) { return static_cast(implicit_cast(addr)); } SA* sockaddr_cast(struct sockaddr_in* addr) { return static_cast(implicit_cast(addr)); } void setNonBlockAndCloseOnExec(int sockfd) { // non-block int flags = ::fcntl(sockfd, F_GETFL, 0); flags |= O_NONBLOCK; int ret = ::fcntl(sockfd, F_SETFL, flags); // FIXME check // close-on-exec flags = ::fcntl(sockfd, F_GETFD, 0); flags |= FD_CLOEXEC; ret = ::fcntl(sockfd, F_SETFD, flags); // FIXME check } } int sockets::createNonblockingOrDie() { // socket #if VALGRIND int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockfd < 0) { LOG_SYSFATAL << "sockets::createNonblockingOrDie"; } setNonBlockAndCloseOnExec(sockfd); #else int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); if (sockfd < 0) { LOG_SYSFATAL << "sockets::createNonblockingOrDie"; } #endif return sockfd; } void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) { int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); if (ret < 0) { LOG_SYSFATAL << "sockets::bindOrDie"; } } void sockets::listenOrDie(int sockfd) { int ret = ::listen(sockfd, SOMAXCONN); if (ret < 0) { LOG_SYSFATAL << "sockets::listenOrDie"; } } int sockets::accept(int sockfd, struct sockaddr_in* addr) { socklen_t addrlen = sizeof *addr; #if VALGRIND int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); setNonBlockAndCloseOnExec(connfd); #else int connfd = ::accept4(sockfd, sockaddr_cast(addr), &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); #endif if (connfd < 0) { int savedErrno = errno; LOG_SYSERR << "Socket::accept"; switch (savedErrno) { case EAGAIN: case ECONNABORTED: case EINTR: case EPROTO: // ??? case EPERM: case EMFILE: // per-process lmit of open file desctiptor ??? // expected errors errno = savedErrno; break; case EBADF: case EFAULT: case EINVAL: case ENFILE: case ENOBUFS: case ENOMEM: case ENOTSOCK: case EOPNOTSUPP: // unexpected errors LOG_FATAL << "unexpected error of ::accept " << savedErrno; break; default: LOG_FATAL << "unknown error of ::accept " << savedErrno; break; } } return connfd; } void sockets::close(int sockfd) { if (::close(sockfd) < 0) { LOG_SYSERR << "sockets::close"; } } void sockets::toHostPort(char* buf, size_t size, const struct sockaddr_in& addr) { char host[INET_ADDRSTRLEN] = "INVALID"; ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); uint16_t port = sockets::networkToHost16(addr.sin_port); snprintf(buf, size, "%s:%u", host, port); } void sockets::fromHostPort(const char* ip, uint16_t port, struct sockaddr_in* addr) { addr->sin_family = AF_INET; addr->sin_port = hostToNetwork16(port); if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) { LOG_SYSERR << "sockets::fromHostPort"; } } struct sockaddr_in sockets::getLocalAddr(int sockfd) { struct sockaddr_in localaddr; bzero(&localaddr, sizeof localaddr); socklen_t addrlen = sizeof(localaddr); if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) { LOG_SYSERR << "sockets::getLocalAddr"; } return localaddr; } int sockets::getSocketError(int sockfd) { int optval; socklen_t optlen = sizeof optval; if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) { return errno; } else { return optval; } }