s05-s04-SocketsOps.cc.diff revision 048f6023
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 65048f6023SShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); 66048f6023SShuo Chen if (sockfd < 0) 67048f6023SShuo Chen { 68048f6023SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 69048f6023SShuo Chen } 70048f6023SShuo Chen #endif 71048f6023SShuo Chen return sockfd; 72048f6023SShuo Chen } 73048f6023SShuo Chen 74048f6023SShuo Chen void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 75048f6023SShuo Chen { 76048f6023SShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 77048f6023SShuo Chen if (ret < 0) 78048f6023SShuo Chen { 79048f6023SShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 80048f6023SShuo Chen } 81048f6023SShuo Chen } 82048f6023SShuo Chen 83048f6023SShuo Chen void sockets::listenOrDie(int sockfd) 84048f6023SShuo Chen { 85048f6023SShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 86048f6023SShuo Chen if (ret < 0) 87048f6023SShuo Chen { 88048f6023SShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 89048f6023SShuo Chen } 90048f6023SShuo Chen } 91048f6023SShuo Chen 92048f6023SShuo Chen int sockets::accept(int sockfd, struct sockaddr_in* addr) 93048f6023SShuo Chen { 94048f6023SShuo Chen socklen_t addrlen = sizeof *addr; 95048f6023SShuo Chen #if VALGRIND 96048f6023SShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 97048f6023SShuo Chen setNonBlockAndCloseOnExec(connfd); 98048f6023SShuo Chen #else 99048f6023SShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 100048f6023SShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 101048f6023SShuo Chen #endif 102048f6023SShuo Chen if (connfd < 0) 103048f6023SShuo Chen { 104048f6023SShuo Chen int savedErrno = errno; 105048f6023SShuo Chen LOG_SYSERR << "Socket::accept"; 106048f6023SShuo Chen switch (savedErrno) 107048f6023SShuo Chen { 108048f6023SShuo Chen case EAGAIN: 109048f6023SShuo Chen case ECONNABORTED: 110048f6023SShuo Chen case EINTR: 111048f6023SShuo Chen case EPROTO: // ??? 112048f6023SShuo Chen case EPERM: 113048f6023SShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 114048f6023SShuo Chen // expected errors 115048f6023SShuo Chen errno = savedErrno; 116048f6023SShuo Chen break; 117048f6023SShuo Chen case EBADF: 118048f6023SShuo Chen case EFAULT: 119048f6023SShuo Chen case EINVAL: 120048f6023SShuo Chen case ENFILE: 121048f6023SShuo Chen case ENOBUFS: 122048f6023SShuo Chen case ENOMEM: 123048f6023SShuo Chen case ENOTSOCK: 124048f6023SShuo Chen case EOPNOTSUPP: 125048f6023SShuo Chen // unexpected errors 126048f6023SShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 127048f6023SShuo Chen break; 128048f6023SShuo Chen default: 129048f6023SShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 130048f6023SShuo Chen break; 131048f6023SShuo Chen } 132048f6023SShuo Chen } 133048f6023SShuo Chen return connfd; 134048f6023SShuo Chen } 135048f6023SShuo Chen 136048f6023SShuo Chen void sockets::close(int sockfd) 137048f6023SShuo Chen { 138048f6023SShuo Chen if (::close(sockfd) < 0) 139048f6023SShuo Chen { 140048f6023SShuo Chen LOG_SYSERR << "sockets::close"; 141048f6023SShuo Chen } 142048f6023SShuo Chen } 143048f6023SShuo Chen 144048f6023SShuo Chen void sockets::toHostPort(char* buf, size_t size, 145048f6023SShuo Chen const struct sockaddr_in& addr) 146048f6023SShuo Chen { 147048f6023SShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 148048f6023SShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 149048f6023SShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 150048f6023SShuo Chen snprintf(buf, size, "%s:%u", host, port); 151048f6023SShuo Chen } 152048f6023SShuo Chen 153048f6023SShuo Chen void sockets::fromHostPort(const char* ip, uint16_t port, 154048f6023SShuo Chen struct sockaddr_in* addr) 155048f6023SShuo Chen { 156048f6023SShuo Chen addr->sin_family = AF_INET; 157048f6023SShuo Chen addr->sin_port = hostToNetwork16(port); 158048f6023SShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 159048f6023SShuo Chen { 160048f6023SShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 161048f6023SShuo Chen } 162048f6023SShuo Chen } 163048f6023SShuo Chen 164048f6023SShuo Chen+struct sockaddr_in sockets::getLocalAddr(int sockfd) 165048f6023SShuo Chen+{ 166048f6023SShuo Chen+ struct sockaddr_in localaddr; 167048f6023SShuo Chen+ bzero(&localaddr, sizeof localaddr); 168048f6023SShuo Chen+ socklen_t addrlen = sizeof(localaddr); 169048f6023SShuo Chen+ if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 170048f6023SShuo Chen+ { 171048f6023SShuo Chen+ LOG_SYSERR << "sockets::getLocalAddr"; 172048f6023SShuo Chen+ } 173048f6023SShuo Chen+ return localaddr; 174048f6023SShuo Chen+} 175048f6023SShuo Chen+ 176