SocketsOps.cc revision 354280cf
1354280cfSShuo Chen// Copyright 2010, Shuo Chen. All rights reserved. 2354280cfSShuo Chen// http://code.google.com/p/muduo/ 3354280cfSShuo Chen// 4354280cfSShuo Chen// Use of this source code is governed by a BSD-style license 5354280cfSShuo Chen// that can be found in the License file. 6354280cfSShuo Chen 7354280cfSShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 8354280cfSShuo Chen 9354280cfSShuo Chen#include "SocketsOps.h" 10354280cfSShuo Chen#include "logging/Logging.h" 11354280cfSShuo Chen 12354280cfSShuo Chen#include <errno.h> 13354280cfSShuo Chen#include <fcntl.h> 14354280cfSShuo Chen#include <stdio.h> // snprintf 15354280cfSShuo Chen#include <strings.h> // bzero 16354280cfSShuo Chen#include <sys/socket.h> 17354280cfSShuo Chen#include <unistd.h> 18354280cfSShuo Chen 19354280cfSShuo Chenusing namespace muduo; 20354280cfSShuo Chen 21354280cfSShuo Chennamespace 22354280cfSShuo Chen{ 23354280cfSShuo Chen 24354280cfSShuo Chentypedef struct sockaddr SA; 25354280cfSShuo Chen 26354280cfSShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr) 27354280cfSShuo Chen{ 28354280cfSShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 29354280cfSShuo Chen} 30354280cfSShuo Chen 31354280cfSShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr) 32354280cfSShuo Chen{ 33354280cfSShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 34354280cfSShuo Chen} 35354280cfSShuo Chen 36354280cfSShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd) 37354280cfSShuo Chen{ 38354280cfSShuo Chen // non-block 39354280cfSShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 40354280cfSShuo Chen flags |= O_NONBLOCK; 41354280cfSShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 42354280cfSShuo Chen // FIXME check 43354280cfSShuo Chen 44354280cfSShuo Chen // close-on-exec 45354280cfSShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 46354280cfSShuo Chen flags |= FD_CLOEXEC; 47354280cfSShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 48354280cfSShuo Chen // FIXME check 49354280cfSShuo Chen} 50354280cfSShuo Chen 51354280cfSShuo Chen} 52354280cfSShuo Chen 53354280cfSShuo Chenint sockets::createNonblockingOrDie() 54354280cfSShuo Chen{ 55354280cfSShuo Chen // socket 56354280cfSShuo Chen#if VALGRIND 57354280cfSShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 58354280cfSShuo Chen if (sockfd < 0) 59354280cfSShuo Chen { 60354280cfSShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 61354280cfSShuo Chen } 62354280cfSShuo Chen 63354280cfSShuo Chen setNonBlockAndCloseOnExec(sockfd); 64354280cfSShuo Chen#else 65354280cfSShuo Chen int sockfd = ::socket(AF_INET, 66354280cfSShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 67354280cfSShuo Chen IPPROTO_TCP); 68354280cfSShuo Chen if (sockfd < 0) 69354280cfSShuo Chen { 70354280cfSShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 71354280cfSShuo Chen } 72354280cfSShuo Chen#endif 73354280cfSShuo Chen return sockfd; 74354280cfSShuo Chen} 75354280cfSShuo Chen 76354280cfSShuo Chenint sockets::connect(int sockfd, const struct sockaddr_in& addr) 77354280cfSShuo Chen{ 78354280cfSShuo Chen return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr); 79354280cfSShuo Chen} 80354280cfSShuo Chen 81354280cfSShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 82354280cfSShuo Chen{ 83354280cfSShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 84354280cfSShuo Chen if (ret < 0) 85354280cfSShuo Chen { 86354280cfSShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 87354280cfSShuo Chen } 88354280cfSShuo Chen} 89354280cfSShuo Chen 90354280cfSShuo Chenvoid sockets::listenOrDie(int sockfd) 91354280cfSShuo Chen{ 92354280cfSShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 93354280cfSShuo Chen if (ret < 0) 94354280cfSShuo Chen { 95354280cfSShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 96354280cfSShuo Chen } 97354280cfSShuo Chen} 98354280cfSShuo Chen 99354280cfSShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr) 100354280cfSShuo Chen{ 101354280cfSShuo Chen socklen_t addrlen = sizeof *addr; 102354280cfSShuo Chen#if VALGRIND 103354280cfSShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 104354280cfSShuo Chen setNonBlockAndCloseOnExec(connfd); 105354280cfSShuo Chen#else 106354280cfSShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 107354280cfSShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 108354280cfSShuo Chen#endif 109354280cfSShuo Chen if (connfd < 0) 110354280cfSShuo Chen { 111354280cfSShuo Chen int savedErrno = errno; 112354280cfSShuo Chen LOG_SYSERR << "Socket::accept"; 113354280cfSShuo Chen switch (savedErrno) 114354280cfSShuo Chen { 115354280cfSShuo Chen case EAGAIN: 116354280cfSShuo Chen case ECONNABORTED: 117354280cfSShuo Chen case EINTR: 118354280cfSShuo Chen case EPROTO: // ??? 119354280cfSShuo Chen case EPERM: 120354280cfSShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 121354280cfSShuo Chen // expected errors 122354280cfSShuo Chen errno = savedErrno; 123354280cfSShuo Chen break; 124354280cfSShuo Chen case EBADF: 125354280cfSShuo Chen case EFAULT: 126354280cfSShuo Chen case EINVAL: 127354280cfSShuo Chen case ENFILE: 128354280cfSShuo Chen case ENOBUFS: 129354280cfSShuo Chen case ENOMEM: 130354280cfSShuo Chen case ENOTSOCK: 131354280cfSShuo Chen case EOPNOTSUPP: 132354280cfSShuo Chen // unexpected errors 133354280cfSShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 134354280cfSShuo Chen break; 135354280cfSShuo Chen default: 136354280cfSShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 137354280cfSShuo Chen break; 138354280cfSShuo Chen } 139354280cfSShuo Chen } 140354280cfSShuo Chen return connfd; 141354280cfSShuo Chen} 142354280cfSShuo Chen 143354280cfSShuo Chenvoid sockets::close(int sockfd) 144354280cfSShuo Chen{ 145354280cfSShuo Chen if (::close(sockfd) < 0) 146354280cfSShuo Chen { 147354280cfSShuo Chen LOG_SYSERR << "sockets::close"; 148354280cfSShuo Chen } 149354280cfSShuo Chen} 150354280cfSShuo Chen 151354280cfSShuo Chenvoid sockets::shutdownWrite(int sockfd) 152354280cfSShuo Chen{ 153354280cfSShuo Chen if (::shutdown(sockfd, SHUT_WR) < 0) 154354280cfSShuo Chen { 155354280cfSShuo Chen LOG_SYSERR << "sockets::shutdownWrite"; 156354280cfSShuo Chen } 157354280cfSShuo Chen} 158354280cfSShuo Chen 159354280cfSShuo Chenvoid sockets::toHostPort(char* buf, size_t size, 160354280cfSShuo Chen const struct sockaddr_in& addr) 161354280cfSShuo Chen{ 162354280cfSShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 163354280cfSShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 164354280cfSShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 165354280cfSShuo Chen snprintf(buf, size, "%s:%u", host, port); 166354280cfSShuo Chen} 167354280cfSShuo Chen 168354280cfSShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port, 169354280cfSShuo Chen struct sockaddr_in* addr) 170354280cfSShuo Chen{ 171354280cfSShuo Chen addr->sin_family = AF_INET; 172354280cfSShuo Chen addr->sin_port = hostToNetwork16(port); 173354280cfSShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 174354280cfSShuo Chen { 175354280cfSShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 176354280cfSShuo Chen } 177354280cfSShuo Chen} 178354280cfSShuo Chen 179354280cfSShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd) 180354280cfSShuo Chen{ 181354280cfSShuo Chen struct sockaddr_in localaddr; 182354280cfSShuo Chen bzero(&localaddr, sizeof localaddr); 183354280cfSShuo Chen socklen_t addrlen = sizeof(localaddr); 184354280cfSShuo Chen if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 185354280cfSShuo Chen { 186354280cfSShuo Chen LOG_SYSERR << "sockets::getLocalAddr"; 187354280cfSShuo Chen } 188354280cfSShuo Chen return localaddr; 189354280cfSShuo Chen} 190354280cfSShuo Chen 191354280cfSShuo Chenstruct sockaddr_in sockets::getPeerAddr(int sockfd) 192354280cfSShuo Chen{ 193354280cfSShuo Chen struct sockaddr_in peeraddr; 194354280cfSShuo Chen bzero(&peeraddr, sizeof peeraddr); 195354280cfSShuo Chen socklen_t addrlen = sizeof(peeraddr); 196354280cfSShuo Chen if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) 197354280cfSShuo Chen { 198354280cfSShuo Chen LOG_SYSERR << "sockets::getPeerAddr"; 199354280cfSShuo Chen } 200354280cfSShuo Chen return peeraddr; 201354280cfSShuo Chen} 202354280cfSShuo Chen 203354280cfSShuo Chenint sockets::getSocketError(int sockfd) 204354280cfSShuo Chen{ 205354280cfSShuo Chen int optval; 206354280cfSShuo Chen socklen_t optlen = sizeof optval; 207354280cfSShuo Chen 208354280cfSShuo Chen if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 209354280cfSShuo Chen { 210354280cfSShuo Chen return errno; 211354280cfSShuo Chen } 212354280cfSShuo Chen else 213354280cfSShuo Chen { 214354280cfSShuo Chen return optval; 215354280cfSShuo Chen } 216354280cfSShuo Chen} 217354280cfSShuo Chen 218354280cfSShuo Chenbool sockets::isSelfConnect(int sockfd) 219354280cfSShuo Chen{ 220354280cfSShuo Chen struct sockaddr_in localaddr = getLocalAddr(sockfd); 221354280cfSShuo Chen struct sockaddr_in peeraddr = getPeerAddr(sockfd); 222354280cfSShuo Chen return localaddr.sin_port == peeraddr.sin_port 223354280cfSShuo Chen && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr; 224354280cfSShuo Chen} 225