2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/tcp.h>
33 #include <arpa/inet.h>
34 #include <sys/select.h>
38 #include <boost/utility.hpp>
40 #include "namespaces.hh"
43 typedef int ProtocolType; //!< Supported protocol types
45 //! Representation of a Socket and many of the Berkeley functions available
46 class Socket : public boost::noncopyable
49 Socket(int fd): d_socket(fd)
53 //! Construct a socket of specified address family and socket type.
54 Socket(int af, int st, ProtocolType pt=0)
56 if((d_socket=socket(af, st, pt))<0)
57 throw NetworkError(stringerror());
58 setCloseOnExec(d_socket);
61 Socket(Socket&& rhs): d_buffer(std::move(rhs.d_buffer)), d_socket(rhs.d_socket)
66 Socket& operator=(Socket&& rhs)
71 d_socket = rhs.d_socket;
73 d_buffer = std::move(rhs.d_buffer);
81 closesocket(d_socket);
84 catch(const PDNSException& e) {
88 //! If the socket is capable of doing so, this function will wait for a connection
89 std::unique_ptr<Socket> accept()
91 struct sockaddr_in remote;
92 socklen_t remlen=sizeof(remote);
93 memset(&remote, 0, sizeof(remote));
94 int s=::accept(d_socket, reinterpret_cast<sockaddr *>(&remote), &remlen);
99 throw NetworkError("Accepting a connection: "+stringerror());
102 return std::make_unique<Socket>(s);
105 //! Get remote address
106 bool getRemote(ComboAddress &remote) {
107 socklen_t remotelen=sizeof(remote);
108 return (getpeername(d_socket, reinterpret_cast<struct sockaddr *>(&remote), &remotelen) >= 0);
111 //! Check remote address against netmaskgroup ng
112 bool acl(const NetmaskGroup &ng)
115 if (getRemote(remote))
116 return ng.match(remote);
121 //! Set the socket to non-blocking
122 void setNonBlocking()
124 ::setNonBlocking(d_socket);
127 //! Set the socket to blocking
130 ::setBlocking(d_socket);
136 ::setReuseAddr(d_socket);
137 } catch (const PDNSException &e) {
138 throw NetworkError(e.reason);
142 void setFastOpenConnect()
144 #ifdef TCP_FASTOPEN_CONNECT
146 if (setsockopt(d_socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &on, sizeof(on)) < 0) {
147 throw NetworkError("While setting TCP_FASTOPEN_CONNECT: " + stringerror());
150 throw NetworkError("While setting TCP_FASTOPEN_CONNECT: not compiled in");
154 //! Bind the socket to a specified endpoint
155 void bind(const ComboAddress &local, bool reuseaddr=true)
158 if(reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp)<0)
159 throw NetworkError("Setsockopt failed: "+stringerror());
161 if(::bind(d_socket, reinterpret_cast<const struct sockaddr *>(&local), local.getSocklen())<0)
162 throw NetworkError("While binding: "+stringerror());
165 //! Connect the socket to a specified endpoint
166 void connect(const ComboAddress &ep, int timeout=0)
168 SConnectWithTimeout(d_socket, ep, timeval{timeout,0});
172 //! For datagram sockets, receive a datagram and learn where it came from
173 /** For datagram sockets, receive a datagram and learn where it came from
174 \param dgram Will be filled with the datagram
175 \param ep Will be filled with the origin of the datagram */
176 void recvFrom(string &dgram, ComboAddress &ep)
178 socklen_t remlen = sizeof(ep);
180 d_buffer.resize(s_buflen);
181 if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&ep) , &remlen)) <0)
182 throw NetworkError("After recvfrom: "+stringerror());
184 dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
187 bool recvFromAsync(string &dgram, ComboAddress &ep)
189 struct sockaddr_in remote;
190 socklen_t remlen = sizeof(remote);
192 d_buffer.resize(s_buflen);
193 if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&remote), &remlen))<0) {
195 throw NetworkError("After async recvfrom: "+stringerror());
201 dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
206 //! For datagram sockets, send a datagram to a destination
207 void sendTo(const char* msg, size_t len, const ComboAddress &ep)
209 if(sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&ep), ep.getSocklen())<0)
210 throw NetworkError("After sendto: "+stringerror());
213 //! For connected datagram sockets, send a datagram
214 void send(const std::string& msg)
216 if(::send(d_socket, msg.c_str(), msg.size(), 0)<0)
217 throw NetworkError("After send: "+stringerror());
221 /** For datagram sockets, send a datagram to a destination
222 \param dgram The datagram
223 \param ep The intended destination of the datagram */
224 void sendTo(const string &dgram, const ComboAddress &ep)
226 sendTo(dgram.c_str(), dgram.length(), ep);
230 //! Write this data to the socket, taking care that all bytes are written out
231 void writen(const string &data)
236 size_t toWrite=data.length();
238 const char *ptr=data.c_str();
241 res=::send(d_socket, ptr, toWrite, 0);
243 throw NetworkError("Writing to a socket: "+stringerror());
245 throw NetworkError("EOF on socket");
246 toWrite -= static_cast<size_t>(res);
247 ptr += static_cast<size_t>(res);
252 //! tries to write toWrite bytes from ptr to the socket
253 /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
254 \param ptr Location to write from
255 \param toWrite number of bytes to try
257 size_t tryWrite(const char *ptr, size_t toWrite)
260 res=::send(d_socket,ptr,toWrite,0);
262 throw NetworkError("EOF on writing to a socket");
270 throw NetworkError("Writing to a socket: "+stringerror());
273 //! Writes toWrite bytes from ptr to the socket
274 /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
275 size_t write(const char *ptr, size_t toWrite)
278 res=::send(d_socket,ptr,toWrite,0);
280 throw NetworkError("Writing to a socket: "+stringerror());
285 void writenWithTimeout(const void *buffer, size_t n, int timeout)
288 const char *ptr = reinterpret_cast<const char*>(buffer);
291 ret=::write(d_socket, ptr, bytes);
293 if(errno == EAGAIN) {
294 ret=waitForRWData(d_socket, false, timeout, 0);
296 throw NetworkError("Waiting for data write");
298 throw NetworkError("Timeout writing data");
302 throw NetworkError("Writing data: "+stringerror());
305 throw NetworkError("Did not fulfill TCP write due to EOF");
308 ptr += static_cast<size_t>(ret);
309 bytes -= static_cast<size_t>(ret);
313 //! reads one character from the socket
318 ssize_t res=::recv(d_socket,&c,1,0);
324 void getline(string &data)
328 while((c=getChar())!=-1) {
335 //! Reads a block of data from the socket to a string
336 void read(string &data)
338 d_buffer.resize(s_buflen);
339 ssize_t res=::recv(d_socket, &d_buffer[0], s_buflen, 0);
341 throw NetworkError("Reading from a socket: "+stringerror());
342 data.assign(d_buffer, 0, static_cast<size_t>(res));
345 //! Reads a block of data from the socket to a block of memory
346 size_t read(char *buffer, size_t bytes)
348 ssize_t res=::recv(d_socket, buffer, bytes, 0);
350 throw NetworkError("Reading from a socket: "+stringerror());
351 return static_cast<size_t>(res);
354 ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
356 int err = waitForRWData(d_socket, true, timeout, 0);
359 throw NetworkError("timeout reading");
361 throw NetworkError("nonblocking read failed: "+stringerror());
363 return read(buffer, n);
366 //! Sets the socket to listen with a default listen backlog of 10 pending connections
367 void listen(unsigned int length=10)
369 if(::listen(d_socket,length)<0)
370 throw NetworkError("Setting socket to listen: "+stringerror());
373 //! Returns the internal file descriptor of the socket
374 int getHandle() const
387 static const size_t s_buflen{4096};
388 std::string d_buffer;