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