1f4e8e3d3SShuo Chen // Copyright 2010, Shuo Chen. All rights reserved. 2f4e8e3d3SShuo Chen // http://code.google.com/p/muduo/ 3f4e8e3d3SShuo Chen // 4f4e8e3d3SShuo Chen // Use of this source code is governed by a BSD-style license 5f4e8e3d3SShuo Chen // that can be found in the License file. 6f4e8e3d3SShuo Chen 7f4e8e3d3SShuo Chen // Author: Shuo Chen (chenshuo at chenshuo dot com) 8f4e8e3d3SShuo Chen 9f4e8e3d3SShuo Chen #include "SocketsOps.h" 10f4e8e3d3SShuo Chen #include "logging/Logging.h" 11f4e8e3d3SShuo Chen 12f4e8e3d3SShuo Chen #include <errno.h> 13f4e8e3d3SShuo Chen #include <fcntl.h> 14f4e8e3d3SShuo Chen #include <stdio.h> // snprintf 15f4e8e3d3SShuo Chen #include <strings.h> // bzero 16f4e8e3d3SShuo Chen #include <sys/socket.h> 17f4e8e3d3SShuo Chen #include <unistd.h> 18f4e8e3d3SShuo Chen 19f4e8e3d3SShuo Chen using namespace muduo; 20f4e8e3d3SShuo Chen 21f4e8e3d3SShuo Chen namespace 22f4e8e3d3SShuo Chen { 23f4e8e3d3SShuo Chen 24f4e8e3d3SShuo Chen typedef struct sockaddr SA; 25f4e8e3d3SShuo Chen 26f4e8e3d3SShuo Chen const SA* sockaddr_cast(const struct sockaddr_in* addr) 27f4e8e3d3SShuo Chen { 28f4e8e3d3SShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 29f4e8e3d3SShuo Chen } 30f4e8e3d3SShuo Chen 31f4e8e3d3SShuo Chen SA* sockaddr_cast(struct sockaddr_in* addr) 32f4e8e3d3SShuo Chen { 33f4e8e3d3SShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 34f4e8e3d3SShuo Chen } 35f4e8e3d3SShuo Chen 36f4e8e3d3SShuo Chen void setNonBlockAndCloseOnExec(int sockfd) 37f4e8e3d3SShuo Chen { 38f4e8e3d3SShuo Chen // non-block 39f4e8e3d3SShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 40f4e8e3d3SShuo Chen flags |= O_NONBLOCK; 41f4e8e3d3SShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 42f4e8e3d3SShuo Chen // FIXME check 43f4e8e3d3SShuo Chen 44f4e8e3d3SShuo Chen // close-on-exec 45f4e8e3d3SShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 46f4e8e3d3SShuo Chen flags |= FD_CLOEXEC; 47f4e8e3d3SShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 48f4e8e3d3SShuo Chen // FIXME check 49f4e8e3d3SShuo Chen } 50f4e8e3d3SShuo Chen 51f4e8e3d3SShuo Chen } 52f4e8e3d3SShuo Chen 53f4e8e3d3SShuo Chen int sockets::createNonblockingOrDie() 54f4e8e3d3SShuo Chen { 55f4e8e3d3SShuo Chen // socket 56f4e8e3d3SShuo Chen #if VALGRIND 57f4e8e3d3SShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 58f4e8e3d3SShuo Chen if (sockfd < 0) 59f4e8e3d3SShuo Chen { 60f4e8e3d3SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 61f4e8e3d3SShuo Chen } 62f4e8e3d3SShuo Chen 63f4e8e3d3SShuo Chen setNonBlockAndCloseOnExec(sockfd); 64f4e8e3d3SShuo Chen #else 65f4e8e3d3SShuo Chen int sockfd = ::socket(AF_INET, 66f4e8e3d3SShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 67f4e8e3d3SShuo Chen IPPROTO_TCP); 68f4e8e3d3SShuo Chen if (sockfd < 0) 69f4e8e3d3SShuo Chen { 70f4e8e3d3SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 71f4e8e3d3SShuo Chen } 72f4e8e3d3SShuo Chen #endif 73f4e8e3d3SShuo Chen return sockfd; 74f4e8e3d3SShuo Chen } 75f4e8e3d3SShuo Chen 76f4e8e3d3SShuo Chen+int sockets::connect(int sockfd, const struct sockaddr_in& addr) 77f4e8e3d3SShuo Chen+{ 78f4e8e3d3SShuo Chen+ return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr); 79f4e8e3d3SShuo Chen+} 80f4e8e3d3SShuo Chen+ 81f4e8e3d3SShuo Chen void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 82f4e8e3d3SShuo Chen { 83f4e8e3d3SShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 84f4e8e3d3SShuo Chen if (ret < 0) 85f4e8e3d3SShuo Chen { 86f4e8e3d3SShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 87f4e8e3d3SShuo Chen } 88f4e8e3d3SShuo Chen } 89f4e8e3d3SShuo Chen 90f4e8e3d3SShuo Chen void sockets::listenOrDie(int sockfd) 91f4e8e3d3SShuo Chen { 92f4e8e3d3SShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 93f4e8e3d3SShuo Chen if (ret < 0) 94f4e8e3d3SShuo Chen { 95f4e8e3d3SShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 96f4e8e3d3SShuo Chen } 97f4e8e3d3SShuo Chen } 98f4e8e3d3SShuo Chen 99f4e8e3d3SShuo Chen int sockets::accept(int sockfd, struct sockaddr_in* addr) 100f4e8e3d3SShuo Chen { 101f4e8e3d3SShuo Chen socklen_t addrlen = sizeof *addr; 102f4e8e3d3SShuo Chen #if VALGRIND 103f4e8e3d3SShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 104f4e8e3d3SShuo Chen setNonBlockAndCloseOnExec(connfd); 105f4e8e3d3SShuo Chen #else 106f4e8e3d3SShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 107f4e8e3d3SShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 108f4e8e3d3SShuo Chen #endif 109f4e8e3d3SShuo Chen if (connfd < 0) 110f4e8e3d3SShuo Chen { 111f4e8e3d3SShuo Chen int savedErrno = errno; 112f4e8e3d3SShuo Chen LOG_SYSERR << "Socket::accept"; 113f4e8e3d3SShuo Chen switch (savedErrno) 114f4e8e3d3SShuo Chen { 115f4e8e3d3SShuo Chen case EAGAIN: 116f4e8e3d3SShuo Chen case ECONNABORTED: 117f4e8e3d3SShuo Chen case EINTR: 118f4e8e3d3SShuo Chen case EPROTO: // ??? 119f4e8e3d3SShuo Chen case EPERM: 120f4e8e3d3SShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 121f4e8e3d3SShuo Chen // expected errors 122f4e8e3d3SShuo Chen errno = savedErrno; 123f4e8e3d3SShuo Chen break; 124f4e8e3d3SShuo Chen case EBADF: 125f4e8e3d3SShuo Chen case EFAULT: 126f4e8e3d3SShuo Chen case EINVAL: 127f4e8e3d3SShuo Chen case ENFILE: 128f4e8e3d3SShuo Chen case ENOBUFS: 129f4e8e3d3SShuo Chen case ENOMEM: 130f4e8e3d3SShuo Chen case ENOTSOCK: 131f4e8e3d3SShuo Chen case EOPNOTSUPP: 132f4e8e3d3SShuo Chen // unexpected errors 133f4e8e3d3SShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 134f4e8e3d3SShuo Chen break; 135f4e8e3d3SShuo Chen default: 136f4e8e3d3SShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 137f4e8e3d3SShuo Chen break; 138f4e8e3d3SShuo Chen } 139f4e8e3d3SShuo Chen } 140f4e8e3d3SShuo Chen return connfd; 141f4e8e3d3SShuo Chen } 142f4e8e3d3SShuo Chen 143f4e8e3d3SShuo Chen void sockets::close(int sockfd) 144f4e8e3d3SShuo Chen { 145f4e8e3d3SShuo Chen if (::close(sockfd) < 0) 146f4e8e3d3SShuo Chen { 147f4e8e3d3SShuo Chen LOG_SYSERR << "sockets::close"; 148f4e8e3d3SShuo Chen } 149f4e8e3d3SShuo Chen } 150f4e8e3d3SShuo Chen 151f4e8e3d3SShuo Chen void sockets::shutdownWrite(int sockfd) 152f4e8e3d3SShuo Chen { 153f4e8e3d3SShuo Chen if (::shutdown(sockfd, SHUT_WR) < 0) 154f4e8e3d3SShuo Chen { 155f4e8e3d3SShuo Chen LOG_SYSERR << "sockets::shutdownWrite"; 156f4e8e3d3SShuo Chen } 157f4e8e3d3SShuo Chen } 158f4e8e3d3SShuo Chen 159f4e8e3d3SShuo Chen void sockets::toHostPort(char* buf, size_t size, 160f4e8e3d3SShuo Chen const struct sockaddr_in& addr) 161f4e8e3d3SShuo Chen { 162f4e8e3d3SShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 163f4e8e3d3SShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 164f4e8e3d3SShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 165f4e8e3d3SShuo Chen snprintf(buf, size, "%s:%u", host, port); 166f4e8e3d3SShuo Chen } 167f4e8e3d3SShuo Chen 168f4e8e3d3SShuo Chen void sockets::fromHostPort(const char* ip, uint16_t port, 169f4e8e3d3SShuo Chen struct sockaddr_in* addr) 170f4e8e3d3SShuo Chen { 171f4e8e3d3SShuo Chen addr->sin_family = AF_INET; 172f4e8e3d3SShuo Chen addr->sin_port = hostToNetwork16(port); 173f4e8e3d3SShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 174f4e8e3d3SShuo Chen { 175f4e8e3d3SShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 176f4e8e3d3SShuo Chen } 177f4e8e3d3SShuo Chen } 178f4e8e3d3SShuo Chen 179f4e8e3d3SShuo Chen struct sockaddr_in sockets::getLocalAddr(int sockfd) 180f4e8e3d3SShuo Chen { 181f4e8e3d3SShuo Chen struct sockaddr_in localaddr; 182f4e8e3d3SShuo Chen bzero(&localaddr, sizeof localaddr); 183f4e8e3d3SShuo Chen socklen_t addrlen = sizeof(localaddr); 184f4e8e3d3SShuo Chen if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 185f4e8e3d3SShuo Chen { 186f4e8e3d3SShuo Chen LOG_SYSERR << "sockets::getLocalAddr"; 187f4e8e3d3SShuo Chen } 188f4e8e3d3SShuo Chen return localaddr; 189f4e8e3d3SShuo Chen } 190f4e8e3d3SShuo Chen 191f4e8e3d3SShuo Chen+struct sockaddr_in sockets::getPeerAddr(int sockfd) 192f4e8e3d3SShuo Chen+{ 193f4e8e3d3SShuo Chen+ struct sockaddr_in peeraddr; 194f4e8e3d3SShuo Chen+ bzero(&peeraddr, sizeof peeraddr); 195f4e8e3d3SShuo Chen+ socklen_t addrlen = sizeof(peeraddr); 196f4e8e3d3SShuo Chen+ if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) 197f4e8e3d3SShuo Chen+ { 198f4e8e3d3SShuo Chen+ LOG_SYSERR << "sockets::getPeerAddr"; 199f4e8e3d3SShuo Chen+ } 200f4e8e3d3SShuo Chen+ return peeraddr; 201f4e8e3d3SShuo Chen+} 202f4e8e3d3SShuo Chen+ 203f4e8e3d3SShuo Chen int sockets::getSocketError(int sockfd) 204f4e8e3d3SShuo Chen { 205f4e8e3d3SShuo Chen int optval; 206f4e8e3d3SShuo Chen socklen_t optlen = sizeof optval; 207f4e8e3d3SShuo Chen 208f4e8e3d3SShuo Chen if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 209f4e8e3d3SShuo Chen { 210f4e8e3d3SShuo Chen return errno; 211f4e8e3d3SShuo Chen } 212f4e8e3d3SShuo Chen else 213f4e8e3d3SShuo Chen { 214f4e8e3d3SShuo Chen return optval; 215f4e8e3d3SShuo Chen } 216f4e8e3d3SShuo Chen } 217f4e8e3d3SShuo Chen+ 218f4e8e3d3SShuo Chen+bool sockets::isSelfConnect(int sockfd) 219f4e8e3d3SShuo Chen+{ 220f4e8e3d3SShuo Chen+ struct sockaddr_in localaddr = getLocalAddr(sockfd); 221f4e8e3d3SShuo Chen+ struct sockaddr_in peeraddr = getPeerAddr(sockfd); 222f4e8e3d3SShuo Chen+ return localaddr.sin_port == peeraddr.sin_port 223f4e8e3d3SShuo Chen+ && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr; 224f4e8e3d3SShuo Chen+} 225