1bfe73648SShuo Chen// Copyright 2010, Shuo Chen.  All rights reserved.
2bfe73648SShuo Chen// http://code.google.com/p/muduo/
3bfe73648SShuo Chen//
4bfe73648SShuo Chen// Use of this source code is governed by a BSD-style license
5bfe73648SShuo Chen// that can be found in the License file.
6bfe73648SShuo Chen
7bfe73648SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
8bfe73648SShuo Chen
9bfe73648SShuo Chen#include "SocketsOps.h"
10bfe73648SShuo Chen#include "logging/Logging.h"
11bfe73648SShuo Chen
12bfe73648SShuo Chen#include <errno.h>
13bfe73648SShuo Chen#include <fcntl.h>
14bfe73648SShuo Chen#include <stdio.h>  // snprintf
15bfe73648SShuo Chen#include <strings.h>  // bzero
16bfe73648SShuo Chen#include <sys/socket.h>
17bfe73648SShuo Chen#include <unistd.h>
18bfe73648SShuo Chen
19bfe73648SShuo Chenusing namespace muduo;
20bfe73648SShuo Chen
21bfe73648SShuo Chennamespace
22bfe73648SShuo Chen{
23bfe73648SShuo Chen
24bfe73648SShuo Chentypedef struct sockaddr SA;
25bfe73648SShuo Chen
26bfe73648SShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr)
27bfe73648SShuo Chen{
28bfe73648SShuo Chen  return static_cast<const SA*>(implicit_cast<const void*>(addr));
29bfe73648SShuo Chen}
30bfe73648SShuo Chen
31bfe73648SShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr)
32bfe73648SShuo Chen{
33bfe73648SShuo Chen  return static_cast<SA*>(implicit_cast<void*>(addr));
34bfe73648SShuo Chen}
35bfe73648SShuo Chen
36bfe73648SShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd)
37bfe73648SShuo Chen{
38bfe73648SShuo Chen  // non-block
39bfe73648SShuo Chen  int flags = ::fcntl(sockfd, F_GETFL, 0);
40bfe73648SShuo Chen  flags |= O_NONBLOCK;
41bfe73648SShuo Chen  int ret = ::fcntl(sockfd, F_SETFL, flags);
42bfe73648SShuo Chen  // FIXME check
43bfe73648SShuo Chen
44bfe73648SShuo Chen  // close-on-exec
45bfe73648SShuo Chen  flags = ::fcntl(sockfd, F_GETFD, 0);
46bfe73648SShuo Chen  flags |= FD_CLOEXEC;
47bfe73648SShuo Chen  ret = ::fcntl(sockfd, F_SETFD, flags);
48bfe73648SShuo Chen  // FIXME check
49bfe73648SShuo Chen}
50bfe73648SShuo Chen
51bfe73648SShuo Chen}
52bfe73648SShuo Chen
53bfe73648SShuo Chenint sockets::createNonblockingOrDie()
54bfe73648SShuo Chen{
55bfe73648SShuo Chen  // socket
56bfe73648SShuo Chen#if VALGRIND
57bfe73648SShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
58bfe73648SShuo Chen  if (sockfd < 0)
59bfe73648SShuo Chen  {
60bfe73648SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
61bfe73648SShuo Chen  }
62bfe73648SShuo Chen
63bfe73648SShuo Chen  setNonBlockAndCloseOnExec(sockfd);
64bfe73648SShuo Chen#else
65b4a5ce52SShuo Chen  int sockfd = ::socket(AF_INET,
66b4a5ce52SShuo Chen                        SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
67b4a5ce52SShuo Chen                        IPPROTO_TCP);
68bfe73648SShuo Chen  if (sockfd < 0)
69bfe73648SShuo Chen  {
70bfe73648SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
71bfe73648SShuo Chen  }
72bfe73648SShuo Chen#endif
73bfe73648SShuo Chen  return sockfd;
74bfe73648SShuo Chen}
75bfe73648SShuo Chen
76bfe73648SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
77bfe73648SShuo Chen{
78bfe73648SShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
79bfe73648SShuo Chen  if (ret < 0)
80bfe73648SShuo Chen  {
81bfe73648SShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
82bfe73648SShuo Chen  }
83bfe73648SShuo Chen}
84bfe73648SShuo Chen
85bfe73648SShuo Chenvoid sockets::listenOrDie(int sockfd)
86bfe73648SShuo Chen{
87bfe73648SShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
88bfe73648SShuo Chen  if (ret < 0)
89bfe73648SShuo Chen  {
90bfe73648SShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
91bfe73648SShuo Chen  }
92bfe73648SShuo Chen}
93bfe73648SShuo Chen
94bfe73648SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
95bfe73648SShuo Chen{
96bfe73648SShuo Chen  socklen_t addrlen = sizeof *addr;
97bfe73648SShuo Chen#if VALGRIND
98bfe73648SShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
99bfe73648SShuo Chen  setNonBlockAndCloseOnExec(connfd);
100bfe73648SShuo Chen#else
101bfe73648SShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
102bfe73648SShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
103bfe73648SShuo Chen#endif
104bfe73648SShuo Chen  if (connfd < 0)
105bfe73648SShuo Chen  {
106bfe73648SShuo Chen    int savedErrno = errno;
107bfe73648SShuo Chen    LOG_SYSERR << "Socket::accept";
108bfe73648SShuo Chen    switch (savedErrno)
109bfe73648SShuo Chen    {
110bfe73648SShuo Chen      case EAGAIN:
111bfe73648SShuo Chen      case ECONNABORTED:
112bfe73648SShuo Chen      case EINTR:
113bfe73648SShuo Chen      case EPROTO: // ???
114bfe73648SShuo Chen      case EPERM:
115bfe73648SShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
116bfe73648SShuo Chen        // expected errors
117bfe73648SShuo Chen        errno = savedErrno;
118bfe73648SShuo Chen        break;
119bfe73648SShuo Chen      case EBADF:
120bfe73648SShuo Chen      case EFAULT:
121bfe73648SShuo Chen      case EINVAL:
122bfe73648SShuo Chen      case ENFILE:
123bfe73648SShuo Chen      case ENOBUFS:
124bfe73648SShuo Chen      case ENOMEM:
125bfe73648SShuo Chen      case ENOTSOCK:
126bfe73648SShuo Chen      case EOPNOTSUPP:
127bfe73648SShuo Chen        // unexpected errors
128bfe73648SShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
129bfe73648SShuo Chen        break;
130bfe73648SShuo Chen      default:
131bfe73648SShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
132bfe73648SShuo Chen        break;
133bfe73648SShuo Chen    }
134bfe73648SShuo Chen  }
135bfe73648SShuo Chen  return connfd;
136bfe73648SShuo Chen}
137bfe73648SShuo Chen
138bfe73648SShuo Chenvoid sockets::close(int sockfd)
139bfe73648SShuo Chen{
140bfe73648SShuo Chen  if (::close(sockfd) < 0)
141bfe73648SShuo Chen  {
142bfe73648SShuo Chen    LOG_SYSERR << "sockets::close";
143bfe73648SShuo Chen  }
144bfe73648SShuo Chen}
145bfe73648SShuo Chen
146bfe73648SShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
147bfe73648SShuo Chen                         const struct sockaddr_in& addr)
148bfe73648SShuo Chen{
149bfe73648SShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
150bfe73648SShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
151bfe73648SShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
152bfe73648SShuo Chen  snprintf(buf, size, "%s:%u", host, port);
153bfe73648SShuo Chen}
154bfe73648SShuo Chen
155bfe73648SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
156bfe73648SShuo Chen                           struct sockaddr_in* addr)
157bfe73648SShuo Chen{
158bfe73648SShuo Chen  addr->sin_family = AF_INET;
159bfe73648SShuo Chen  addr->sin_port = hostToNetwork16(port);
160bfe73648SShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
161bfe73648SShuo Chen  {
162bfe73648SShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
163bfe73648SShuo Chen  }
164bfe73648SShuo Chen}
165bfe73648SShuo Chen
166bfe73648SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
167bfe73648SShuo Chen{
168bfe73648SShuo Chen  struct sockaddr_in localaddr;
169bfe73648SShuo Chen  bzero(&localaddr, sizeof localaddr);
170bfe73648SShuo Chen  socklen_t addrlen = sizeof(localaddr);
171bfe73648SShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
172bfe73648SShuo Chen  {
173bfe73648SShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
174bfe73648SShuo Chen  }
175bfe73648SShuo Chen  return localaddr;
176bfe73648SShuo Chen}
177bfe73648SShuo Chen
17817c057c3SShuo Chenint sockets::getSocketError(int sockfd)
17917c057c3SShuo Chen{
18017c057c3SShuo Chen  int optval;
18117c057c3SShuo Chen  socklen_t optlen = sizeof optval;
18217c057c3SShuo Chen
18317c057c3SShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
18417c057c3SShuo Chen  {
18517c057c3SShuo Chen    return errno;
18617c057c3SShuo Chen  }
18717c057c3SShuo Chen  else
18817c057c3SShuo Chen  {
18917c057c3SShuo Chen    return optval;
19017c057c3SShuo Chen  }
19117c057c3SShuo Chen}
192