ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pipe-fd.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Frederic Urbani <frederic.urbani@inria.fr>
19  *
20  */
21 #include "pipe-fd.h"
22 #include "ns3/log.h"
23 #include "utils.h"
24 #include "process.h"
25 #include <poll.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 
29 NS_LOG_COMPONENT_DEFINE ("PipeFd");
30 
31 #define PIPE_CAPACITY 65536
32 
33 namespace ns3 {
34 PipeFd::PipeFd () : m_peer (0),
35  m_readSide (1),
36  m_statusFlags (0),
37  m_buf (PIPE_CAPACITY)
38 {
39 }
40 
41 PipeFd::PipeFd (PipeFd *peer) : m_peer (peer),
42  m_readSide (0),
43  m_statusFlags (0),
44  m_buf (0)
45 {
46  m_peer->m_peer = this;
47 }
48 
49 int
51 {
52  NS_LOG_FUNCTION (this);
53  if (m_peer)
54  {
55  PipeFd *p = m_peer;
56  m_peer = 0;
57  p->Close ();
58  short ph = POLLHUP;
59  WakeWaiters (&ph);
60  return 0;
61  }
62  Current ()->err = EBADF;
63  return -1;
64 }
65 
66 ssize_t
67 PipeFd::Write (const void *buf, size_t count)
68 {
69  NS_LOG_FUNCTION (this);
70  if (m_peer)
71  {
72  if (m_readSide)
73  {
74  Current ()->err = EBADF;
75  return -1;
76  }
77  size_t r = m_peer->DoRecvPacket ((uint8_t*)buf, count);
78  if (r > 0)
79  {
80  short po = POLLOUT;
81  WakeWaiters (&po); // WakeUp
82  }
83  return r;
84  }
85  UtilsSendSignal (Current ()->process, SIGPIPE);
86  UtilsDoSignal ();
87  Current ()->err = EPIPE;
88  return -1;
89 }
90 ssize_t
91 PipeFd::DoRecvPacket (uint8_t* buf, size_t len)
92 {
93  Thread *current = Current ();
94  NS_LOG_FUNCTION (this << (long)buf << len);
95  NS_ASSERT (current != 0);
96 
97  WaitQueueEntryTimeout *wq = 0;
98 
99  while (true)
100  {
101  ssize_t r = m_buf.Write (buf, len);
102  if (r > 0)
103  {
104  short pi = POLLIN;
105  WakeWaiters (&pi); // WakeUp reader or poller for read or select for read
106 
107  RETURNFREE (r);
108  }
109  if (m_peer->m_statusFlags & O_NONBLOCK)
110  {
111  Current ()->err = EAGAIN;
112  RETURNFREE (-1);
113  }
114 
115  if (!wq)
116  {
117  wq = new WaitQueueEntryTimeout (POLLOUT | POLLHUP, Time (0));
118  }
119  AddWaitQueue (wq, true);
120  PollTable::Result res = wq->Wait ();
121  RemoveWaitQueue (wq, true);
122 
123  switch (res)
124  {
125  case PollTable::OK:
126  break;
128  {
129  UtilsDoSignal ();
130 
131  current->err = EINTR;
132  RETURNFREE (-1);
133  }
134  break;
135  case PollTable::TIMEOUT:
136  {
137  current->err = EAGAIN;
138  RETURNFREE (-1);
139  }
140  break;
141  }
142  }
143 }
144 
145 ssize_t
146 PipeFd::Read (void *buf, size_t count)
147 {
148  Thread *current = Current ();
149  NS_LOG_FUNCTION (this << (long)buf << count);
150  NS_ASSERT (current != 0);
151 
152  if (!m_readSide)
153  {
154  Current ()->err = EBADF;
155  return -1;
156  }
157  WaitQueueEntryTimeout *wq = 0;
158 
159  while (true)
160  {
161  ssize_t r = m_buf.Read ((uint8_t*)buf, count);
162  if (r > 0)
163  {
164  short po = POLLOUT;
165  if (m_peer)
166  {
167  // WakeUp
168  m_peer->WakeWaiters (&po);
169  }
170  WakeWaiters (&po);
171 
172  RETURNFREE (r);
173  }
174  if (0 == m_peer)
175  {
176  Current ()->err = EPIPE;
177  RETURNFREE (-1);
178  }
179  if (m_statusFlags & O_NONBLOCK)
180  {
181  Current ()->err = EAGAIN;
182  RETURNFREE (-1);
183  }
184  if (!wq)
185  {
186  wq = new WaitQueueEntryTimeout (POLLIN | POLLHUP, Time (0));
187  }
188  AddWaitQueue (wq, true);
189  PollTable::Result res = wq->Wait ();
190  RemoveWaitQueue (wq, true);
191 
192  switch (res)
193  {
194  case PollTable::OK:
195  break;
197  {
198  UtilsDoSignal ();
199  current->err = EINTR;
200  RETURNFREE (-1);
201  }
202  break;
203  case PollTable::TIMEOUT:
204  {
205  current->err = EAGAIN;
206  RETURNFREE (-1);
207  }
208  break;
209  }
210  }
211 }
212 
213 ssize_t
214 PipeFd::Recvmsg (struct msghdr *msg, int flags)
215 {
216  Thread *current = Current ();
217  NS_LOG_FUNCTION (this << current);
218  NS_ASSERT (current != 0);
219  current->err = ENOTSOCK;
220  return -1;
221 }
222 
223 ssize_t
224 PipeFd::Sendmsg (const struct msghdr *msg, int flags)
225 {
226  Thread *current = Current ();
227  NS_LOG_FUNCTION (this << current);
228  NS_ASSERT (current != 0);
229  current->err = ENOTSOCK;
230  return -1;
231 }
232 
233 int
234 PipeFd::Setsockopt (int level, int optname,
235  const void *optval, socklen_t optlen)
236 {
237  Thread *current = Current ();
238  NS_LOG_FUNCTION (this << current);
239  NS_ASSERT (current != 0);
240  current->err = ENOTSOCK;
241  return -1;
242 }
243 
244 int
245 PipeFd::Getsockopt (int level, int optname,
246  void *optval, socklen_t *optlen)
247 {
248  Thread *current = Current ();
249  NS_LOG_FUNCTION (this << current);
250  NS_ASSERT (current != 0);
251  current->err = ENOTSOCK;
252  return -1;
253 }
254 
255 int
256 PipeFd::Getsockname (struct sockaddr *name, socklen_t *namelen)
257 {
258  Thread *current = Current ();
259  NS_LOG_FUNCTION (this << current);
260  NS_ASSERT (current != 0);
261  current->err = ENOTSOCK;
262  return -1;
263 }
264 
265 int
266 PipeFd::Getpeername (struct sockaddr *name, socklen_t *namelen)
267 {
268  Thread *current = Current ();
269  NS_LOG_FUNCTION (this << current);
270  NS_ASSERT (current != 0);
271  current->err = ENOTSOCK;
272  return -1;
273 }
274 
275 int
276 PipeFd::Ioctl (int request, char *argp)
277 {
278  Thread *current = Current ();
279  NS_LOG_FUNCTION (this << current);
280  NS_ASSERT (current != 0);
281  current->err = EINVAL;
282  return -1;
283 }
284 
285 int
286 PipeFd::Bind (const struct sockaddr *my_addr, socklen_t addrlen)
287 {
288  Thread *current = Current ();
289  NS_LOG_FUNCTION (this << current);
290  NS_ASSERT (current != 0);
291  current->err = ENOTSOCK;
292  return -1;
293 }
294 
295 int
296 PipeFd::Connect (const struct sockaddr *my_addr, socklen_t addrlen)
297 {
298  Thread *current = Current ();
299  NS_LOG_FUNCTION (this << current);
300  NS_ASSERT (current != 0);
301  current->err = ENOTSOCK;
302  return -1;
303 }
304 
305 int
306 PipeFd::Listen (int backlog)
307 {
308  Thread *current = Current ();
309  NS_LOG_FUNCTION (this << current);
310  NS_ASSERT (current != 0);
311  current->err = ENOTSOCK;
312  return -1;
313 }
314 
315 int
317 {
318  Thread *current = Current ();
319  NS_LOG_FUNCTION (this << current);
320  NS_ASSERT (current != 0);
321  current->err = ENOTSOCK;
322  return -1;
323 }
324 
325 int
326 PipeFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
327 {
328  Thread *current = Current ();
329  NS_LOG_FUNCTION (this << current);
330  NS_ASSERT (current != 0);
331  current->err = ENOTSOCK;
332  return -1;
333 }
334 
335 void *
336 PipeFd::Mmap (void *start, size_t length, int prot, int flags, off64_t offset)
337 {
338  Thread *current = Current ();
339  NS_LOG_FUNCTION (this << current);
340  NS_ASSERT (current != 0);
341  current->err = EBADF;
342  return 0;
343 }
344 
345 off64_t
346 PipeFd::Lseek (off64_t offset, int whence)
347 {
348  Thread *current = Current ();
349  NS_LOG_FUNCTION (this << current);
350  NS_ASSERT (current != 0);
351  current->err = EBADF;
352  return -1;
353 }
354 
355 int
356 PipeFd::Fxstat (int ver, struct ::stat *buf)
357 {
358  Thread *current = Current ();
359  NS_LOG_FUNCTION (this << current);
360  NS_ASSERT (current != 0);
361  current->err = EBADF;
362  return -1;
363 }
364 
365 int
366 PipeFd::Fxstat64 (int ver, struct ::stat64 *buf)
367 {
368  Thread *current = Current ();
369  NS_LOG_FUNCTION (this << current);
370  NS_ASSERT (current != 0);
371  current->err = EBADF;
372  return -1;
373 }
374 
375 int
376 PipeFd::Fcntl (int cmd, unsigned long arg)
377 {
378  switch (cmd)
379  {
380  case F_GETFL:
381  return m_statusFlags;
382  break;
383  case F_SETFL:
384  m_statusFlags = arg;
385  return 0;
386  break;
387  default:
388  NS_FATAL_ERROR ("fcntl not implemented on pipe");
389  return -1;
390  }
391 }
392 
393 int
394 PipeFd::Settime (int flags,
395  const struct itimerspec *new_value,
396  struct itimerspec *old_value)
397 {
398  NS_LOG_FUNCTION (this << Current () << flags << new_value << old_value);
399  NS_ASSERT (Current () != 0);
400  Thread *current = Current ();
401  current->err = EINVAL;
402  return -1;
403 }
404 
405 int
406 PipeFd::Gettime (struct itimerspec *cur_value) const
407 {
408  NS_LOG_FUNCTION (this << Current ());
409  NS_ASSERT (Current () != 0);
410  Thread *current = Current ();
411  current->err = EINVAL;
412  return -1;
413 }
414 
415 int
416 PipeFd::Ftruncate (off_t length)
417 {
418  NS_LOG_FUNCTION (this << Current ());
419  NS_ASSERT (Current () != 0);
420  Thread *current = Current ();
421  current->err = EINVAL;
422  return -1;
423 }
424 
425 // Return true if a select on this fd should return POLLHUP
426 bool
428 {
429  return (0 == m_peer);
430 }
431 bool
432 PipeFd::Isatty (void) const
433 {
434  return 0;
435 }
436 
437 int
439 {
440  int ret = 0;
441 
442  if (m_readSide)
443  {
444  if (m_buf.GetSize () > 0)
445  {
446  ret |= POLLIN;
447  }
448  }
449  else
450  {
451  if (m_peer && (m_peer->m_buf.GetSpace () > 0))
452  {
453  ret |= POLLOUT;
454  }
455  }
456  if (0 == m_peer)
457  {
458  ret |= POLLHUP;
459  }
460  if (ptable)
461  {
462  ptable->PollWait (this);
463  }
464 #ifdef TODO
465  if (m_readSide)
466  {
467  if (m_buffer.GetSize () < PIPE_CAPACITY)
468  {
469  ret |= POLLIN;
470  }
471  }
472  else
473  {
474  if (m_peer && (m_peer->m_buffer.GetSize () < PIPE_CAPACITY))
475  {
476  ret |= POLLOUT;
477  }
478  }
479 
480  if (HangupReceived ())
481  {
482  ret |= POLLHUP;
483  }
484 
485  if (ptable)
486  {
487  ptable->PollWait (this);
488  }
489 #endif
490  return ret;
491 }
492 
493 
494 } // namespace ns3