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