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 19 using namespace muduo; 20 21 namespace 22 { 23 24 typedef struct sockaddr SA; 25 26 const SA* sockaddr_cast(const struct sockaddr_in* addr) 27 { 28 return static_cast<const SA*>(implicit_cast<const void*>(addr)); 29 } 30 31 SA* sockaddr_cast(struct sockaddr_in* addr) 32 { 33 return static_cast<SA*>(implicit_cast<void*>(addr)); 34 } 35 36 void 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 53 int 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 76 void 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 85 void sockets::listenOrDie(int sockfd) 86 { 87 int ret = ::listen(sockfd, SOMAXCONN); 88 if (ret < 0) 89 { 90 LOG_SYSFATAL << "sockets::listenOrDie"; 91 } 92 } 93 94 int 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 138 void sockets::close(int sockfd) 139 { 140 if (::close(sockfd) < 0) 141 { 142 LOG_SYSERR << "sockets::close"; 143 } 144 } 145 146+void sockets::shutdownWrite(int sockfd) 147+{ 148+ if (::shutdown(sockfd, SHUT_WR) < 0) 149+ { 150+ LOG_SYSERR << "sockets::shutdownWrite"; 151+ } 152+} 153+ 154 void 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 163 void 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 174 struct 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 186 int 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