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 class NetworkError : public runtime_error
48 NetworkError(const string& why="Network Error") : runtime_error(why.c_str())
50 NetworkError(const char *why="Network Error") : runtime_error(why)
55 typedef int ProtocolType; //!< Supported protocol types
57 //! Representation of a Socket and many of the Berkeley functions available
58 class Socket : public boost::noncopyable
64 d_buffer=new char[d_buflen];
68 //! Construct a socket of specified address family and socket type.
69 Socket(int af, int st, ProtocolType pt=0)
71 if((d_socket=socket(af,st, pt))<0)
72 throw NetworkError(strerror(errno));
73 setCloseOnExec(d_socket);
76 d_buffer=new char[d_buflen];
82 closesocket(d_socket);
84 catch(const PDNSException& e) {
90 //! If the socket is capable of doing so, this function will wait for a connection
93 struct sockaddr_in remote;
94 socklen_t remlen=sizeof(remote);
95 memset(&remote, 0, sizeof(remote));
96 int s=::accept(d_socket,(sockaddr *)&remote, &remlen);
101 throw NetworkError("Accepting a connection: "+string(strerror(errno)));
104 return new Socket(s);
107 //! Get remote address
108 bool getRemote(ComboAddress &remote) {
109 socklen_t remotelen=sizeof(remote);
110 return (getpeername(d_socket, (struct sockaddr *)&remote, &remotelen) >= 0);
113 //! Check remote address against netmaskgroup ng
114 bool acl(NetmaskGroup &ng)
117 if (getRemote(remote))
118 return ng.match((ComboAddress *) &remote);
123 //! Set the socket to non-blocking
124 void setNonBlocking()
126 ::setNonBlocking(d_socket);
128 //! Set the socket to blocking
131 ::setBlocking(d_socket);
137 if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast<unsigned>(sizeof tmp))<0)
138 throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
141 //! Bind the socket to a specified endpoint
142 void bind(const ComboAddress &local)
145 if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
146 throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
148 if(::bind(d_socket,(struct sockaddr *)&local, local.getSocklen())<0)
149 throw NetworkError("While binding: "+string(strerror(errno)));
153 //! Bind the socket to a specified endpoint
154 void bind(const ComboAddress &ep)
157 memset(reinterpret_cast<char *>(&local),0,sizeof(local));
158 local.sin_family=d_family;
159 local.sin_addr.s_addr=ep.address.byte;
160 local.sin_port=htons(ep.port);
165 //! Connect the socket to a specified endpoint
166 void connect(const ComboAddress &ep, int timeout=0)
168 if(::connect(d_socket,(struct sockaddr *)&ep, ep.getSocklen()) < 0) {
169 if(errno == EINPROGRESS) {
171 /* if a timeout is provided, we wait until the connection has been established */
172 int res = waitForRWData(d_socket, false, timeout, 0);
174 throw NetworkError("timeout while connecting to "+ep.toStringWithPort());
175 } else if (res < 0) {
176 throw NetworkError("while waiting to connect to "+ep.toStringWithPort()+": "+string(strerror(errno)));
181 throw NetworkError("While connecting to "+ep.toStringWithPort()+": "+string(strerror(errno)));
187 //! For datagram sockets, receive a datagram and learn where it came from
188 /** For datagram sockets, receive a datagram and learn where it came from
189 \param dgram Will be filled with the datagram
190 \param ep Will be filled with the origin of the datagram */
191 void recvFrom(string &dgram, ComboAddress &ep)
193 socklen_t remlen=sizeof(ep);
195 if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&ep , &remlen)) <0)
196 throw NetworkError("After recvfrom: "+string(strerror(errno)));
198 dgram.assign(d_buffer,bytes);
201 bool recvFromAsync(string &dgram, ComboAddress &ep)
203 struct sockaddr_in remote;
204 socklen_t remlen=sizeof(remote);
206 if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&remote, &remlen))<0) {
208 throw NetworkError("After async recvfrom: "+string(strerror(errno)));
214 dgram.assign(d_buffer,bytes);
219 //! For datagram sockets, send a datagram to a destination
220 void sendTo(const char* msg, size_t len, const ComboAddress &ep)
222 if(sendto(d_socket, msg, len, 0, (sockaddr *)&ep, ep.getSocklen())<0)
223 throw NetworkError("After sendto: "+string(strerror(errno)));
226 //! For connected datagram sockets, send a datagram
227 void send(const std::string& msg)
229 if(::send(d_socket, msg.c_str(), msg.size(), 0)<0)
230 throw NetworkError("After send: "+string(strerror(errno)));
234 /** For datagram sockets, send a datagram to a destination
235 \param dgram The datagram
236 \param ep The intended destination of the datagram */
237 void sendTo(const string &dgram, const ComboAddress &ep)
239 sendTo(dgram.c_str(), dgram.length(), ep);
243 //! Write this data to the socket, taking care that all bytes are written out
244 void writen(const string &data)
249 size_t toWrite=data.length();
251 const char *ptr=data.c_str();
254 res=::send(d_socket, ptr, toWrite, 0);
256 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
258 throw NetworkError("EOF on socket");
259 toWrite-=(size_t)res;
265 //! tries to write toWrite bytes from ptr to the socket
266 /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
267 \param ptr Location to write from
268 \param toWrite number of bytes to try
270 size_t tryWrite(const char *ptr, size_t toWrite)
273 res=::send(d_socket,ptr,toWrite,0);
275 throw NetworkError("EOF on writing to a socket");
283 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
286 //! Writes toWrite bytes from ptr to the socket
287 /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
288 size_t write(const char *ptr, size_t toWrite)
291 res=::send(d_socket,ptr,toWrite,0);
293 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
298 void writenWithTimeout(const void *buffer, size_t n, int timeout)
301 const char *ptr = (char*)buffer;
304 ret=::write(d_socket, ptr, bytes);
307 ret=waitForRWData(d_socket, false, timeout, 0);
309 throw NetworkError("Waiting for data write");
311 throw NetworkError("Timeout writing data");
315 throw NetworkError("Writing data: "+stringerror());
318 throw NetworkError("Did not fulfill TCP write due to EOF");
322 bytes -= (size_t) ret;
326 //! reads one character from the socket
331 ssize_t res=::recv(d_socket,&c,1,0);
337 void getline(string &data)
341 while((c=getChar())!=-1) {
348 //! Reads a block of data from the socket to a string
349 void read(string &data)
351 ssize_t res=::recv(d_socket,d_buffer,d_buflen,0);
353 throw NetworkError("Reading from a socket: "+string(strerror(errno)));
354 data.assign(d_buffer,res);
357 //! Reads a block of data from the socket to a block of memory
358 size_t read(char *buffer, size_t bytes)
360 ssize_t res=::recv(d_socket,buffer,bytes,0);
362 throw NetworkError("Reading from a socket: "+string(strerror(errno)));
366 ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
368 int err = waitForRWData(d_socket, true, timeout, 0);
371 throw NetworkError("timeout reading");
373 throw NetworkError("nonblocking read failed: "+string(strerror(errno)));
375 return read(buffer, n);
378 //! Sets the socket to listen with a default listen backlog of 10 pending connections
379 void listen(unsigned int length=10)
381 if(::listen(d_socket,length)<0)
382 throw NetworkError("Setting socket to listen: "+string(strerror(errno)));
385 //! Returns the internal file descriptor of the socket
386 int getHandle() const