CPN
Computational Process Networks
SocketHandle.cc
Go to the documentation of this file.
1 //=============================================================================
2 // Computational Process Networks class library
3 // Copyright (C) 1997-2006 Gregory E. Allen and The University of Texas
4 //
5 // This library is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Library General Public License as published
7 // by the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Library General Public License for more details.
14 //
15 // The GNU Public License is available in the file LICENSE, or you
16 // can write to the Free Software Foundation, Inc., 59 Temple Place -
17 // Suite 330, Boston, MA 02111-1307, USA, or you can find it on the
18 // World Wide Web at http://www.fsf.org.
19 //=============================================================================
23 #include "common_priv.h"
24 #include <cpn/io/SocketHandle.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
32 
34  ASSERT(sock1.FD() == -1, "sock1 already connected");
35  ASSERT(sock2.FD() == -1, "sock2 already connected");
36  int pair[2];
37  CreatePair(pair);
38  sock1.FD(pair[0]);
39  sock2.FD(pair[1]);
40 }
41 
42 void SocketHandle::CreatePair(int fd[2]) {
43  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
44  throw ErrnoException(errno);
45  }
46 }
47 
49  int error = 0;
50  if (!Connect(addr, error)) { throw ErrnoException(error); }
51 }
52 
53 void SocketHandle::Connect(const SockAddrList &addrs) {
54  int error = 0;
55  bool success = false;
56  for (SockAddrList::const_iterator itr = addrs.begin();
57  itr != addrs.end(); ++itr) {
58  success = Connect(*itr, error);
59  if (success) break;
60  }
61  if (!success) throw ErrnoException(error);
62 }
63 
64 bool SocketHandle::Connect(const SocketAddress &addr, int &error) {
65  ASSERT(Closed(), "Already connected!");
66  int nfd = socket(addr.Family(), SOCK_STREAM, 0);
67  if (nfd < 0) {
68  error = errno;
69  return false;
70  }
71  SocketAddress address = addr;
72  bool loop = true;
73  while (loop) {
74  if (connect(nfd, address.GetAddr(), address.GetLen()) < 0) {
75  error = errno;
76  switch (error) {
77  case EINTR:
78  case EAGAIN: // not enough resources
79  break;
80  case EINPROGRESS: // non blocking and connection not completed yet
81  // may want to change things to let non blocking connect.
82  case EALREADY: // previous attempt has not completed
83  case EACCES:
84  case EPERM:
85  case EADDRINUSE:
86  case EAFNOSUPPORT:
87  case EBADF:
88  case ECONNREFUSED:
89  case EFAULT:
90  case EISCONN:
91  case ENETUNREACH:
92  case ENOTSOCK:
93  case ETIMEDOUT:
94  default:
95  close(nfd);
96  nfd = -1;
97  return false;
98  }
99  } else {
100  loop = false;
101  }
102  }
103  FD(nfd);
104  return true;
105 }
106 
108  if (shutdown(FD(), SHUT_RD) != 0) {
109  throw ErrnoException();
110  }
111 }
112 
114  if (shutdown(FD(), SHUT_WR) != 0) {
115  throw ErrnoException();
116  }
117 }
118 
119 unsigned SocketHandle::Recv(void *ptr, unsigned len, bool block) {
120  int filed;
121  {
122  ALock al(file_lock);
123  if (eof || fd == -1) { return 0; }
124  filed = fd;
125  }
126  int flags = 0;
127  if (block) {
128  flags |= MSG_WAITALL;
129  } else {
130  flags |= MSG_DONTWAIT;
131  }
132  unsigned bytesread = 0;
133  int num = recv(filed, ptr, len, flags);
134  if (num > 0) {
135  if (unsigned(num) < len) { Readable(false); }
136  bytesread = num;
137  } else if (num == 0 && len != 0) {
138  ALock al(file_lock);
139  eof = true;
140  readable = false;
141  } else if (num < 0) {
142  int error = errno;
143  switch (error) {
144  case EAGAIN: // Ether non blocking or timed out
145  Readable(false);
146  case EINTR: // Interrupted by an interrupt
147  case ENOMEM:
148  // report nothing received
149  break;
150  default:
151  throw ErrnoException(error);
152  }
153  }
154  return bytesread;
155 }
156 
157 #if !defined(__APPLE__)
159  if (block) { flags &= ~MSG_DONTWAIT; }
160  else { flags |= MSG_DONTWAIT; }
161  return *this;
162 }
163 
165  if (sig) { flags &= ~MSG_NOSIGNAL; }
166  else { flags |= MSG_NOSIGNAL; }
167  return *this;
168 }
169 
171  if (more) { flags |= MSG_MORE; }
172  else { flags &= ~MSG_MORE; }
173  return *this;
174 }
175 #endif
176 
177 unsigned SocketHandle::Send(const void *ptr, unsigned len, const SendOpts &opts) {
178  int filed;
179  {
180  ALock al(file_lock);
181  if (fd == -1) { return 0; }
182  filed = fd;
183  }
184  unsigned written = 0;
185  int num = send(filed, ptr, len, opts.flags);
186  if (num < 0) {
187  int error = errno;
188  switch (error) {
189  case EAGAIN:
190  Writeable(false);
191  case EINTR:
192  case ENOMEM:
193  break;
194  default:
195  throw ErrnoException(error);
196  }
197  } else {
198  if (unsigned(num) < len) { Writeable(false); }
199  written = num;
200  }
201  return written;
202 }
203 
205  int err = 0;
206  socklen_t len = sizeof(err);
207  if (getsockopt(FD(), SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
208  throw ErrnoException();
209  }
210  return err;
211 }
212 
214  if (setsockopt(FD(), SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0) {
215  throw ErrnoException();
216  }
217 }
218 
220  int ka;
221  socklen_t len = sizeof(ka);
222  if (getsockopt(FD(), SOL_SOCKET, SO_KEEPALIVE, &ka, &len) < 0) {
223  throw ErrnoException();
224  }
225  return ka;
226 }
227 
229  linger l = {0};
230  if (seconds > 0) {
231  l.l_onoff = 1;
232  l.l_linger = seconds;
233  }
234  if (setsockopt(FD(), SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
235  throw ErrnoException();
236  }
237 }
238 
240  linger l = {0};
241  socklen_t len = sizeof(l);
242  if (getsockopt(FD(), SOL_SOCKET, SO_LINGER, &l, &len) < 0) {
243  throw ErrnoException();
244  }
245  if (l.l_onoff) {
246  return -1;
247  } else {
248  return l.l_linger;
249  }
250 }
251 
253  if (setsockopt(FD(), SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) {
254  throw ErrnoException();
255  }
256 }
257 
259  int size;
260  socklen_t len = sizeof(size);
261  if (getsockopt(FD(), SOL_SOCKET, SO_RCVBUF, &size, &len) < 0) {
262  throw ErrnoException();
263  }
264  return size;
265 }
266 
268  if (setsockopt(FD(), SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) {
269  throw ErrnoException();
270  }
271 }
272 
274  int size;
275  socklen_t len = sizeof(size);
276  if (getsockopt(FD(), SOL_SOCKET, SO_SNDBUF, &size, &len) < 0) {
277  throw ErrnoException();
278  }
279  return size;
280 }
281 
282 
283 void SocketHandle::SetReceiveTimeout(double timeout) {
284  timeval tv = {0};
285  tv.tv_sec = (int)timeout;
286  tv.tv_usec = (int)((timeout - tv.tv_sec) * 1e6);
287  if (setsockopt(FD(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
288  throw ErrnoException();
289  }
290 }
291 
292 void SocketHandle::SetSendTimeout(double timeout) {
293  timeval tv = {0};
294  tv.tv_sec = (int)timeout;
295  tv.tv_usec = (int)((timeout - tv.tv_sec) * 1e6);
296  if (setsockopt(FD(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
297  throw ErrnoException();
298  }
299 }
300 
302  timeval tv = {0};
303  socklen_t len = sizeof(tv);
304  if (getsockopt(FD(), SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
305  throw ErrnoException();
306  }
307  return ((double)tv.tv_sec) + (((double)tv.tv_usec)*1e-6);
308 }
309 
311  timeval tv = {0};
312  socklen_t len = sizeof(tv);
313  if (getsockopt(FD(), SOL_SOCKET, SO_SNDTIMEO, &tv, &len) < 0) {
314  throw ErrnoException();
315  }
316  return ((double)tv.tv_sec) + (((double)tv.tv_usec)*1e-6);
317 }
318 
319 void SocketHandle::SetNoDelay(bool nodelay) {
320  int flag = nodelay ? 1 : 0;
321  if (setsockopt(FD(), IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0) {
322  throw ErrnoException();
323  }
324 }
325 
327  int flag = 0;
328  socklen_t len = sizeof(flag);
329  if (getsockopt(FD(), IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
330  throw ErrnoException();
331  }
332  return flag == 0 ? false : true;
333 }
334 
335 
336 
int GetReceiveBufferSize()
void SetSendTimeout(double timeout)
SendOpts & Block(bool block)
void ShutdownRead()
Shutdown the read end of this socket. This does NOT close the socket! Any future attempt to read from...
void ShutdownWrite()
Shutdown the write end of this socket. Any future attempt to write to this socket will fail...
void SetSendBufferSize(int size)
An abstraction of a socket address with convenience methods.
Definition: SocketAddress.h:42
A FileHandle customized with some socket specific functionality and functions.
Definition: SocketHandle.h:34
void SetKeepAlive(int ka)
socklen_t & GetLen()
void SetLingerTimeout(int seconds)
Set the linger socket options.
unsigned Recv(void *ptr, unsigned len, bool block)
static void CreatePair(SocketHandle &sock1, SocketHandle &sock2)
Create a socket pair.
Definition: SocketHandle.cc:33
SendOpts & More(bool more)
PthreadMutex file_lock
Definition: FileHandle.h:213
sa_family_t & Family()
int GetKeepAlive()
sockaddr * GetAddr()
bool Closed() const
Definition: FileHandle.h:128
double GetReceiveTimeout()
void SetNoDelay(bool nodelay)
SendOpts & NoSignal(bool sig)
void SetReceiveBufferSize(int size)
int GetLingerTimeout()
int GetPendingError()
Get and clear any pending error.
int GetSendBufferSize()
bool Writeable() const
Gives the current writability status of the file.
Definition: FileHandle.h:102
int FD() const
Definition: FileHandle.h:106
unsigned Send(const void *ptr, unsigned len, const SendOpts &opts)
bool readable
Definition: FileHandle.h:215
std::vector< SocketAddress > SockAddrList
Definition: SocketAddress.h:35
bool Readable() const
Gives the current readability status of the file.
Definition: FileHandle.h:91
bool GetNoDelay()
void SetReceiveTimeout(double timeout)
double GetSendTimeout()
void Connect(const SocketAddress &addr)
Create a new socket and try to connect to the given address.
Definition: SocketHandle.cc:48
#define ASSERT(exp,...)