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 void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
77 {
78   int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
79   if (ret < 0)
80   {
81     LOG_SYSFATAL << "sockets::bindOrDie";
82   }
83 }
84 
85 void sockets::listenOrDie(int sockfd)
86 {
87   int ret = ::listen(sockfd, SOMAXCONN);
88   if (ret < 0)
89   {
90     LOG_SYSFATAL << "sockets::listenOrDie";
91   }
92 }
93 
94 int sockets::accept(int sockfd, struct sockaddr_in* addr)
95 {
96   socklen_t addrlen = sizeof *addr;
97 #if VALGRIND
98   int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
99   setNonBlockAndCloseOnExec(connfd);
100 #else
101   int connfd = ::accept4(sockfd, sockaddr_cast(addr),
102                          &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
103 #endif
104   if (connfd < 0)
105   {
106     int savedErrno = errno;
107     LOG_SYSERR << "Socket::accept";
108     switch (savedErrno)
109     {
110       case EAGAIN:
111       case ECONNABORTED:
112       case EINTR:
113       case EPROTO: // ???
114       case EPERM:
115       case EMFILE: // per-process lmit of open file desctiptor ???
116         // expected errors
117         errno = savedErrno;
118         break;
119       case EBADF:
120       case EFAULT:
121       case EINVAL:
122       case ENFILE:
123       case ENOBUFS:
124       case ENOMEM:
125       case ENOTSOCK:
126       case EOPNOTSUPP:
127         // unexpected errors
128         LOG_FATAL << "unexpected error of ::accept " << savedErrno;
129         break;
130       default:
131         LOG_FATAL << "unknown error of ::accept " << savedErrno;
132         break;
133     }
134   }
135   return connfd;
136 }
137 
138 void sockets::close(int sockfd)
139 {
140   if (::close(sockfd) < 0)
141   {
142     LOG_SYSERR << "sockets::close";
143   }
144 }
145 
146 void sockets::toHostPort(char* buf, size_t size,
147                          const struct sockaddr_in& addr)
148 {
149   char host[INET_ADDRSTRLEN] = "INVALID";
150   ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
151   uint16_t port = sockets::networkToHost16(addr.sin_port);
152   snprintf(buf, size, "%s:%u", host, port);
153 }
154 
155 void sockets::fromHostPort(const char* ip, uint16_t port,
156                            struct sockaddr_in* addr)
157 {
158   addr->sin_family = AF_INET;
159   addr->sin_port = hostToNetwork16(port);
160   if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
161   {
162     LOG_SYSERR << "sockets::fromHostPort";
163   }
164 }
165 
166 struct sockaddr_in sockets::getLocalAddr(int sockfd)
167 {
168   struct sockaddr_in localaddr;
169   bzero(&localaddr, sizeof localaddr);
170   socklen_t addrlen = sizeof(localaddr);
171   if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
172   {
173     LOG_SYSERR << "sockets::getLocalAddr";
174   }
175   return localaddr;
176 }
177 
178+int sockets::getSocketError(int sockfd)
179+{
180+  int optval;
181+  socklen_t optlen = sizeof optval;
182+
183+  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
184+  {
185+    return errno;
186+  }
187+  else
188+  {
189+    return optval;
190+  }
191+}
192