19a1e991dSShuo Chen// Copyright 2010, Shuo Chen. All rights reserved. 29a1e991dSShuo Chen// http://code.google.com/p/muduo/ 39a1e991dSShuo Chen// 49a1e991dSShuo Chen// Use of this source code is governed by a BSD-style license 59a1e991dSShuo Chen// that can be found in the License file. 69a1e991dSShuo Chen 79a1e991dSShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 89a1e991dSShuo Chen 99a1e991dSShuo Chen#include "SocketsOps.h" 109a1e991dSShuo Chen#include "logging/Logging.h" 119a1e991dSShuo Chen 129a1e991dSShuo Chen#include <errno.h> 139a1e991dSShuo Chen#include <fcntl.h> 149a1e991dSShuo Chen#include <stdio.h> // snprintf 159a1e991dSShuo Chen#include <strings.h> // bzero 169a1e991dSShuo Chen#include <sys/socket.h> 179a1e991dSShuo Chen#include <unistd.h> 189a1e991dSShuo Chen 199a1e991dSShuo Chenusing namespace muduo; 209a1e991dSShuo Chen 219a1e991dSShuo Chennamespace 229a1e991dSShuo Chen{ 239a1e991dSShuo Chen 249a1e991dSShuo Chentypedef struct sockaddr SA; 259a1e991dSShuo Chen 269a1e991dSShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr) 279a1e991dSShuo Chen{ 289a1e991dSShuo Chen return static_cast<const SA*>(implicit_cast<const void*>(addr)); 299a1e991dSShuo Chen} 309a1e991dSShuo Chen 319a1e991dSShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr) 329a1e991dSShuo Chen{ 339a1e991dSShuo Chen return static_cast<SA*>(implicit_cast<void*>(addr)); 349a1e991dSShuo Chen} 359a1e991dSShuo Chen 369a1e991dSShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd) 379a1e991dSShuo Chen{ 389a1e991dSShuo Chen // non-block 399a1e991dSShuo Chen int flags = ::fcntl(sockfd, F_GETFL, 0); 409a1e991dSShuo Chen flags |= O_NONBLOCK; 419a1e991dSShuo Chen int ret = ::fcntl(sockfd, F_SETFL, flags); 429a1e991dSShuo Chen // FIXME check 439a1e991dSShuo Chen 449a1e991dSShuo Chen // close-on-exec 459a1e991dSShuo Chen flags = ::fcntl(sockfd, F_GETFD, 0); 469a1e991dSShuo Chen flags |= FD_CLOEXEC; 479a1e991dSShuo Chen ret = ::fcntl(sockfd, F_SETFD, flags); 489a1e991dSShuo Chen // FIXME check 499a1e991dSShuo Chen} 509a1e991dSShuo Chen 519a1e991dSShuo Chen} 529a1e991dSShuo Chen 539a1e991dSShuo Chenint sockets::createNonblockingOrDie() 549a1e991dSShuo Chen{ 559a1e991dSShuo Chen // socket 569a1e991dSShuo Chen#if VALGRIND 579a1e991dSShuo Chen int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 589a1e991dSShuo Chen if (sockfd < 0) 599a1e991dSShuo Chen { 609a1e991dSShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 619a1e991dSShuo Chen } 629a1e991dSShuo Chen 639a1e991dSShuo Chen setNonBlockAndCloseOnExec(sockfd); 649a1e991dSShuo Chen#else 65b4a5ce52SShuo Chen int sockfd = ::socket(AF_INET, 66b4a5ce52SShuo Chen SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 67b4a5ce52SShuo Chen IPPROTO_TCP); 689a1e991dSShuo Chen if (sockfd < 0) 699a1e991dSShuo Chen { 709a1e991dSShuo Chen LOG_SYSFATAL << "sockets::createNonblockingOrDie"; 719a1e991dSShuo Chen } 729a1e991dSShuo Chen#endif 739a1e991dSShuo Chen return sockfd; 749a1e991dSShuo Chen} 759a1e991dSShuo Chen 769a1e991dSShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr) 779a1e991dSShuo Chen{ 789a1e991dSShuo Chen int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); 799a1e991dSShuo Chen if (ret < 0) 809a1e991dSShuo Chen { 819a1e991dSShuo Chen LOG_SYSFATAL << "sockets::bindOrDie"; 829a1e991dSShuo Chen } 839a1e991dSShuo Chen} 849a1e991dSShuo Chen 859a1e991dSShuo Chenvoid sockets::listenOrDie(int sockfd) 869a1e991dSShuo Chen{ 879a1e991dSShuo Chen int ret = ::listen(sockfd, SOMAXCONN); 889a1e991dSShuo Chen if (ret < 0) 899a1e991dSShuo Chen { 909a1e991dSShuo Chen LOG_SYSFATAL << "sockets::listenOrDie"; 919a1e991dSShuo Chen } 929a1e991dSShuo Chen} 939a1e991dSShuo Chen 949a1e991dSShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr) 959a1e991dSShuo Chen{ 969a1e991dSShuo Chen socklen_t addrlen = sizeof *addr; 979a1e991dSShuo Chen#if VALGRIND 989a1e991dSShuo Chen int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); 999a1e991dSShuo Chen setNonBlockAndCloseOnExec(connfd); 1009a1e991dSShuo Chen#else 1019a1e991dSShuo Chen int connfd = ::accept4(sockfd, sockaddr_cast(addr), 1029a1e991dSShuo Chen &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 1039a1e991dSShuo Chen#endif 1049a1e991dSShuo Chen if (connfd < 0) 1059a1e991dSShuo Chen { 1069a1e991dSShuo Chen int savedErrno = errno; 1079a1e991dSShuo Chen LOG_SYSERR << "Socket::accept"; 1089a1e991dSShuo Chen switch (savedErrno) 1099a1e991dSShuo Chen { 1109a1e991dSShuo Chen case EAGAIN: 1119a1e991dSShuo Chen case ECONNABORTED: 1129a1e991dSShuo Chen case EINTR: 1139a1e991dSShuo Chen case EPROTO: // ??? 1149a1e991dSShuo Chen case EPERM: 1159a1e991dSShuo Chen case EMFILE: // per-process lmit of open file desctiptor ??? 1169a1e991dSShuo Chen // expected errors 1179a1e991dSShuo Chen errno = savedErrno; 1189a1e991dSShuo Chen break; 1199a1e991dSShuo Chen case EBADF: 1209a1e991dSShuo Chen case EFAULT: 1219a1e991dSShuo Chen case EINVAL: 1229a1e991dSShuo Chen case ENFILE: 1239a1e991dSShuo Chen case ENOBUFS: 1249a1e991dSShuo Chen case ENOMEM: 1259a1e991dSShuo Chen case ENOTSOCK: 1269a1e991dSShuo Chen case EOPNOTSUPP: 1279a1e991dSShuo Chen // unexpected errors 1289a1e991dSShuo Chen LOG_FATAL << "unexpected error of ::accept " << savedErrno; 1299a1e991dSShuo Chen break; 1309a1e991dSShuo Chen default: 1319a1e991dSShuo Chen LOG_FATAL << "unknown error of ::accept " << savedErrno; 1329a1e991dSShuo Chen break; 1339a1e991dSShuo Chen } 1349a1e991dSShuo Chen } 1359a1e991dSShuo Chen return connfd; 1369a1e991dSShuo Chen} 1379a1e991dSShuo Chen 1389a1e991dSShuo Chenvoid sockets::close(int sockfd) 1399a1e991dSShuo Chen{ 1409a1e991dSShuo Chen if (::close(sockfd) < 0) 1419a1e991dSShuo Chen { 1429a1e991dSShuo Chen LOG_SYSERR << "sockets::close"; 1439a1e991dSShuo Chen } 1449a1e991dSShuo Chen} 1459a1e991dSShuo Chen 1469a1e991dSShuo Chenvoid sockets::toHostPort(char* buf, size_t size, 1479a1e991dSShuo Chen const struct sockaddr_in& addr) 1489a1e991dSShuo Chen{ 1499a1e991dSShuo Chen char host[INET_ADDRSTRLEN] = "INVALID"; 1509a1e991dSShuo Chen ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host); 1519a1e991dSShuo Chen uint16_t port = sockets::networkToHost16(addr.sin_port); 1529a1e991dSShuo Chen snprintf(buf, size, "%s:%u", host, port); 1539a1e991dSShuo Chen} 1549a1e991dSShuo Chen 1559a1e991dSShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port, 1569a1e991dSShuo Chen struct sockaddr_in* addr) 1579a1e991dSShuo Chen{ 1589a1e991dSShuo Chen addr->sin_family = AF_INET; 1599a1e991dSShuo Chen addr->sin_port = hostToNetwork16(port); 1609a1e991dSShuo Chen if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) 1619a1e991dSShuo Chen { 1629a1e991dSShuo Chen LOG_SYSERR << "sockets::fromHostPort"; 1639a1e991dSShuo Chen } 1649a1e991dSShuo Chen} 1659a1e991dSShuo Chen 166e54e5389SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd) 167e54e5389SShuo Chen{ 168e54e5389SShuo Chen struct sockaddr_in localaddr; 169e54e5389SShuo Chen bzero(&localaddr, sizeof localaddr); 170e54e5389SShuo Chen socklen_t addrlen = sizeof(localaddr); 171e54e5389SShuo Chen if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) 172e54e5389SShuo Chen { 173e54e5389SShuo Chen LOG_SYSERR << "sockets::getLocalAddr"; 174e54e5389SShuo Chen } 175e54e5389SShuo Chen return localaddr; 176e54e5389SShuo Chen} 177e54e5389SShuo Chen 178