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