SocketsOps.cc revision 9a1e991d
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
659a1e991dSShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
669a1e991dSShuo Chen  if (sockfd < 0)
679a1e991dSShuo Chen  {
689a1e991dSShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
699a1e991dSShuo Chen  }
709a1e991dSShuo Chen#endif
719a1e991dSShuo Chen  return sockfd;
729a1e991dSShuo Chen}
739a1e991dSShuo Chen
749a1e991dSShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
759a1e991dSShuo Chen{
769a1e991dSShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
779a1e991dSShuo Chen  if (ret < 0)
789a1e991dSShuo Chen  {
799a1e991dSShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
809a1e991dSShuo Chen  }
819a1e991dSShuo Chen}
829a1e991dSShuo Chen
839a1e991dSShuo Chenvoid sockets::listenOrDie(int sockfd)
849a1e991dSShuo Chen{
859a1e991dSShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
869a1e991dSShuo Chen  if (ret < 0)
879a1e991dSShuo Chen  {
889a1e991dSShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
899a1e991dSShuo Chen  }
909a1e991dSShuo Chen}
919a1e991dSShuo Chen
929a1e991dSShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
939a1e991dSShuo Chen{
949a1e991dSShuo Chen  socklen_t addrlen = sizeof *addr;
959a1e991dSShuo Chen#if VALGRIND
969a1e991dSShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
979a1e991dSShuo Chen  setNonBlockAndCloseOnExec(connfd);
989a1e991dSShuo Chen#else
999a1e991dSShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
1009a1e991dSShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1019a1e991dSShuo Chen#endif
1029a1e991dSShuo Chen  if (connfd < 0)
1039a1e991dSShuo Chen  {
1049a1e991dSShuo Chen    int savedErrno = errno;
1059a1e991dSShuo Chen    LOG_SYSERR << "Socket::accept";
1069a1e991dSShuo Chen    switch (savedErrno)
1079a1e991dSShuo Chen    {
1089a1e991dSShuo Chen      case EAGAIN:
1099a1e991dSShuo Chen      case ECONNABORTED:
1109a1e991dSShuo Chen      case EINTR:
1119a1e991dSShuo Chen      case EPROTO: // ???
1129a1e991dSShuo Chen      case EPERM:
1139a1e991dSShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
1149a1e991dSShuo Chen        // expected errors
1159a1e991dSShuo Chen        errno = savedErrno;
1169a1e991dSShuo Chen        break;
1179a1e991dSShuo Chen      case EBADF:
1189a1e991dSShuo Chen      case EFAULT:
1199a1e991dSShuo Chen      case EINVAL:
1209a1e991dSShuo Chen      case ENFILE:
1219a1e991dSShuo Chen      case ENOBUFS:
1229a1e991dSShuo Chen      case ENOMEM:
1239a1e991dSShuo Chen      case ENOTSOCK:
1249a1e991dSShuo Chen      case EOPNOTSUPP:
1259a1e991dSShuo Chen        // unexpected errors
1269a1e991dSShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
1279a1e991dSShuo Chen        break;
1289a1e991dSShuo Chen      default:
1299a1e991dSShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
1309a1e991dSShuo Chen        break;
1319a1e991dSShuo Chen    }
1329a1e991dSShuo Chen  }
1339a1e991dSShuo Chen  return connfd;
1349a1e991dSShuo Chen}
1359a1e991dSShuo Chen
1369a1e991dSShuo Chenvoid sockets::close(int sockfd)
1379a1e991dSShuo Chen{
1389a1e991dSShuo Chen  if (::close(sockfd) < 0)
1399a1e991dSShuo Chen  {
1409a1e991dSShuo Chen    LOG_SYSERR << "sockets::close";
1419a1e991dSShuo Chen  }
1429a1e991dSShuo Chen}
1439a1e991dSShuo Chen
1449a1e991dSShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
1459a1e991dSShuo Chen                         const struct sockaddr_in& addr)
1469a1e991dSShuo Chen{
1479a1e991dSShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
1489a1e991dSShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
1499a1e991dSShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
1509a1e991dSShuo Chen  snprintf(buf, size, "%s:%u", host, port);
1519a1e991dSShuo Chen}
1529a1e991dSShuo Chen
1539a1e991dSShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
1549a1e991dSShuo Chen                           struct sockaddr_in* addr)
1559a1e991dSShuo Chen{
1569a1e991dSShuo Chen  addr->sin_family = AF_INET;
1579a1e991dSShuo Chen  addr->sin_port = hostToNetwork16(port);
1589a1e991dSShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
1599a1e991dSShuo Chen  {
1609a1e991dSShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
1619a1e991dSShuo Chen  }
1629a1e991dSShuo Chen}
1639a1e991dSShuo Chen
164