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 <arpa/inet.h>
33 #include <sys/select.h>
37 #include <boost/utility.hpp>
39 #include "namespaces.hh"
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
48 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)
70 closesocket(d_socket);
73 catch(const PDNSException& e) {
77 //! If the socket is capable of doing so, this function will wait for a connection
78 std::unique_ptr<Socket> accept()
80 struct sockaddr_in remote;
81 socklen_t remlen=sizeof(remote);
82 memset(&remote, 0, sizeof(remote));
83 int s=::accept(d_socket, reinterpret_cast<sockaddr *>(&remote), &remlen);
88 throw NetworkError("Accepting a connection: "+stringerror());
91 return std::unique_ptr<Socket>(new Socket(s));
94 //! Get remote address
95 bool getRemote(ComboAddress &remote) {
96 socklen_t remotelen=sizeof(remote);
97 return (getpeername(d_socket, reinterpret_cast<struct sockaddr *>(&remote), &remotelen) >= 0);
100 //! Check remote address against netmaskgroup ng
101 bool acl(const NetmaskGroup &ng)
104 if (getRemote(remote))
105 return ng.match(remote);
110 //! Set the socket to non-blocking
111 void setNonBlocking()
113 ::setNonBlocking(d_socket);
116 //! Set the socket to blocking
119 ::setBlocking(d_socket);
125 ::setReuseAddr(d_socket);
126 } catch (const PDNSException &e) {
127 throw NetworkError(e.reason);
131 //! Bind the socket to a specified endpoint
132 void bind(const ComboAddress &local, bool reuseaddr=true)
135 if(reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp)<0)
136 throw NetworkError("Setsockopt failed: "+stringerror());
138 if(::bind(d_socket, reinterpret_cast<const struct sockaddr *>(&local), local.getSocklen())<0)
139 throw NetworkError("While binding: "+stringerror());
142 //! Connect the socket to a specified endpoint
143 void connect(const ComboAddress &ep, int timeout=0)
145 SConnectWithTimeout(d_socket, ep, timeout);
149 //! For datagram sockets, receive a datagram and learn where it came from
150 /** For datagram sockets, receive a datagram and learn where it came from
151 \param dgram Will be filled with the datagram
152 \param ep Will be filled with the origin of the datagram */
153 void recvFrom(string &dgram, ComboAddress &ep)
155 socklen_t remlen = sizeof(ep);
157 d_buffer.resize(s_buflen);
158 if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&ep) , &remlen)) <0)
159 throw NetworkError("After recvfrom: "+stringerror());
161 dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
164 bool recvFromAsync(string &dgram, ComboAddress &ep)
166 struct sockaddr_in remote;
167 socklen_t remlen = sizeof(remote);
169 d_buffer.resize(s_buflen);
170 if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&remote), &remlen))<0) {
172 throw NetworkError("After async recvfrom: "+stringerror());
178 dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
183 //! For datagram sockets, send a datagram to a destination
184 void sendTo(const char* msg, size_t len, const ComboAddress &ep)
186 if(sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&ep), ep.getSocklen())<0)
187 throw NetworkError("After sendto: "+stringerror());
190 //! For connected datagram sockets, send a datagram
191 void send(const std::string& msg)
193 if(::send(d_socket, msg.c_str(), msg.size(), 0)<0)
194 throw NetworkError("After send: "+stringerror());
198 /** For datagram sockets, send a datagram to a destination
199 \param dgram The datagram
200 \param ep The intended destination of the datagram */
201 void sendTo(const string &dgram, const ComboAddress &ep)
203 sendTo(dgram.c_str(), dgram.length(), ep);
207 //! Write this data to the socket, taking care that all bytes are written out
208 void writen(const string &data)
213 size_t toWrite=data.length();
215 const char *ptr=data.c_str();
218 res=::send(d_socket, ptr, toWrite, 0);
220 throw NetworkError("Writing to a socket: "+stringerror());
222 throw NetworkError("EOF on socket");
223 toWrite -= static_cast<size_t>(res);
224 ptr += static_cast<size_t>(res);
229 //! tries to write toWrite bytes from ptr to the socket
230 /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
231 \param ptr Location to write from
232 \param toWrite number of bytes to try
234 size_t tryWrite(const char *ptr, size_t toWrite)
237 res=::send(d_socket,ptr,toWrite,0);
239 throw NetworkError("EOF on writing to a socket");
247 throw NetworkError("Writing to a socket: "+stringerror());
250 //! Writes toWrite bytes from ptr to the socket
251 /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
252 size_t write(const char *ptr, size_t toWrite)
255 res=::send(d_socket,ptr,toWrite,0);
257 throw NetworkError("Writing to a socket: "+stringerror());
262 void writenWithTimeout(const void *buffer, size_t n, int timeout)
265 const char *ptr = reinterpret_cast<const char*>(buffer);
268 ret=::write(d_socket, ptr, bytes);
271 ret=waitForRWData(d_socket, false, timeout, 0);
273 throw NetworkError("Waiting for data write");
275 throw NetworkError("Timeout writing data");
279 throw NetworkError("Writing data: "+stringerror());
282 throw NetworkError("Did not fulfill TCP write due to EOF");
285 ptr += static_cast<size_t>(ret);
286 bytes -= static_cast<size_t>(ret);
290 //! reads one character from the socket
295 ssize_t res=::recv(d_socket,&c,1,0);
301 void getline(string &data)
305 while((c=getChar())!=-1) {
312 //! Reads a block of data from the socket to a string
313 void read(string &data)
315 d_buffer.resize(s_buflen);
316 ssize_t res=::recv(d_socket, &d_buffer[0], s_buflen, 0);
318 throw NetworkError("Reading from a socket: "+stringerror());
319 data.assign(d_buffer, 0, static_cast<size_t>(res));
322 //! Reads a block of data from the socket to a block of memory
323 size_t read(char *buffer, size_t bytes)
325 ssize_t res=::recv(d_socket, buffer, bytes, 0);
327 throw NetworkError("Reading from a socket: "+stringerror());
328 return static_cast<size_t>(res);
331 ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
333 int err = waitForRWData(d_socket, true, timeout, 0);
336 throw NetworkError("timeout reading");
338 throw NetworkError("nonblocking read failed: "+stringerror());
340 return read(buffer, n);
343 //! Sets the socket to listen with a default listen backlog of 10 pending connections
344 void listen(unsigned int length=10)
346 if(::listen(d_socket,length)<0)
347 throw NetworkError("Setting socket to listen: "+stringerror());
350 //! Returns the internal file descriptor of the socket
351 int getHandle() const
357 static const size_t s_buflen{4096};
358 std::string d_buffer;