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.
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <sys/select.h>
39 #include <boost/utility.hpp>
41 #include "namespaces.hh"
42 #include "namespaces.hh"
45 typedef int ProtocolType; //!< Supported protocol types
47 //! Representation of a Socket and many of the Berkeley functions available
48 class Socket : public boost::noncopyable
50 Socket(int fd): d_socket(fd)
55 //! Construct a socket of specified address family and socket type.
56 Socket(int af, int st, ProtocolType pt=0)
58 if((d_socket=socket(af, st, pt))<0)
59 throw NetworkError(strerror(errno));
60 setCloseOnExec(d_socket);
63 Socket(Socket&& rhs): d_buffer(std::move(rhs.d_buffer)), d_socket(rhs.d_socket)
72 closesocket(d_socket);
75 catch(const PDNSException& e) {
79 //! If the socket is capable of doing so, this function will wait for a connection
80 std::unique_ptr<Socket> accept()
82 struct sockaddr_in remote;
83 socklen_t remlen=sizeof(remote);
84 memset(&remote, 0, sizeof(remote));
85 int s=::accept(d_socket, reinterpret_cast<sockaddr *>(&remote), &remlen);
90 throw NetworkError("Accepting a connection: "+string(strerror(errno)));
93 return std::unique_ptr<Socket>(new Socket(s));
96 //! Get remote address
97 bool getRemote(ComboAddress &remote) {
98 socklen_t remotelen=sizeof(remote);
99 return (getpeername(d_socket, reinterpret_cast<struct sockaddr *>(&remote), &remotelen) >= 0);
102 //! Check remote address against netmaskgroup ng
103 bool acl(const NetmaskGroup &ng)
106 if (getRemote(remote))
107 return ng.match(remote);
112 //! Set the socket to non-blocking
113 void setNonBlocking()
115 ::setNonBlocking(d_socket);
118 //! Set the socket to blocking
121 ::setBlocking(d_socket);
127 ::setReuseAddr(d_socket);
128 } catch (const PDNSException &e) {
129 throw NetworkError(e.reason);
133 //! Bind the socket to a specified endpoint
134 void bind(const ComboAddress &local, bool reuseaddr=true)
137 if(reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp)<0)
138 throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
140 if(::bind(d_socket, reinterpret_cast<const struct sockaddr *>(&local), local.getSocklen())<0)
141 throw NetworkError("While binding: "+string(strerror(errno)));
144 //! Connect the socket to a specified endpoint
145 void connect(const ComboAddress &ep, int timeout=0)
147 SConnectWithTimeout(d_socket, ep, timeout);
151 //! For datagram sockets, receive a datagram and learn where it came from
152 /** For datagram sockets, receive a datagram and learn where it came from
153 \param dgram Will be filled with the datagram
154 \param ep Will be filled with the origin of the datagram */
155 void recvFrom(string &dgram, ComboAddress &ep)
157 socklen_t remlen = sizeof(ep);
159 d_buffer.resize(s_buflen);
160 if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&ep) , &remlen)) <0)
161 throw NetworkError("After recvfrom: "+string(strerror(errno)));
163 dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
166 bool recvFromAsync(string &dgram, ComboAddress &ep)
168 struct sockaddr_in remote;
169 socklen_t remlen = sizeof(remote);
171 d_buffer.resize(s_buflen);
172 if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&remote), &remlen))<0) {
174 throw NetworkError("After async recvfrom: "+string(strerror(errno)));
180 dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
185 //! For datagram sockets, send a datagram to a destination
186 void sendTo(const char* msg, size_t len, const ComboAddress &ep)
188 if(sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&ep), ep.getSocklen())<0)
189 throw NetworkError("After sendto: "+string(strerror(errno)));
192 //! For connected datagram sockets, send a datagram
193 void send(const std::string& msg)
195 if(::send(d_socket, msg.c_str(), msg.size(), 0)<0)
196 throw NetworkError("After send: "+string(strerror(errno)));
200 /** For datagram sockets, send a datagram to a destination
201 \param dgram The datagram
202 \param ep The intended destination of the datagram */
203 void sendTo(const string &dgram, const ComboAddress &ep)
205 sendTo(dgram.c_str(), dgram.length(), ep);
209 //! Write this data to the socket, taking care that all bytes are written out
210 void writen(const string &data)
215 size_t toWrite=data.length();
217 const char *ptr=data.c_str();
220 res=::send(d_socket, ptr, toWrite, 0);
222 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
224 throw NetworkError("EOF on socket");
225 toWrite -= static_cast<size_t>(res);
226 ptr += static_cast<size_t>(res);
231 //! tries to write toWrite bytes from ptr to the socket
232 /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
233 \param ptr Location to write from
234 \param toWrite number of bytes to try
236 size_t tryWrite(const char *ptr, size_t toWrite)
239 res=::send(d_socket,ptr,toWrite,0);
241 throw NetworkError("EOF on writing to a socket");
249 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
252 //! Writes toWrite bytes from ptr to the socket
253 /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
254 size_t write(const char *ptr, size_t toWrite)
257 res=::send(d_socket,ptr,toWrite,0);
259 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
264 void writenWithTimeout(const void *buffer, size_t n, int timeout)
267 const char *ptr = reinterpret_cast<const char*>(buffer);
270 ret=::write(d_socket, ptr, bytes);
273 ret=waitForRWData(d_socket, false, timeout, 0);
275 throw NetworkError("Waiting for data write");
277 throw NetworkError("Timeout writing data");
281 throw NetworkError("Writing data: "+stringerror());
284 throw NetworkError("Did not fulfill TCP write due to EOF");
287 ptr += static_cast<size_t>(ret);
288 bytes -= static_cast<size_t>(ret);
292 //! reads one character from the socket
297 ssize_t res=::recv(d_socket,&c,1,0);
303 void getline(string &data)
307 while((c=getChar())!=-1) {
314 //! Reads a block of data from the socket to a string
315 void read(string &data)
317 d_buffer.resize(s_buflen);
318 ssize_t res=::recv(d_socket, &d_buffer[0], s_buflen, 0);
320 throw NetworkError("Reading from a socket: "+string(strerror(errno)));
321 data.assign(d_buffer, 0, static_cast<size_t>(res));
324 //! Reads a block of data from the socket to a block of memory
325 size_t read(char *buffer, size_t bytes)
327 ssize_t res=::recv(d_socket, buffer, bytes, 0);
329 throw NetworkError("Reading from a socket: "+string(strerror(errno)));
330 return static_cast<size_t>(res);
333 ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
335 int err = waitForRWData(d_socket, true, timeout, 0);
338 throw NetworkError("timeout reading");
340 throw NetworkError("nonblocking read failed: "+string(strerror(errno)));
342 return read(buffer, n);
345 //! Sets the socket to listen with a default listen backlog of 10 pending connections
346 void listen(unsigned int length=10)
348 if(::listen(d_socket,length)<0)
349 throw NetworkError("Setting socket to listen: "+string(strerror(errno)));
352 //! Returns the internal file descriptor of the socket
353 int getHandle() const
359 static const size_t s_buflen{4096};
360 std::string d_buffer;