SocketsOps.cc revision 65c497a3
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
6565c497a3SShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
6665c497a3SShuo Chen  if (sockfd < 0)
6765c497a3SShuo Chen  {
6865c497a3SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
6965c497a3SShuo Chen  }
7065c497a3SShuo Chen#endif
7165c497a3SShuo Chen  return sockfd;
7265c497a3SShuo Chen}
7365c497a3SShuo Chen
7465c497a3SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
7565c497a3SShuo Chen{
7665c497a3SShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
7765c497a3SShuo Chen  if (ret < 0)
7865c497a3SShuo Chen  {
7965c497a3SShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
8065c497a3SShuo Chen  }
8165c497a3SShuo Chen}
8265c497a3SShuo Chen
8365c497a3SShuo Chenvoid sockets::listenOrDie(int sockfd)
8465c497a3SShuo Chen{
8565c497a3SShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
8665c497a3SShuo Chen  if (ret < 0)
8765c497a3SShuo Chen  {
8865c497a3SShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
8965c497a3SShuo Chen  }
9065c497a3SShuo Chen}
9165c497a3SShuo Chen
9265c497a3SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
9365c497a3SShuo Chen{
9465c497a3SShuo Chen  socklen_t addrlen = sizeof *addr;
9565c497a3SShuo Chen#if VALGRIND
9665c497a3SShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
9765c497a3SShuo Chen  setNonBlockAndCloseOnExec(connfd);
9865c497a3SShuo Chen#else
9965c497a3SShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
10065c497a3SShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
10165c497a3SShuo Chen#endif
10265c497a3SShuo Chen  if (connfd < 0)
10365c497a3SShuo Chen  {
10465c497a3SShuo Chen    int savedErrno = errno;
10565c497a3SShuo Chen    LOG_SYSERR << "Socket::accept";
10665c497a3SShuo Chen    switch (savedErrno)
10765c497a3SShuo Chen    {
10865c497a3SShuo Chen      case EAGAIN:
10965c497a3SShuo Chen      case ECONNABORTED:
11065c497a3SShuo Chen      case EINTR:
11165c497a3SShuo Chen      case EPROTO: // ???
11265c497a3SShuo Chen      case EPERM:
11365c497a3SShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
11465c497a3SShuo Chen        // expected errors
11565c497a3SShuo Chen        errno = savedErrno;
11665c497a3SShuo Chen        break;
11765c497a3SShuo Chen      case EBADF:
11865c497a3SShuo Chen      case EFAULT:
11965c497a3SShuo Chen      case EINVAL:
12065c497a3SShuo Chen      case ENFILE:
12165c497a3SShuo Chen      case ENOBUFS:
12265c497a3SShuo Chen      case ENOMEM:
12365c497a3SShuo Chen      case ENOTSOCK:
12465c497a3SShuo Chen      case EOPNOTSUPP:
12565c497a3SShuo Chen        // unexpected errors
12665c497a3SShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
12765c497a3SShuo Chen        break;
12865c497a3SShuo Chen      default:
12965c497a3SShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
13065c497a3SShuo Chen        break;
13165c497a3SShuo Chen    }
13265c497a3SShuo Chen  }
13365c497a3SShuo Chen  return connfd;
13465c497a3SShuo Chen}
13565c497a3SShuo Chen
13665c497a3SShuo Chenvoid sockets::close(int sockfd)
13765c497a3SShuo Chen{
13865c497a3SShuo Chen  if (::close(sockfd) < 0)
13965c497a3SShuo Chen  {
14065c497a3SShuo Chen    LOG_SYSERR << "sockets::close";
14165c497a3SShuo Chen  }
14265c497a3SShuo Chen}
14365c497a3SShuo Chen
14465c497a3SShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
14565c497a3SShuo Chen                         const struct sockaddr_in& addr)
14665c497a3SShuo Chen{
14765c497a3SShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
14865c497a3SShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
14965c497a3SShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
15065c497a3SShuo Chen  snprintf(buf, size, "%s:%u", host, port);
15165c497a3SShuo Chen}
15265c497a3SShuo Chen
15365c497a3SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
15465c497a3SShuo Chen                           struct sockaddr_in* addr)
15565c497a3SShuo Chen{
15665c497a3SShuo Chen  addr->sin_family = AF_INET;
15765c497a3SShuo Chen  addr->sin_port = hostToNetwork16(port);
15865c497a3SShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
15965c497a3SShuo Chen  {
16065c497a3SShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
16165c497a3SShuo Chen  }
16265c497a3SShuo Chen}
16365c497a3SShuo Chen
16465c497a3SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
16565c497a3SShuo Chen{
16665c497a3SShuo Chen  struct sockaddr_in localaddr;
16765c497a3SShuo Chen  bzero(&localaddr, sizeof localaddr);
16865c497a3SShuo Chen  socklen_t addrlen = sizeof(localaddr);
16965c497a3SShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
17065c497a3SShuo Chen  {
17165c497a3SShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
17265c497a3SShuo Chen  }
17365c497a3SShuo Chen  return localaddr;
17465c497a3SShuo Chen}
17565c497a3SShuo Chen
17665c497a3SShuo Chenint sockets::getSocketError(int sockfd)
17765c497a3SShuo Chen{
17865c497a3SShuo Chen  int optval;
17965c497a3SShuo Chen  socklen_t optlen = sizeof optval;
18065c497a3SShuo Chen
18165c497a3SShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
18265c497a3SShuo Chen  {
18365c497a3SShuo Chen    return errno;
18465c497a3SShuo Chen  }
18565c497a3SShuo Chen  else
18665c497a3SShuo Chen  {
18765c497a3SShuo Chen    return optval;
18865c497a3SShuo Chen  }
18965c497a3SShuo Chen}
190