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