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