1048f6023SShuo Chen // Copyright 2010, Shuo Chen.  All rights reserved.
2048f6023SShuo Chen // http://code.google.com/p/muduo/
3048f6023SShuo Chen //
4048f6023SShuo Chen // Use of this source code is governed by a BSD-style license
5048f6023SShuo Chen // that can be found in the License file.
6048f6023SShuo Chen 
7048f6023SShuo Chen // Author: Shuo Chen (chenshuo at chenshuo dot com)
8048f6023SShuo Chen 
9048f6023SShuo Chen #include "SocketsOps.h"
10048f6023SShuo Chen #include "logging/Logging.h"
11048f6023SShuo Chen 
12048f6023SShuo Chen #include <errno.h>
13048f6023SShuo Chen #include <fcntl.h>
14048f6023SShuo Chen #include <stdio.h>  // snprintf
15048f6023SShuo Chen #include <strings.h>  // bzero
16048f6023SShuo Chen #include <sys/socket.h>
17048f6023SShuo Chen #include <unistd.h>
18048f6023SShuo Chen 
19048f6023SShuo Chen using namespace muduo;
20048f6023SShuo Chen 
21048f6023SShuo Chen namespace
22048f6023SShuo Chen {
23048f6023SShuo Chen 
24048f6023SShuo Chen typedef struct sockaddr SA;
25048f6023SShuo Chen 
26048f6023SShuo Chen const SA* sockaddr_cast(const struct sockaddr_in* addr)
27048f6023SShuo Chen {
28048f6023SShuo Chen   return static_cast<const SA*>(implicit_cast<const void*>(addr));
29048f6023SShuo Chen }
30048f6023SShuo Chen 
31048f6023SShuo Chen SA* sockaddr_cast(struct sockaddr_in* addr)
32048f6023SShuo Chen {
33048f6023SShuo Chen   return static_cast<SA*>(implicit_cast<void*>(addr));
34048f6023SShuo Chen }
35048f6023SShuo Chen 
36048f6023SShuo Chen void setNonBlockAndCloseOnExec(int sockfd)
37048f6023SShuo Chen {
38048f6023SShuo Chen   // non-block
39048f6023SShuo Chen   int flags = ::fcntl(sockfd, F_GETFL, 0);
40048f6023SShuo Chen   flags |= O_NONBLOCK;
41048f6023SShuo Chen   int ret = ::fcntl(sockfd, F_SETFL, flags);
42048f6023SShuo Chen   // FIXME check
43048f6023SShuo Chen 
44048f6023SShuo Chen   // close-on-exec
45048f6023SShuo Chen   flags = ::fcntl(sockfd, F_GETFD, 0);
46048f6023SShuo Chen   flags |= FD_CLOEXEC;
47048f6023SShuo Chen   ret = ::fcntl(sockfd, F_SETFD, flags);
48048f6023SShuo Chen   // FIXME check
49048f6023SShuo Chen }
50048f6023SShuo Chen 
51048f6023SShuo Chen }
52048f6023SShuo Chen 
53048f6023SShuo Chen int sockets::createNonblockingOrDie()
54048f6023SShuo Chen {
55048f6023SShuo Chen   // socket
56048f6023SShuo Chen #if VALGRIND
57048f6023SShuo Chen   int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
58048f6023SShuo Chen   if (sockfd < 0)
59048f6023SShuo Chen   {
60048f6023SShuo Chen     LOG_SYSFATAL << "sockets::createNonblockingOrDie";
61048f6023SShuo Chen   }
62048f6023SShuo Chen 
63048f6023SShuo Chen   setNonBlockAndCloseOnExec(sockfd);
64048f6023SShuo Chen #else
650f776063SShuo Chen   int sockfd = ::socket(AF_INET,
660f776063SShuo Chen                         SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
670f776063SShuo Chen                         IPPROTO_TCP);
68048f6023SShuo Chen   if (sockfd < 0)
69048f6023SShuo Chen   {
70048f6023SShuo Chen     LOG_SYSFATAL << "sockets::createNonblockingOrDie";
71048f6023SShuo Chen   }
72048f6023SShuo Chen #endif
73048f6023SShuo Chen   return sockfd;
74048f6023SShuo Chen }
75048f6023SShuo Chen 
76048f6023SShuo Chen void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr)
77048f6023SShuo Chen {
78048f6023SShuo Chen   int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
79048f6023SShuo Chen   if (ret < 0)
80048f6023SShuo Chen   {
81048f6023SShuo Chen     LOG_SYSFATAL << "sockets::bindOrDie";
82048f6023SShuo Chen   }
83048f6023SShuo Chen }
84048f6023SShuo Chen 
85048f6023SShuo Chen void sockets::listenOrDie(int sockfd)
86048f6023SShuo Chen {
87048f6023SShuo Chen   int ret = ::listen(sockfd, SOMAXCONN);
88048f6023SShuo Chen   if (ret < 0)
89048f6023SShuo Chen   {
90048f6023SShuo Chen     LOG_SYSFATAL << "sockets::listenOrDie";
91048f6023SShuo Chen   }
92048f6023SShuo Chen }
93048f6023SShuo Chen 
94048f6023SShuo Chen int sockets::accept(int sockfd, struct sockaddr_in* addr)
95048f6023SShuo Chen {
96048f6023SShuo Chen   socklen_t addrlen = sizeof *addr;
97048f6023SShuo Chen #if VALGRIND
98048f6023SShuo Chen   int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
99048f6023SShuo Chen   setNonBlockAndCloseOnExec(connfd);
100048f6023SShuo Chen #else
101048f6023SShuo Chen   int connfd = ::accept4(sockfd, sockaddr_cast(addr),
102048f6023SShuo Chen                          &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
103048f6023SShuo Chen #endif
104048f6023SShuo Chen   if (connfd < 0)
105048f6023SShuo Chen   {
106048f6023SShuo Chen     int savedErrno = errno;
107048f6023SShuo Chen     LOG_SYSERR << "Socket::accept";
108048f6023SShuo Chen     switch (savedErrno)
109048f6023SShuo Chen     {
110048f6023SShuo Chen       case EAGAIN:
111048f6023SShuo Chen       case ECONNABORTED:
112048f6023SShuo Chen       case EINTR:
113048f6023SShuo Chen       case EPROTO: // ???
114048f6023SShuo Chen       case EPERM:
115048f6023SShuo Chen       case EMFILE: // per-process lmit of open file desctiptor ???
116048f6023SShuo Chen         // expected errors
117048f6023SShuo Chen         errno = savedErrno;
118048f6023SShuo Chen         break;
119048f6023SShuo Chen       case EBADF:
120048f6023SShuo Chen       case EFAULT:
121048f6023SShuo Chen       case EINVAL:
122048f6023SShuo Chen       case ENFILE:
123048f6023SShuo Chen       case ENOBUFS:
124048f6023SShuo Chen       case ENOMEM:
125048f6023SShuo Chen       case ENOTSOCK:
126048f6023SShuo Chen       case EOPNOTSUPP:
127048f6023SShuo Chen         // unexpected errors
128048f6023SShuo Chen         LOG_FATAL << "unexpected error of ::accept " << savedErrno;
129048f6023SShuo Chen         break;
130048f6023SShuo Chen       default:
131048f6023SShuo Chen         LOG_FATAL << "unknown error of ::accept " << savedErrno;
132048f6023SShuo Chen         break;
133048f6023SShuo Chen     }
134048f6023SShuo Chen   }
135048f6023SShuo Chen   return connfd;
136048f6023SShuo Chen }
137048f6023SShuo Chen 
138048f6023SShuo Chen void sockets::close(int sockfd)
139048f6023SShuo Chen {
140048f6023SShuo Chen   if (::close(sockfd) < 0)
141048f6023SShuo Chen   {
142048f6023SShuo Chen     LOG_SYSERR << "sockets::close";
143048f6023SShuo Chen   }
144048f6023SShuo Chen }
145048f6023SShuo Chen 
146048f6023SShuo Chen void sockets::toHostPort(char* buf, size_t size,
147048f6023SShuo Chen                          const struct sockaddr_in& addr)
148048f6023SShuo Chen {
149048f6023SShuo Chen   char host[INET_ADDRSTRLEN] = "INVALID";
150048f6023SShuo Chen   ::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
151048f6023SShuo Chen   uint16_t port = sockets::networkToHost16(addr.sin_port);
152048f6023SShuo Chen   snprintf(buf, size, "%s:%u", host, port);
153048f6023SShuo Chen }
154048f6023SShuo Chen 
155048f6023SShuo Chen void sockets::fromHostPort(const char* ip, uint16_t port,
156048f6023SShuo Chen                            struct sockaddr_in* addr)
157048f6023SShuo Chen {
158048f6023SShuo Chen   addr->sin_family = AF_INET;
159048f6023SShuo Chen   addr->sin_port = hostToNetwork16(port);
160048f6023SShuo Chen   if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
161048f6023SShuo Chen   {
162048f6023SShuo Chen     LOG_SYSERR << "sockets::fromHostPort";
163048f6023SShuo Chen   }
164048f6023SShuo Chen }
165048f6023SShuo Chen 
166048f6023SShuo Chen+struct sockaddr_in sockets::getLocalAddr(int sockfd)
167048f6023SShuo Chen+{
168048f6023SShuo Chen+  struct sockaddr_in localaddr;
169048f6023SShuo Chen+  bzero(&localaddr, sizeof localaddr);
170048f6023SShuo Chen+  socklen_t addrlen = sizeof(localaddr);
171048f6023SShuo Chen+  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
172048f6023SShuo Chen+  {
173048f6023SShuo Chen+    LOG_SYSERR << "sockets::getLocalAddr";
174048f6023SShuo Chen+  }
175048f6023SShuo Chen+  return localaddr;
176048f6023SShuo Chen+}
177048f6023SShuo Chen+
178