12a18e699SShuo Chen// Copyright 2010, Shuo Chen. All rights reserved. 22a18e699SShuo Chen// http://code.google.com/p/muduo/ 32a18e699SShuo Chen// 42a18e699SShuo Chen// Use of this source code is governed by a BSD-style license 52a18e699SShuo Chen// that can be found in the License file. 62a18e699SShuo Chen 72a18e699SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 82a18e699SShuo Chen 92a18e699SShuo Chen#include "SocketsOps.h" 102a18e699SShuo Chen#include "logging/Logging.h" 112a18e699SShuo Chen 122a18e699SShuo Chen#include <errno.h> 132a18e699SShuo Chen#include <fcntl.h> 142a18e699SShuo Chen#include <stdio.h> // snprintf 152a18e699SShuo Chen#include <strings.h> // bzero 162a18e699SShuo Chen#include <sys/socket.h> 172a18e699SShuo Chen#include <unistd.h> 182a18e699SShuo Chen 192a18e699SShuo Chenusing namespace muduo; 202a18e699SShuo Chen 212a18e699SShuo Chennamespace 222a18e699SShuo Chen{ 232a18e699SShuo Chen 242a18e699SShuo Chentypedef struct sockaddr SA; 252a18e699SShuo Chen 262a18e699SShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr) 272a18e699SShuo Chen{ 282a18e699SShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 292a18e699SShuo Chen} 302a18e699SShuo Chen 312a18e699SShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr) 322a18e699SShuo Chen{ 332a18e699SShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 342a18e699SShuo Chen} 352a18e699SShuo Chen 362a18e699SShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd) 372a18e699SShuo Chen{ 382a18e699SShuo Chen // non-block 392a18e699SShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 402a18e699SShuo Chen flags |= O_NONBLOCK; 412a18e699SShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 422a18e699SShuo Chen // FIXME check 432a18e699SShuo Chen 442a18e699SShuo Chen // close-on-exec 452a18e699SShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 462a18e699SShuo Chen flags |= FD_CLOEXEC; 472a18e699SShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 482a18e699SShuo Chen // FIXME check 492a18e699SShuo Chen} 502a18e699SShuo Chen 512a18e699SShuo Chen} 522a18e699SShuo Chen 532a18e699SShuo Chenint sockets::createNonblockingOrDie() 542a18e699SShuo Chen{ 552a18e699SShuo Chen // socket 562a18e699SShuo Chen#if VALGRIND 572a18e699SShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 582a18e699SShuo Chen if (sockfd < 0) 592a18e699SShuo Chen { 602a18e699SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 612a18e699SShuo Chen } 622a18e699SShuo Chen 632a18e699SShuo Chen setNonBlockAndCloseOnExec(sockfd); 642a18e699SShuo Chen#else 65b4a5ce52SShuo Chen int sockfd = ::socket(AF_INET, 66b4a5ce52SShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 67b4a5ce52SShuo Chen IPPROTO_TCP); 682a18e699SShuo Chen if (sockfd < 0) 692a18e699SShuo Chen { 702a18e699SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 712a18e699SShuo Chen } 722a18e699SShuo Chen#endif 732a18e699SShuo Chen return sockfd; 742a18e699SShuo Chen} 752a18e699SShuo Chen 762a18e699SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 772a18e699SShuo Chen{ 782a18e699SShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 792a18e699SShuo Chen if (ret < 0) 802a18e699SShuo Chen { 812a18e699SShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 822a18e699SShuo Chen } 832a18e699SShuo Chen} 842a18e699SShuo Chen 852a18e699SShuo Chenvoid sockets::listenOrDie(int sockfd) 862a18e699SShuo Chen{ 872a18e699SShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 882a18e699SShuo Chen if (ret < 0) 892a18e699SShuo Chen { 902a18e699SShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 912a18e699SShuo Chen } 922a18e699SShuo Chen} 932a18e699SShuo Chen 942a18e699SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr) 952a18e699SShuo Chen{ 962a18e699SShuo Chen socklen_t addrlen = sizeof *addr; 972a18e699SShuo Chen#if VALGRIND 982a18e699SShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 992a18e699SShuo Chen setNonBlockAndCloseOnExec(connfd); 1002a18e699SShuo Chen#else 1012a18e699SShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 1022a18e699SShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 1032a18e699SShuo Chen#endif 1042a18e699SShuo Chen if (connfd < 0) 1052a18e699SShuo Chen { 1062a18e699SShuo Chen int savedErrno = errno; 1072a18e699SShuo Chen LOG_SYSERR << "Socket::accept"; 1082a18e699SShuo Chen switch (savedErrno) 1092a18e699SShuo Chen { 1102a18e699SShuo Chen case EAGAIN: 1112a18e699SShuo Chen case ECONNABORTED: 1122a18e699SShuo Chen case EINTR: 1132a18e699SShuo Chen case EPROTO: // ??? 1142a18e699SShuo Chen case EPERM: 1152a18e699SShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 1162a18e699SShuo Chen // expected errors 1172a18e699SShuo Chen errno = savedErrno; 1182a18e699SShuo Chen break; 1192a18e699SShuo Chen case EBADF: 1202a18e699SShuo Chen case EFAULT: 1212a18e699SShuo Chen case EINVAL: 1222a18e699SShuo Chen case ENFILE: 1232a18e699SShuo Chen case ENOBUFS: 1242a18e699SShuo Chen case ENOMEM: 1252a18e699SShuo Chen case ENOTSOCK: 1262a18e699SShuo Chen case EOPNOTSUPP: 1272a18e699SShuo Chen // unexpected errors 1282a18e699SShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 1292a18e699SShuo Chen break; 1302a18e699SShuo Chen default: 1312a18e699SShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 1322a18e699SShuo Chen break; 1332a18e699SShuo Chen } 1342a18e699SShuo Chen } 1352a18e699SShuo Chen return connfd; 1362a18e699SShuo Chen} 1372a18e699SShuo Chen 1382a18e699SShuo Chenvoid sockets::close(int sockfd) 1392a18e699SShuo Chen{ 1402a18e699SShuo Chen if (::close(sockfd) < 0) 1412a18e699SShuo Chen { 1422a18e699SShuo Chen LOG_SYSERR << "sockets::close"; 1432a18e699SShuo Chen } 1442a18e699SShuo Chen} 1452a18e699SShuo Chen 146129fe122SShuo Chenvoid sockets::shutdownWrite(int sockfd) 147129fe122SShuo Chen{ 148129fe122SShuo Chen if (::shutdown(sockfd, SHUT_WR) < 0) 149129fe122SShuo Chen { 150129fe122SShuo Chen LOG_SYSERR << "sockets::shutdownWrite"; 151129fe122SShuo Chen } 152129fe122SShuo Chen} 153129fe122SShuo Chen 1542a18e699SShuo Chenvoid sockets::toHostPort(char* buf, size_t size, 1552a18e699SShuo Chen const struct sockaddr_in& addr) 1562a18e699SShuo Chen{ 1572a18e699SShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 1582a18e699SShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 1592a18e699SShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 1602a18e699SShuo Chen snprintf(buf, size, "%s:%u", host, port); 1612a18e699SShuo Chen} 1622a18e699SShuo Chen 1632a18e699SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port, 1642a18e699SShuo Chen struct sockaddr_in* addr) 1652a18e699SShuo Chen{ 1662a18e699SShuo Chen addr->sin_family = AF_INET; 1672a18e699SShuo Chen addr->sin_port = hostToNetwork16(port); 1682a18e699SShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 1692a18e699SShuo Chen { 1702a18e699SShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 1712a18e699SShuo Chen } 1722a18e699SShuo Chen} 1732a18e699SShuo Chen 1742a18e699SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd) 1752a18e699SShuo Chen{ 1762a18e699SShuo Chen struct sockaddr_in localaddr; 1772a18e699SShuo Chen bzero(&localaddr, sizeof localaddr); 1782a18e699SShuo Chen socklen_t addrlen = sizeof(localaddr); 1792a18e699SShuo Chen if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 1802a18e699SShuo Chen { 1812a18e699SShuo Chen LOG_SYSERR << "sockets::getLocalAddr"; 1822a18e699SShuo Chen } 1832a18e699SShuo Chen return localaddr; 1842a18e699SShuo Chen} 1852a18e699SShuo Chen 1862a18e699SShuo Chenint sockets::getSocketError(int sockfd) 1872a18e699SShuo Chen{ 1882a18e699SShuo Chen int optval; 1892a18e699SShuo Chen socklen_t optlen = sizeof optval; 1902a18e699SShuo Chen 1912a18e699SShuo Chen if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 1922a18e699SShuo Chen { 1932a18e699SShuo Chen return errno; 1942a18e699SShuo Chen } 1952a18e699SShuo Chen else 1962a18e699SShuo Chen { 1972a18e699SShuo Chen return optval; 1982a18e699SShuo Chen } 1992a18e699SShuo Chen} 200