11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <sys/select.h>
17 #include <boost/shared_ptr.hpp>
18 #include <boost/utility.hpp>
20 #include "namespaces.hh"
21 #include "namespaces.hh"
24 class NetworkError : public runtime_error
27 NetworkError(const string& why="Network Error") : runtime_error(why.c_str())
29 NetworkError(const char *why="Network Error") : runtime_error(why)
34 typedef int ProtocolType; //!< Supported protocol types
36 //! Representation of a Socket and many of the Berkeley functions available
37 class Socket : public boost::noncopyable
40 //! Construct a socket of specified address family and socket type.
41 Socket(int af, int st, ProtocolType pt=0)
44 if((d_socket=(int)socket(af,st, pt))<0)
45 throw NetworkError(strerror(errno));
46 Utility::setCloseOnExec(d_socket);
49 d_buffer=new char[d_buflen];
54 Utility::closesocket(d_socket);
58 //! If the socket is capable of doing so, this function will wait for a connection
61 struct sockaddr_in remote;
62 socklen_t remlen=sizeof(remote);
63 memset(&remote, 0, sizeof(remote));
64 int s=(int)::accept(d_socket,(sockaddr *)&remote, &remlen);
69 throw NetworkError("Accepting a connection: "+string(strerror(errno)));
72 return new Socket(s, d_family);
75 //! Set the socket to non-blocking
78 Utility::setNonBlocking(d_socket);
84 if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast<unsigned>(sizeof tmp))<0)
85 throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
88 //! Bind the socket to a specified endpoint
89 void bind(const ComboAddress &local)
92 if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
93 throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
95 if(::bind(d_socket,(struct sockaddr *)&local, local.getSocklen())<0)
96 throw NetworkError(strerror(errno));
100 //! Bind the socket to a specified endpoint
101 void bind(const ComboAddress &ep)
104 memset(reinterpret_cast<char *>(&local),0,sizeof(local));
105 local.sin_family=d_family;
106 local.sin_addr.s_addr=ep.address.byte;
107 local.sin_port=htons(ep.port);
112 //! Connect the socket to a specified endpoint
113 void connect(const ComboAddress &ep)
115 if(::connect(d_socket,(struct sockaddr *)&ep, ep.getSocklen()) < 0 && errno != EINPROGRESS)
116 throw NetworkError(strerror(errno));
120 //! For datagram sockets, receive a datagram and learn where it came from
121 /** For datagram sockets, receive a datagram and learn where it came from
122 \param dgram Will be filled with the datagram
123 \param ep Will be filled with the origin of the datagram */
124 void recvFrom(string &dgram, ComboAddress &ep)
126 socklen_t remlen=sizeof(ep);
128 if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&ep , &remlen)) <0)
129 throw NetworkError(strerror(errno));
131 dgram.assign(d_buffer,bytes);
134 bool recvFromAsync(string &dgram, ComboAddress &ep)
136 struct sockaddr_in remote;
137 socklen_t remlen=sizeof(remote);
139 if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&remote, &remlen))<0) {
141 throw NetworkError(strerror(errno));
147 dgram.assign(d_buffer,bytes);
152 //! For datagram sockets, send a datagram to a destination
153 void sendTo(const char* msg, unsigned int len, const ComboAddress &ep)
155 if(sendto(d_socket, msg, len, 0, (sockaddr *)&ep, ep.getSocklen())<0)
156 throw NetworkError(strerror(errno));
159 /** For datagram sockets, send a datagram to a destination
160 \param dgram The datagram
161 \param ep The intended destination of the datagram */
162 void sendTo(const string &dgram, const ComboAddress &ep)
164 sendTo(dgram.c_str(), dgram.length(), ep);
168 //! Write this data to the socket, taking care that all bytes are written out
169 void writen(const string &data)
174 int toWrite=(int)data.length();
176 const char *ptr=data.c_str();
179 res=::send(d_socket, ptr, toWrite, 0);
181 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
183 throw NetworkError("EOF on socket");
190 //! tries to write toWrite bytes from ptr to the socket
191 /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
192 \param ptr Location to write from
193 \param toWrite number of bytes to try
195 unsigned int tryWrite(const char *ptr, int toWrite)
198 res=::send(d_socket,ptr,toWrite,0);
200 throw NetworkError("EOF on writing to a socket");
208 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
211 //! Writes toWrite bytes from ptr to the socket
212 /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
213 unsigned int write(const char *ptr, int toWrite)
216 res=::send(d_socket,ptr,toWrite,0);
218 throw NetworkError("Writing to a socket: "+string(strerror(errno)));
223 void writenWithTimeout(const void *buffer, unsigned int n, int timeout)
225 unsigned int bytes=n;
226 const char *ptr = (char*)buffer;
229 ret=::write(d_socket, ptr, bytes);
232 ret=waitForRWData(d_socket, false, timeout, 0);
234 throw NetworkError("Waiting for data write");
236 throw NetworkError("Timeout writing data");
240 throw NetworkError("Writing data: "+stringerror());
243 throw NetworkError("Did not fulfill TCP write due to EOF");
251 //! reads one character from the socket
256 int res=::recv(d_socket,&c,1,0);
262 void getline(string &data)
266 while((c=getChar())!=-1) {
273 //! Reads a block of data from the socket to a string
274 void read(string &data)
276 int res=::recv(d_socket,d_buffer,d_buflen,0);
278 throw NetworkError("Reading from a socket: "+string(strerror(errno)));
279 data.assign(d_buffer,res);
282 //! Reads a block of data from the socket to a block of memory
283 int read(char *buffer, int bytes)
285 int res=::recv(d_socket,buffer,bytes,0);
287 throw NetworkError("Reading from a socket: "+string(strerror(errno)));
291 int readWithTimeout(char* buffer, int n, int timeout)
293 int err = waitForRWData(d_socket, true, timeout, 0);
296 throw NetworkError("timeout reading");
298 throw NetworkError("nonblocking read failed: "+string(strerror(errno)));
300 return read(buffer, n);
303 //! Sets the socket to listen with a default listen backlog of 10 bytes
304 void listen(unsigned int length=10)
306 if(::listen(d_socket,length)<0)
307 throw NetworkError("Setting socket to listen: "+string(strerror(errno)));
310 //! Returns the internal file descriptor of the socket
311 int getHandle() const