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 76void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 77{ 78 int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 79 if (ret < 0) 80 { 81 LOG_SYSFATAL << "sockets::bindOrDie"; 82 } 83} 84 85void sockets::listenOrDie(int sockfd) 86{ 87 int ret = ::listen(sockfd, SOMAXCONN); 88 if (ret < 0) 89 { 90 LOG_SYSFATAL << "sockets::listenOrDie"; 91 } 92} 93 94int sockets::accept(int sockfd, struct sockaddr_in* addr) 95{ 96 socklen_t addrlen = sizeof *addr; 97#if VALGRIND 98 int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 99 setNonBlockAndCloseOnExec(connfd); 100#else 101 int connfd = ::accept4(sockfd, sockaddr_cast(addr), 102 &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 103#endif 104 if (connfd < 0) 105 { 106 int savedErrno = errno; 107 LOG_SYSERR << "Socket::accept"; 108 switch (savedErrno) 109 { 110 case EAGAIN: 111 case ECONNABORTED: 112 case EINTR: 113 case EPROTO: // ??? 114 case EPERM: 115 case EMFILE: // per-process lmit of open file desctiptor ??? 116 // expected errors 117 errno = savedErrno; 118 break; 119 case EBADF: 120 case EFAULT: 121 case EINVAL: 122 case ENFILE: 123 case ENOBUFS: 124 case ENOMEM: 125 case ENOTSOCK: 126 case EOPNOTSUPP: 127 // unexpected errors 128 LOG_FATAL << "unexpected error of ::accept " << savedErrno; 129 break; 130 default: 131 LOG_FATAL << "unknown error of ::accept " << savedErrno; 132 break; 133 } 134 } 135 return connfd; 136} 137 138void sockets::close(int sockfd) 139{ 140 if (::close(sockfd) < 0) 141 { 142 LOG_SYSERR << "sockets::close"; 143 } 144} 145 146void sockets::shutdownWrite(int sockfd) 147{ 148 if (::shutdown(sockfd, SHUT_WR) < 0) 149 { 150 LOG_SYSERR << "sockets::shutdownWrite"; 151 } 152} 153 154void sockets::toHostPort(char* buf, size_t size, 155 const struct sockaddr_in& addr) 156{ 157 char host[INET_ADDRSTRLEN] = "INVALID"; 158 ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 159 uint16_t port = sockets::networkToHost16(addr.sin_port); 160 snprintf(buf, size, "%s:%u", host, port); 161} 162 163void sockets::fromHostPort(const char* ip, uint16_t port, 164 struct sockaddr_in* addr) 165{ 166 addr->sin_family = AF_INET; 167 addr->sin_port = hostToNetwork16(port); 168 if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 169 { 170 LOG_SYSERR << "sockets::fromHostPort"; 171 } 172} 173 174struct sockaddr_in sockets::getLocalAddr(int sockfd) 175{ 176 struct sockaddr_in localaddr; 177 bzero(&localaddr, sizeof localaddr); 178 socklen_t addrlen = sizeof(localaddr); 179 if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 180 { 181 LOG_SYSERR << "sockets::getLocalAddr"; 182 } 183 return localaddr; 184} 185 186int sockets::getSocketError(int sockfd) 187{ 188 int optval; 189 socklen_t optlen = sizeof optval; 190 191 if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 192 { 193 return errno; 194 } 195 else 196 { 197 return optval; 198 } 199} 200