1354280cfSShuo Chen// Copyright 2010, Shuo Chen.  All rights reserved.
2354280cfSShuo Chen// http://code.google.com/p/muduo/
3354280cfSShuo Chen//
4354280cfSShuo Chen// Use of this source code is governed by a BSD-style license
5354280cfSShuo Chen// that can be found in the License file.
6354280cfSShuo Chen
7354280cfSShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
8354280cfSShuo Chen
9354280cfSShuo Chen#include "SocketsOps.h"
10354280cfSShuo Chen#include "logging/Logging.h"
11354280cfSShuo Chen
12354280cfSShuo Chen#include <errno.h>
13354280cfSShuo Chen#include <fcntl.h>
14354280cfSShuo Chen#include <stdio.h>  // snprintf
15354280cfSShuo Chen#include <strings.h>  // bzero
16354280cfSShuo Chen#include <sys/socket.h>
17354280cfSShuo Chen#include <unistd.h>
18354280cfSShuo Chen
19354280cfSShuo Chenusing namespace muduo;
20354280cfSShuo Chen
21354280cfSShuo Chennamespace
22354280cfSShuo Chen{
23354280cfSShuo Chen
24354280cfSShuo Chentypedef struct sockaddr SA;
25354280cfSShuo Chen
26354280cfSShuo Chenconst SA* sockaddr_cast(const struct sockaddr_in* addr)
27354280cfSShuo Chen{
28354280cfSShuo Chen  return static_cast<const SA*>(implicit_cast<const void*>(addr));
29354280cfSShuo Chen}
30354280cfSShuo Chen
31354280cfSShuo ChenSA* sockaddr_cast(struct sockaddr_in* addr)
32354280cfSShuo Chen{
33354280cfSShuo Chen  return static_cast<SA*>(implicit_cast<void*>(addr));
34354280cfSShuo Chen}
35354280cfSShuo Chen
36354280cfSShuo Chenvoid setNonBlockAndCloseOnExec(int sockfd)
37354280cfSShuo Chen{
38354280cfSShuo Chen  // non-block
39354280cfSShuo Chen  int flags = ::fcntl(sockfd, F_GETFL, 0);
40354280cfSShuo Chen  flags |= O_NONBLOCK;
41354280cfSShuo Chen  int ret = ::fcntl(sockfd, F_SETFL, flags);
42354280cfSShuo Chen  // FIXME check
43354280cfSShuo Chen
44354280cfSShuo Chen  // close-on-exec
45354280cfSShuo Chen  flags = ::fcntl(sockfd, F_GETFD, 0);
46354280cfSShuo Chen  flags |= FD_CLOEXEC;
47354280cfSShuo Chen  ret = ::fcntl(sockfd, F_SETFD, flags);
48354280cfSShuo Chen  // FIXME check
49354280cfSShuo Chen}
50354280cfSShuo Chen
51354280cfSShuo Chen}
52354280cfSShuo Chen
53354280cfSShuo Chenint sockets::createNonblockingOrDie()
54354280cfSShuo Chen{
55354280cfSShuo Chen  // socket
56354280cfSShuo Chen#if VALGRIND
57354280cfSShuo Chen  int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
58354280cfSShuo Chen  if (sockfd < 0)
59354280cfSShuo Chen  {
60354280cfSShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
61354280cfSShuo Chen  }
62354280cfSShuo Chen
63354280cfSShuo Chen  setNonBlockAndCloseOnExec(sockfd);
64354280cfSShuo Chen#else
65354280cfSShuo Chen  int sockfd = ::socket(AF_INET,
66354280cfSShuo Chen                        SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
67354280cfSShuo Chen                        IPPROTO_TCP);
68354280cfSShuo Chen  if (sockfd < 0)
69354280cfSShuo Chen  {
70354280cfSShuo Chen    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
71354280cfSShuo Chen  }
72354280cfSShuo Chen#endif
73354280cfSShuo Chen  return sockfd;
74354280cfSShuo Chen}
75354280cfSShuo Chen
76354280cfSShuo Chenint sockets::connect(int sockfd, const struct sockaddr_in& addr)
77354280cfSShuo Chen{
78354280cfSShuo Chen  return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr);
79354280cfSShuo Chen}
80354280cfSShuo Chen
81354280cfSShuo Chenvoid sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
82354280cfSShuo Chen{
83354280cfSShuo Chen  int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
84354280cfSShuo Chen  if (ret < 0)
85354280cfSShuo Chen  {
86354280cfSShuo Chen    LOG_SYSFATAL << "sockets::bindOrDie";
87354280cfSShuo Chen  }
88354280cfSShuo Chen}
89354280cfSShuo Chen
90354280cfSShuo Chenvoid sockets::listenOrDie(int sockfd)
91354280cfSShuo Chen{
92354280cfSShuo Chen  int ret = ::listen(sockfd, SOMAXCONN);
93354280cfSShuo Chen  if (ret < 0)
94354280cfSShuo Chen  {
95354280cfSShuo Chen    LOG_SYSFATAL << "sockets::listenOrDie";
96354280cfSShuo Chen  }
97354280cfSShuo Chen}
98354280cfSShuo Chen
99354280cfSShuo Chenint sockets::accept(int sockfd, struct sockaddr_in* addr)
100354280cfSShuo Chen{
101354280cfSShuo Chen  socklen_t addrlen = sizeof *addr;
102354280cfSShuo Chen#if VALGRIND
103354280cfSShuo Chen  int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
104354280cfSShuo Chen  setNonBlockAndCloseOnExec(connfd);
105354280cfSShuo Chen#else
106354280cfSShuo Chen  int connfd = ::accept4(sockfd, sockaddr_cast(addr),
107354280cfSShuo Chen                         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
108354280cfSShuo Chen#endif
109354280cfSShuo Chen  if (connfd < 0)
110354280cfSShuo Chen  {
111354280cfSShuo Chen    int savedErrno = errno;
112354280cfSShuo Chen    LOG_SYSERR << "Socket::accept";
113354280cfSShuo Chen    switch (savedErrno)
114354280cfSShuo Chen    {
115354280cfSShuo Chen      case EAGAIN:
116354280cfSShuo Chen      case ECONNABORTED:
117354280cfSShuo Chen      case EINTR:
118354280cfSShuo Chen      case EPROTO: // ???
119354280cfSShuo Chen      case EPERM:
120354280cfSShuo Chen      case EMFILE: // per-process lmit of open file desctiptor ???
121354280cfSShuo Chen        // expected errors
122354280cfSShuo Chen        errno = savedErrno;
123354280cfSShuo Chen        break;
124354280cfSShuo Chen      case EBADF:
125354280cfSShuo Chen      case EFAULT:
126354280cfSShuo Chen      case EINVAL:
127354280cfSShuo Chen      case ENFILE:
128354280cfSShuo Chen      case ENOBUFS:
129354280cfSShuo Chen      case ENOMEM:
130354280cfSShuo Chen      case ENOTSOCK:
131354280cfSShuo Chen      case EOPNOTSUPP:
132354280cfSShuo Chen        // unexpected errors
133354280cfSShuo Chen        LOG_FATAL << "unexpected error of ::accept " << savedErrno;
134354280cfSShuo Chen        break;
135354280cfSShuo Chen      default:
136354280cfSShuo Chen        LOG_FATAL << "unknown error of ::accept " << savedErrno;
137354280cfSShuo Chen        break;
138354280cfSShuo Chen    }
139354280cfSShuo Chen  }
140354280cfSShuo Chen  return connfd;
141354280cfSShuo Chen}
142354280cfSShuo Chen
143354280cfSShuo Chenvoid sockets::close(int sockfd)
144354280cfSShuo Chen{
145354280cfSShuo Chen  if (::close(sockfd) < 0)
146354280cfSShuo Chen  {
147354280cfSShuo Chen    LOG_SYSERR << "sockets::close";
148354280cfSShuo Chen  }
149354280cfSShuo Chen}
150354280cfSShuo Chen
151354280cfSShuo Chenvoid sockets::shutdownWrite(int sockfd)
152354280cfSShuo Chen{
153354280cfSShuo Chen  if (::shutdown(sockfd, SHUT_WR) < 0)
154354280cfSShuo Chen  {
155354280cfSShuo Chen    LOG_SYSERR << "sockets::shutdownWrite";
156354280cfSShuo Chen  }
157354280cfSShuo Chen}
158354280cfSShuo Chen
159354280cfSShuo Chenvoid sockets::toHostPort(char* buf, size_t size,
160354280cfSShuo Chen                         const struct sockaddr_in& addr)
161354280cfSShuo Chen{
162354280cfSShuo Chen  char host[INET_ADDRSTRLEN] = "INVALID";
163354280cfSShuo Chen  ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
164354280cfSShuo Chen  uint16_t port = sockets::networkToHost16(addr.sin_port);
165354280cfSShuo Chen  snprintf(buf, size, "%s:%u", host, port);
166354280cfSShuo Chen}
167354280cfSShuo Chen
168354280cfSShuo Chenvoid sockets::fromHostPort(const char* ip, uint16_t port,
169354280cfSShuo Chen                           struct sockaddr_in* addr)
170354280cfSShuo Chen{
171354280cfSShuo Chen  addr->sin_family = AF_INET;
172354280cfSShuo Chen  addr->sin_port = hostToNetwork16(port);
173354280cfSShuo Chen  if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
174354280cfSShuo Chen  {
175354280cfSShuo Chen    LOG_SYSERR << "sockets::fromHostPort";
176354280cfSShuo Chen  }
177354280cfSShuo Chen}
178354280cfSShuo Chen
179354280cfSShuo Chenstruct sockaddr_in sockets::getLocalAddr(int sockfd)
180354280cfSShuo Chen{
181354280cfSShuo Chen  struct sockaddr_in localaddr;
182354280cfSShuo Chen  bzero(&localaddr, sizeof localaddr);
183354280cfSShuo Chen  socklen_t addrlen = sizeof(localaddr);
184354280cfSShuo Chen  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
185354280cfSShuo Chen  {
186354280cfSShuo Chen    LOG_SYSERR << "sockets::getLocalAddr";
187354280cfSShuo Chen  }
188354280cfSShuo Chen  return localaddr;
189354280cfSShuo Chen}
190354280cfSShuo Chen
191354280cfSShuo Chenstruct sockaddr_in sockets::getPeerAddr(int sockfd)
192354280cfSShuo Chen{
193354280cfSShuo Chen  struct sockaddr_in peeraddr;
194354280cfSShuo Chen  bzero(&peeraddr, sizeof peeraddr);
195354280cfSShuo Chen  socklen_t addrlen = sizeof(peeraddr);
196354280cfSShuo Chen  if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0)
197354280cfSShuo Chen  {
198354280cfSShuo Chen    LOG_SYSERR << "sockets::getPeerAddr";
199354280cfSShuo Chen  }
200354280cfSShuo Chen  return peeraddr;
201354280cfSShuo Chen}
202354280cfSShuo Chen
203354280cfSShuo Chenint sockets::getSocketError(int sockfd)
204354280cfSShuo Chen{
205354280cfSShuo Chen  int optval;
206354280cfSShuo Chen  socklen_t optlen = sizeof optval;
207354280cfSShuo Chen
208354280cfSShuo Chen  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
209354280cfSShuo Chen  {
210354280cfSShuo Chen    return errno;
211354280cfSShuo Chen  }
212354280cfSShuo Chen  else
213354280cfSShuo Chen  {
214354280cfSShuo Chen    return optval;
215354280cfSShuo Chen  }
216354280cfSShuo Chen}
217354280cfSShuo Chen
218354280cfSShuo Chenbool sockets::isSelfConnect(int sockfd)
219354280cfSShuo Chen{
220354280cfSShuo Chen  struct sockaddr_in localaddr = getLocalAddr(sockfd);
221354280cfSShuo Chen  struct sockaddr_in peeraddr = getPeerAddr(sockfd);
222354280cfSShuo Chen  return localaddr.sin_port == peeraddr.sin_port
223354280cfSShuo Chen      && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr;
224354280cfSShuo Chen}
225