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