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