1048f6023SShuo Chen // Copyright 2010, Shuo Chen. All rights reserved. 2048f6023SShuo Chen // http://code.google.com/p/muduo/ 3048f6023SShuo Chen // 4048f6023SShuo Chen // Use of this source code is governed by a BSD-style license 5048f6023SShuo Chen // that can be found in the License file. 6048f6023SShuo Chen 7048f6023SShuo Chen // Author: Shuo Chen (chenshuo at chenshuo dot com) 8048f6023SShuo Chen 9048f6023SShuo Chen #include "SocketsOps.h" 10048f6023SShuo Chen #include "logging/Logging.h" 11048f6023SShuo Chen 12048f6023SShuo Chen #include <errno.h> 13048f6023SShuo Chen #include <fcntl.h> 14048f6023SShuo Chen #include <stdio.h> // snprintf 15048f6023SShuo Chen #include <strings.h> // bzero 16048f6023SShuo Chen #include <sys/socket.h> 17048f6023SShuo Chen #include <unistd.h> 18048f6023SShuo Chen 19048f6023SShuo Chen using namespace muduo; 20048f6023SShuo Chen 21048f6023SShuo Chen namespace 22048f6023SShuo Chen { 23048f6023SShuo Chen 24048f6023SShuo Chen typedef struct sockaddr SA; 25048f6023SShuo Chen 26048f6023SShuo Chen const SA* sockaddr_cast(const struct sockaddr_in* addr) 27048f6023SShuo Chen { 28048f6023SShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 29048f6023SShuo Chen } 30048f6023SShuo Chen 31048f6023SShuo Chen SA* sockaddr_cast(struct sockaddr_in* addr) 32048f6023SShuo Chen { 33048f6023SShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 34048f6023SShuo Chen } 35048f6023SShuo Chen 36048f6023SShuo Chen void setNonBlockAndCloseOnExec(int sockfd) 37048f6023SShuo Chen { 38048f6023SShuo Chen // non-block 39048f6023SShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 40048f6023SShuo Chen flags |= O_NONBLOCK; 41048f6023SShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 42048f6023SShuo Chen // FIXME check 43048f6023SShuo Chen 44048f6023SShuo Chen // close-on-exec 45048f6023SShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 46048f6023SShuo Chen flags |= FD_CLOEXEC; 47048f6023SShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 48048f6023SShuo Chen // FIXME check 49048f6023SShuo Chen } 50048f6023SShuo Chen 51048f6023SShuo Chen } 52048f6023SShuo Chen 53048f6023SShuo Chen int sockets::createNonblockingOrDie() 54048f6023SShuo Chen { 55048f6023SShuo Chen // socket 56048f6023SShuo Chen #if VALGRIND 57048f6023SShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 58048f6023SShuo Chen if (sockfd < 0) 59048f6023SShuo Chen { 60048f6023SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 61048f6023SShuo Chen } 62048f6023SShuo Chen 63048f6023SShuo Chen setNonBlockAndCloseOnExec(sockfd); 64048f6023SShuo Chen #else 650f776063SShuo Chen int sockfd = ::socket(AF_INET, 660f776063SShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 670f776063SShuo Chen IPPROTO_TCP); 68048f6023SShuo Chen if (sockfd < 0) 69048f6023SShuo Chen { 70048f6023SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 71048f6023SShuo Chen } 72048f6023SShuo Chen #endif 73048f6023SShuo Chen return sockfd; 74048f6023SShuo Chen } 75048f6023SShuo Chen 76048f6023SShuo Chen void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 77048f6023SShuo Chen { 78048f6023SShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 79048f6023SShuo Chen if (ret < 0) 80048f6023SShuo Chen { 81048f6023SShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 82048f6023SShuo Chen } 83048f6023SShuo Chen } 84048f6023SShuo Chen 85048f6023SShuo Chen void sockets::listenOrDie(int sockfd) 86048f6023SShuo Chen { 87048f6023SShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 88048f6023SShuo Chen if (ret < 0) 89048f6023SShuo Chen { 90048f6023SShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 91048f6023SShuo Chen } 92048f6023SShuo Chen } 93048f6023SShuo Chen 94048f6023SShuo Chen int sockets::accept(int sockfd, struct sockaddr_in* addr) 95048f6023SShuo Chen { 96048f6023SShuo Chen socklen_t addrlen = sizeof *addr; 97048f6023SShuo Chen #if VALGRIND 98048f6023SShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 99048f6023SShuo Chen setNonBlockAndCloseOnExec(connfd); 100048f6023SShuo Chen #else 101048f6023SShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 102048f6023SShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 103048f6023SShuo Chen #endif 104048f6023SShuo Chen if (connfd < 0) 105048f6023SShuo Chen { 106048f6023SShuo Chen int savedErrno = errno; 107048f6023SShuo Chen LOG_SYSERR << "Socket::accept"; 108048f6023SShuo Chen switch (savedErrno) 109048f6023SShuo Chen { 110048f6023SShuo Chen case EAGAIN: 111048f6023SShuo Chen case ECONNABORTED: 112048f6023SShuo Chen case EINTR: 113048f6023SShuo Chen case EPROTO: // ??? 114048f6023SShuo Chen case EPERM: 115048f6023SShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 116048f6023SShuo Chen // expected errors 117048f6023SShuo Chen errno = savedErrno; 118048f6023SShuo Chen break; 119048f6023SShuo Chen case EBADF: 120048f6023SShuo Chen case EFAULT: 121048f6023SShuo Chen case EINVAL: 122048f6023SShuo Chen case ENFILE: 123048f6023SShuo Chen case ENOBUFS: 124048f6023SShuo Chen case ENOMEM: 125048f6023SShuo Chen case ENOTSOCK: 126048f6023SShuo Chen case EOPNOTSUPP: 127048f6023SShuo Chen // unexpected errors 128048f6023SShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 129048f6023SShuo Chen break; 130048f6023SShuo Chen default: 131048f6023SShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 132048f6023SShuo Chen break; 133048f6023SShuo Chen } 134048f6023SShuo Chen } 135048f6023SShuo Chen return connfd; 136048f6023SShuo Chen } 137048f6023SShuo Chen 138048f6023SShuo Chen void sockets::close(int sockfd) 139048f6023SShuo Chen { 140048f6023SShuo Chen if (::close(sockfd) < 0) 141048f6023SShuo Chen { 142048f6023SShuo Chen LOG_SYSERR << "sockets::close"; 143048f6023SShuo Chen } 144048f6023SShuo Chen } 145048f6023SShuo Chen 146048f6023SShuo Chen void sockets::toHostPort(char* buf, size_t size, 147048f6023SShuo Chen const struct sockaddr_in& addr) 148048f6023SShuo Chen { 149048f6023SShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 150048f6023SShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 151048f6023SShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 152048f6023SShuo Chen snprintf(buf, size, "%s:%u", host, port); 153048f6023SShuo Chen } 154048f6023SShuo Chen 155048f6023SShuo Chen void sockets::fromHostPort(const char* ip, uint16_t port, 156048f6023SShuo Chen struct sockaddr_in* addr) 157048f6023SShuo Chen { 158048f6023SShuo Chen addr->sin_family = AF_INET; 159048f6023SShuo Chen addr->sin_port = hostToNetwork16(port); 160048f6023SShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 161048f6023SShuo Chen { 162048f6023SShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 163048f6023SShuo Chen } 164048f6023SShuo Chen } 165048f6023SShuo Chen 166048f6023SShuo Chen+struct sockaddr_in sockets::getLocalAddr(int sockfd) 167048f6023SShuo Chen+{ 168048f6023SShuo Chen+ struct sockaddr_in localaddr; 169048f6023SShuo Chen+ bzero(&localaddr, sizeof localaddr); 170048f6023SShuo Chen+ socklen_t addrlen = sizeof(localaddr); 171048f6023SShuo Chen+ if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 172048f6023SShuo Chen+ { 173048f6023SShuo Chen+ LOG_SYSERR << "sockets::getLocalAddr"; 174048f6023SShuo Chen+ } 175048f6023SShuo Chen+ return localaddr; 176048f6023SShuo Chen+} 177048f6023SShuo Chen+ 178