140161064SShuo Chen// Copyright 2010, Shuo Chen. All rights reserved. 240161064SShuo Chen// http://code.google.com/p/muduo/ 340161064SShuo Chen// 440161064SShuo Chen// Use of this source code is governed by a BSD-style license 540161064SShuo Chen// that can be found in the License file. 640161064SShuo Chen 740161064SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 840161064SShuo Chen 940161064SShuo Chen#include "SocketsOps.h" 1040161064SShuo Chen#include "logging/Logging.h" 1140161064SShuo Chen 1240161064SShuo Chen#include <errno.h> 1340161064SShuo Chen#include <fcntl.h> 1440161064SShuo Chen#include <stdio.h> // snprintf 1540161064SShuo Chen#include <strings.h> // bzero 1640161064SShuo Chen#include <sys/socket.h> 1740161064SShuo Chen#include <unistd.h> 1840161064SShuo Chen 1940161064SShuo Chenusing namespace muduo; 2040161064SShuo Chen 2140161064SShuo Chennamespace 2240161064SShuo Chen{ 2340161064SShuo Chen 2440161064SShuo Chentypedef struct sockaddr SA; 2540161064SShuo Chen 2640161064SShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr) 2740161064SShuo Chen{ 2840161064SShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 2940161064SShuo Chen} 3040161064SShuo Chen 3140161064SShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr) 3240161064SShuo Chen{ 3340161064SShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 3440161064SShuo Chen} 3540161064SShuo Chen 3640161064SShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd) 3740161064SShuo Chen{ 3840161064SShuo Chen // non-block 3940161064SShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 4040161064SShuo Chen flags |= O_NONBLOCK; 4140161064SShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 4240161064SShuo Chen // FIXME check 4340161064SShuo Chen 4440161064SShuo Chen // close-on-exec 4540161064SShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 4640161064SShuo Chen flags |= FD_CLOEXEC; 4740161064SShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 4840161064SShuo Chen // FIXME check 4940161064SShuo Chen} 5040161064SShuo Chen 5140161064SShuo Chen} 5240161064SShuo Chen 5340161064SShuo Chenint sockets::createNonblockingOrDie() 5440161064SShuo Chen{ 5540161064SShuo Chen // socket 5640161064SShuo Chen#if VALGRIND 5740161064SShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 5840161064SShuo Chen if (sockfd < 0) 5940161064SShuo Chen { 6040161064SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 6140161064SShuo Chen } 6240161064SShuo Chen 6340161064SShuo Chen setNonBlockAndCloseOnExec(sockfd); 6440161064SShuo Chen#else 6540161064SShuo Chen int sockfd = ::socket(AF_INET, 6640161064SShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 6740161064SShuo Chen IPPROTO_TCP); 6840161064SShuo Chen if (sockfd < 0) 6940161064SShuo Chen { 7040161064SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 7140161064SShuo Chen } 7240161064SShuo Chen#endif 7340161064SShuo Chen return sockfd; 7440161064SShuo Chen} 7540161064SShuo Chen 7604e5c324SShuo Chenint sockets::connect(int sockfd, const struct sockaddr_in& addr) 7704e5c324SShuo Chen{ 7804e5c324SShuo Chen return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr); 7904e5c324SShuo Chen} 8004e5c324SShuo Chen 8140161064SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 8240161064SShuo Chen{ 8340161064SShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 8440161064SShuo Chen if (ret < 0) 8540161064SShuo Chen { 8640161064SShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 8740161064SShuo Chen } 8840161064SShuo Chen} 8940161064SShuo Chen 9040161064SShuo Chenvoid sockets::listenOrDie(int sockfd) 9140161064SShuo Chen{ 9240161064SShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 9340161064SShuo Chen if (ret < 0) 9440161064SShuo Chen { 9540161064SShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 9640161064SShuo Chen } 9740161064SShuo Chen} 9840161064SShuo Chen 9940161064SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr) 10040161064SShuo Chen{ 10140161064SShuo Chen socklen_t addrlen = sizeof *addr; 10240161064SShuo Chen#if VALGRIND 10340161064SShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 10440161064SShuo Chen setNonBlockAndCloseOnExec(connfd); 10540161064SShuo Chen#else 10640161064SShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 10740161064SShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 10840161064SShuo Chen#endif 10940161064SShuo Chen if (connfd < 0) 11040161064SShuo Chen { 11140161064SShuo Chen int savedErrno = errno; 11240161064SShuo Chen LOG_SYSERR << "Socket::accept"; 11340161064SShuo Chen switch (savedErrno) 11440161064SShuo Chen { 11540161064SShuo Chen case EAGAIN: 11640161064SShuo Chen case ECONNABORTED: 11740161064SShuo Chen case EINTR: 11840161064SShuo Chen case EPROTO: // ??? 11940161064SShuo Chen case EPERM: 12040161064SShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 12140161064SShuo Chen // expected errors 12240161064SShuo Chen errno = savedErrno; 12340161064SShuo Chen break; 12440161064SShuo Chen case EBADF: 12540161064SShuo Chen case EFAULT: 12640161064SShuo Chen case EINVAL: 12740161064SShuo Chen case ENFILE: 12840161064SShuo Chen case ENOBUFS: 12940161064SShuo Chen case ENOMEM: 13040161064SShuo Chen case ENOTSOCK: 13140161064SShuo Chen case EOPNOTSUPP: 13240161064SShuo Chen // unexpected errors 13340161064SShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 13440161064SShuo Chen break; 13540161064SShuo Chen default: 13640161064SShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 13740161064SShuo Chen break; 13840161064SShuo Chen } 13940161064SShuo Chen } 14040161064SShuo Chen return connfd; 14140161064SShuo Chen} 14240161064SShuo Chen 14340161064SShuo Chenvoid sockets::close(int sockfd) 14440161064SShuo Chen{ 14540161064SShuo Chen if (::close(sockfd) < 0) 14640161064SShuo Chen { 14740161064SShuo Chen LOG_SYSERR << "sockets::close"; 14840161064SShuo Chen } 14940161064SShuo Chen} 15040161064SShuo Chen 15140161064SShuo Chenvoid sockets::shutdownWrite(int sockfd) 15240161064SShuo Chen{ 15340161064SShuo Chen if (::shutdown(sockfd, SHUT_WR) < 0) 15440161064SShuo Chen { 15540161064SShuo Chen LOG_SYSERR << "sockets::shutdownWrite"; 15640161064SShuo Chen } 15740161064SShuo Chen} 15840161064SShuo Chen 15940161064SShuo Chenvoid sockets::toHostPort(char* buf, size_t size, 16040161064SShuo Chen const struct sockaddr_in& addr) 16140161064SShuo Chen{ 16240161064SShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 16340161064SShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 16440161064SShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 16540161064SShuo Chen snprintf(buf, size, "%s:%u", host, port); 16640161064SShuo Chen} 16740161064SShuo Chen 16840161064SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port, 16940161064SShuo Chen struct sockaddr_in* addr) 17040161064SShuo Chen{ 17140161064SShuo Chen addr->sin_family = AF_INET; 17240161064SShuo Chen addr->sin_port = hostToNetwork16(port); 17340161064SShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 17440161064SShuo Chen { 17540161064SShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 17640161064SShuo Chen } 17740161064SShuo Chen} 17840161064SShuo Chen 17940161064SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd) 18040161064SShuo Chen{ 18140161064SShuo Chen struct sockaddr_in localaddr; 18240161064SShuo Chen bzero(&localaddr, sizeof localaddr); 18340161064SShuo Chen socklen_t addrlen = sizeof(localaddr); 18440161064SShuo Chen if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 18540161064SShuo Chen { 18640161064SShuo Chen LOG_SYSERR << "sockets::getLocalAddr"; 18740161064SShuo Chen } 18840161064SShuo Chen return localaddr; 18940161064SShuo Chen} 19040161064SShuo Chen 19104e5c324SShuo Chenstruct sockaddr_in sockets::getPeerAddr(int sockfd) 19204e5c324SShuo Chen{ 19304e5c324SShuo Chen struct sockaddr_in peeraddr; 19404e5c324SShuo Chen bzero(&peeraddr, sizeof peeraddr); 19504e5c324SShuo Chen socklen_t addrlen = sizeof(peeraddr); 19604e5c324SShuo Chen if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) 19704e5c324SShuo Chen { 19804e5c324SShuo Chen LOG_SYSERR << "sockets::getPeerAddr"; 19904e5c324SShuo Chen } 20004e5c324SShuo Chen return peeraddr; 20104e5c324SShuo Chen} 20204e5c324SShuo Chen 20340161064SShuo Chenint sockets::getSocketError(int sockfd) 20440161064SShuo Chen{ 20540161064SShuo Chen int optval; 20640161064SShuo Chen socklen_t optlen = sizeof optval; 20740161064SShuo Chen 20840161064SShuo Chen if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 20940161064SShuo Chen { 21040161064SShuo Chen return errno; 21140161064SShuo Chen } 21240161064SShuo Chen else 21340161064SShuo Chen { 21440161064SShuo Chen return optval; 21540161064SShuo Chen } 21640161064SShuo Chen} 21704e5c324SShuo Chen 21804e5c324SShuo Chenbool sockets::isSelfConnect(int sockfd) 21904e5c324SShuo Chen{ 22004e5c324SShuo Chen struct sockaddr_in localaddr = getLocalAddr(sockfd); 22104e5c324SShuo Chen struct sockaddr_in peeraddr = getPeerAddr(sockfd); 22204e5c324SShuo Chen return localaddr.sin_port == peeraddr.sin_port 22304e5c324SShuo Chen && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr; 22404e5c324SShuo Chen} 225