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