SocketsOps.cc revision b37003a7
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
65b37003a7SShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
66b37003a7SShuo Chen  if (sockfd < 0)
67b37003a7SShuo Chen  {
68b37003a7SShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
69b37003a7SShuo Chen  }
70b37003a7SShuo Chen#endif
71b37003a7SShuo Chen  return sockfd;
72b37003a7SShuo Chen}
73b37003a7SShuo Chen
74b37003a7SShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
75b37003a7SShuo Chen{
76b37003a7SShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
77b37003a7SShuo Chen  if (ret < 0)
78b37003a7SShuo Chen  {
79b37003a7SShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
80b37003a7SShuo Chen  }
81b37003a7SShuo Chen}
82b37003a7SShuo Chen
83b37003a7SShuo Chenvoid sockets::listenOrDie(int sockfd)
84b37003a7SShuo Chen{
85b37003a7SShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
86b37003a7SShuo Chen  if (ret < 0)
87b37003a7SShuo Chen  {
88b37003a7SShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
89b37003a7SShuo Chen  }
90b37003a7SShuo Chen}
91b37003a7SShuo Chen
92b37003a7SShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
93b37003a7SShuo Chen{
94b37003a7SShuo Chen  socklen_t addrlen = sizeof *addr;
95b37003a7SShuo Chen#if VALGRIND
96b37003a7SShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
97b37003a7SShuo Chen  setNonBlockAndCloseOnExec(connfd);
98b37003a7SShuo Chen#else
99b37003a7SShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
100b37003a7SShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
101b37003a7SShuo Chen#endif
102b37003a7SShuo Chen  if (connfd < 0)
103b37003a7SShuo Chen  {
104b37003a7SShuo Chen    int savedErrno = errno;
105b37003a7SShuo Chen    LOG_SYSERR << "Socket::accept";
106b37003a7SShuo Chen    switch (savedErrno)
107b37003a7SShuo Chen    {
108b37003a7SShuo Chen      case EAGAIN:
109b37003a7SShuo Chen      case ECONNABORTED:
110b37003a7SShuo Chen      case EINTR:
111b37003a7SShuo Chen      case EPROTO: // ???
112b37003a7SShuo Chen      case EPERM:
113b37003a7SShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
114b37003a7SShuo Chen        // expected errors
115b37003a7SShuo Chen        errno = savedErrno;
116b37003a7SShuo Chen        break;
117b37003a7SShuo Chen      case EBADF:
118b37003a7SShuo Chen      case EFAULT:
119b37003a7SShuo Chen      case EINVAL:
120b37003a7SShuo Chen      case ENFILE:
121b37003a7SShuo Chen      case ENOBUFS:
122b37003a7SShuo Chen      case ENOMEM:
123b37003a7SShuo Chen      case ENOTSOCK:
124b37003a7SShuo Chen      case EOPNOTSUPP:
125b37003a7SShuo Chen        // unexpected errors
126b37003a7SShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
127b37003a7SShuo Chen        break;
128b37003a7SShuo Chen      default:
129b37003a7SShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
130b37003a7SShuo Chen        break;
131b37003a7SShuo Chen    }
132b37003a7SShuo Chen  }
133b37003a7SShuo Chen  return connfd;
134b37003a7SShuo Chen}
135b37003a7SShuo Chen
136b37003a7SShuo Chenvoid sockets::close(int sockfd)
137b37003a7SShuo Chen{
138b37003a7SShuo Chen  if (::close(sockfd) < 0)
139b37003a7SShuo Chen  {
140b37003a7SShuo Chen    LOG_SYSERR << "sockets::close";
141b37003a7SShuo Chen  }
142b37003a7SShuo Chen}
143b37003a7SShuo Chen
144b37003a7SShuo Chenvoid sockets::shutdownWrite(int sockfd)
145b37003a7SShuo Chen{
146b37003a7SShuo Chen  if (::shutdown(sockfd, SHUT_WR) < 0)
147b37003a7SShuo Chen  {
148b37003a7SShuo Chen    LOG_SYSERR << "sockets::shutdownWrite";
149b37003a7SShuo Chen  }
150b37003a7SShuo Chen}
151b37003a7SShuo Chen
152b37003a7SShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
153b37003a7SShuo Chen                         const struct sockaddr_in& addr)
154b37003a7SShuo Chen{
155b37003a7SShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
156b37003a7SShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
157b37003a7SShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
158b37003a7SShuo Chen  snprintf(buf, size, "%s:%u", host, port);
159b37003a7SShuo Chen}
160b37003a7SShuo Chen
161b37003a7SShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
162b37003a7SShuo Chen                           struct sockaddr_in* addr)
163b37003a7SShuo Chen{
164b37003a7SShuo Chen  addr->sin_family = AF_INET;
165b37003a7SShuo Chen  addr->sin_port = hostToNetwork16(port);
166b37003a7SShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
167b37003a7SShuo Chen  {
168b37003a7SShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
169b37003a7SShuo Chen  }
170b37003a7SShuo Chen}
171b37003a7SShuo Chen
172b37003a7SShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
173b37003a7SShuo Chen{
174b37003a7SShuo Chen  struct sockaddr_in localaddr;
175b37003a7SShuo Chen  bzero(&localaddr, sizeof localaddr);
176b37003a7SShuo Chen  socklen_t addrlen = sizeof(localaddr);
177b37003a7SShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
178b37003a7SShuo Chen  {
179b37003a7SShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
180b37003a7SShuo Chen  }
181b37003a7SShuo Chen  return localaddr;
182b37003a7SShuo Chen}
183b37003a7SShuo Chen
184b37003a7SShuo Chenint sockets::getSocketError(int sockfd)
185b37003a7SShuo Chen{
186b37003a7SShuo Chen  int optval;
187b37003a7SShuo Chen  socklen_t optlen = sizeof optval;
188b37003a7SShuo Chen
189b37003a7SShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
190b37003a7SShuo Chen  {
191b37003a7SShuo Chen    return errno;
192b37003a7SShuo Chen  }
193b37003a7SShuo Chen  else
194b37003a7SShuo Chen  {
195b37003a7SShuo Chen    return optval;
196b37003a7SShuo Chen  }
197b37003a7SShuo Chen}
198