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::toHostPort(char* buf, size_t size, 147 const struct sockaddr_in& addr) 148{ 149 char host[INET_ADDRSTRLEN] = "INVALID"; 150 ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 151 uint16_t port = sockets::networkToHost16(addr.sin_port); 152 snprintf(buf, size, "%s:%u", host, port); 153} 154 155void sockets::fromHostPort(const char* ip, uint16_t port, 156 struct sockaddr_in* addr) 157{ 158 addr->sin_family = AF_INET; 159 addr->sin_port = hostToNetwork16(port); 160 if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 161 { 162 LOG_SYSERR << "sockets::fromHostPort"; 163 } 164} 165 166struct sockaddr_in sockets::getLocalAddr(int sockfd) 167{ 168 struct sockaddr_in localaddr; 169 bzero(&localaddr, sizeof localaddr); 170 socklen_t addrlen = sizeof(localaddr); 171 if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 172 { 173 LOG_SYSERR << "sockets::getLocalAddr"; 174 } 175 return localaddr; 176} 177 178