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