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