SocketsOps.cc revision b4a5ce52
165c497a3SShuo Chen// Copyright 2010, Shuo Chen. All rights reserved. 265c497a3SShuo Chen// http://code.google.com/p/muduo/ 365c497a3SShuo Chen// 465c497a3SShuo Chen// Use of this source code is governed by a BSD-style license 565c497a3SShuo Chen// that can be found in the License file. 665c497a3SShuo Chen 765c497a3SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 865c497a3SShuo Chen 965c497a3SShuo Chen#include "SocketsOps.h" 1065c497a3SShuo Chen#include "logging/Logging.h" 1165c497a3SShuo Chen 1265c497a3SShuo Chen#include <errno.h> 1365c497a3SShuo Chen#include <fcntl.h> 1465c497a3SShuo Chen#include <stdio.h> // snprintf 1565c497a3SShuo Chen#include <strings.h> // bzero 1665c497a3SShuo Chen#include <sys/socket.h> 1765c497a3SShuo Chen#include <unistd.h> 1865c497a3SShuo Chen 1965c497a3SShuo Chenusing namespace muduo; 2065c497a3SShuo Chen 2165c497a3SShuo Chennamespace 2265c497a3SShuo Chen{ 2365c497a3SShuo Chen 2465c497a3SShuo Chentypedef struct sockaddr SA; 2565c497a3SShuo Chen 2665c497a3SShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr) 2765c497a3SShuo Chen{ 2865c497a3SShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 2965c497a3SShuo Chen} 3065c497a3SShuo Chen 3165c497a3SShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr) 3265c497a3SShuo Chen{ 3365c497a3SShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 3465c497a3SShuo Chen} 3565c497a3SShuo Chen 3665c497a3SShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd) 3765c497a3SShuo Chen{ 3865c497a3SShuo Chen // non-block 3965c497a3SShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 4065c497a3SShuo Chen flags |= O_NONBLOCK; 4165c497a3SShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 4265c497a3SShuo Chen // FIXME check 4365c497a3SShuo Chen 4465c497a3SShuo Chen // close-on-exec 4565c497a3SShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 4665c497a3SShuo Chen flags |= FD_CLOEXEC; 4765c497a3SShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 4865c497a3SShuo Chen // FIXME check 4965c497a3SShuo Chen} 5065c497a3SShuo Chen 5165c497a3SShuo Chen} 5265c497a3SShuo Chen 5365c497a3SShuo Chenint sockets::createNonblockingOrDie() 5465c497a3SShuo Chen{ 5565c497a3SShuo Chen // socket 5665c497a3SShuo Chen#if VALGRIND 5765c497a3SShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 5865c497a3SShuo Chen if (sockfd < 0) 5965c497a3SShuo Chen { 6065c497a3SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 6165c497a3SShuo Chen } 6265c497a3SShuo Chen 6365c497a3SShuo Chen setNonBlockAndCloseOnExec(sockfd); 6465c497a3SShuo Chen#else 65b4a5ce52SShuo Chen int sockfd = ::socket(AF_INET, 66b4a5ce52SShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 67b4a5ce52SShuo Chen IPPROTO_TCP); 6865c497a3SShuo Chen if (sockfd < 0) 6965c497a3SShuo Chen { 7065c497a3SShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 7165c497a3SShuo Chen } 7265c497a3SShuo Chen#endif 7365c497a3SShuo Chen return sockfd; 7465c497a3SShuo Chen} 7565c497a3SShuo Chen 7665c497a3SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 7765c497a3SShuo Chen{ 7865c497a3SShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 7965c497a3SShuo Chen if (ret < 0) 8065c497a3SShuo Chen { 8165c497a3SShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 8265c497a3SShuo Chen } 8365c497a3SShuo Chen} 8465c497a3SShuo Chen 8565c497a3SShuo Chenvoid sockets::listenOrDie(int sockfd) 8665c497a3SShuo Chen{ 8765c497a3SShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 8865c497a3SShuo Chen if (ret < 0) 8965c497a3SShuo Chen { 9065c497a3SShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 9165c497a3SShuo Chen } 9265c497a3SShuo Chen} 9365c497a3SShuo Chen 9465c497a3SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr) 9565c497a3SShuo Chen{ 9665c497a3SShuo Chen socklen_t addrlen = sizeof *addr; 9765c497a3SShuo Chen#if VALGRIND 9865c497a3SShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 9965c497a3SShuo Chen setNonBlockAndCloseOnExec(connfd); 10065c497a3SShuo Chen#else 10165c497a3SShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 10265c497a3SShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 10365c497a3SShuo Chen#endif 10465c497a3SShuo Chen if (connfd < 0) 10565c497a3SShuo Chen { 10665c497a3SShuo Chen int savedErrno = errno; 10765c497a3SShuo Chen LOG_SYSERR << "Socket::accept"; 10865c497a3SShuo Chen switch (savedErrno) 10965c497a3SShuo Chen { 11065c497a3SShuo Chen case EAGAIN: 11165c497a3SShuo Chen case ECONNABORTED: 11265c497a3SShuo Chen case EINTR: 11365c497a3SShuo Chen case EPROTO: // ??? 11465c497a3SShuo Chen case EPERM: 11565c497a3SShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 11665c497a3SShuo Chen // expected errors 11765c497a3SShuo Chen errno = savedErrno; 11865c497a3SShuo Chen break; 11965c497a3SShuo Chen case EBADF: 12065c497a3SShuo Chen case EFAULT: 12165c497a3SShuo Chen case EINVAL: 12265c497a3SShuo Chen case ENFILE: 12365c497a3SShuo Chen case ENOBUFS: 12465c497a3SShuo Chen case ENOMEM: 12565c497a3SShuo Chen case ENOTSOCK: 12665c497a3SShuo Chen case EOPNOTSUPP: 12765c497a3SShuo Chen // unexpected errors 12865c497a3SShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 12965c497a3SShuo Chen break; 13065c497a3SShuo Chen default: 13165c497a3SShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 13265c497a3SShuo Chen break; 13365c497a3SShuo Chen } 13465c497a3SShuo Chen } 13565c497a3SShuo Chen return connfd; 13665c497a3SShuo Chen} 13765c497a3SShuo Chen 13865c497a3SShuo Chenvoid sockets::close(int sockfd) 13965c497a3SShuo Chen{ 14065c497a3SShuo Chen if (::close(sockfd) < 0) 14165c497a3SShuo Chen { 14265c497a3SShuo Chen LOG_SYSERR << "sockets::close"; 14365c497a3SShuo Chen } 14465c497a3SShuo Chen} 14565c497a3SShuo Chen 14665c497a3SShuo Chenvoid sockets::toHostPort(char* buf, size_t size, 14765c497a3SShuo Chen const struct sockaddr_in& addr) 14865c497a3SShuo Chen{ 14965c497a3SShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 15065c497a3SShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 15165c497a3SShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 15265c497a3SShuo Chen snprintf(buf, size, "%s:%u", host, port); 15365c497a3SShuo Chen} 15465c497a3SShuo Chen 15565c497a3SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port, 15665c497a3SShuo Chen struct sockaddr_in* addr) 15765c497a3SShuo Chen{ 15865c497a3SShuo Chen addr->sin_family = AF_INET; 15965c497a3SShuo Chen addr->sin_port = hostToNetwork16(port); 16065c497a3SShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 16165c497a3SShuo Chen { 16265c497a3SShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 16365c497a3SShuo Chen } 16465c497a3SShuo Chen} 16565c497a3SShuo Chen 16665c497a3SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd) 16765c497a3SShuo Chen{ 16865c497a3SShuo Chen struct sockaddr_in localaddr; 16965c497a3SShuo Chen bzero(&localaddr, sizeof localaddr); 17065c497a3SShuo Chen socklen_t addrlen = sizeof(localaddr); 17165c497a3SShuo Chen if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 17265c497a3SShuo Chen { 17365c497a3SShuo Chen LOG_SYSERR << "sockets::getLocalAddr"; 17465c497a3SShuo Chen } 17565c497a3SShuo Chen return localaddr; 17665c497a3SShuo Chen} 17765c497a3SShuo Chen 17865c497a3SShuo Chenint sockets::getSocketError(int sockfd) 17965c497a3SShuo Chen{ 18065c497a3SShuo Chen int optval; 18165c497a3SShuo Chen socklen_t optlen = sizeof optval; 18265c497a3SShuo Chen 18365c497a3SShuo Chen if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) 18465c497a3SShuo Chen { 18565c497a3SShuo Chen return errno; 18665c497a3SShuo Chen } 18765c497a3SShuo Chen else 18865c497a3SShuo Chen { 18965c497a3SShuo Chen return optval; 19065c497a3SShuo Chen } 19165c497a3SShuo Chen} 192