ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
local-datagram-socket-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 "local-socket-fd.h"
24 #include "utils.h"
25 #include "process.h"
26 #include "ns3/log.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/mman.h> // for MMAP_FAILED
30 #include <sys/un.h>
31 #include "unix-fd.h"
32 #include <exception>
33 #include <poll.h>
34 #include "wait-queue.h"
35 #include <unistd.h>
36 
37 NS_LOG_COMPONENT_DEFINE ("LocalDatagramSocketFd");
38 
39 namespace ns3 {
40 TypeId
42 {
43  static TypeId tid = TypeId ("ns3::LocalDatagramSocketFd").SetParent<LocalSocketFd> ();
44 
45  return tid;
46 }
47 TypeId
49 {
51 }
52 LocalDatagramSocketFd::LocalDatagramSocketFd (Ptr<LocalSocketFdFactory> f)
53  : m_state (CREATED),
54  m_peer (0)
55 {
56  m_factory = f;
57 }
59 {
60  ClearAll (false);
61 }
62 
63 void
65 {
66  NS_LOG_FUNCTION (this);
67  ClearAll (false);
68 }
69 
70 int
72 {
73  NS_LOG_FUNCTION (this);
74 
75  switch (m_state)
76  {
77  case CONNECTED:
78  case BINDED:
79  ClearAll (true);
80  break;
81 
82  default:
83  ClearAll (false);
84  break;
85  }
86 
87  return 0;
88 }
89 ssize_t
90 LocalDatagramSocketFd::Write (const void *buf, size_t count)
91 {
92  NS_LOG_FUNCTION (this << "state:" << m_state);
93 
94  if (CONNECTED != m_state)
95  {
96 
97  Current ()->err = (REMOTECLOSED == m_state) ? ECONNREFUSED : ENOTCONN;
98 
99  return -1;
100  }
101 
102  return Write2Peer (buf, count, m_peer);
103 }
104 
105 ssize_t
106 LocalDatagramSocketFd::Read (void *buf, size_t count, bool noWait, bool peek)
107 {
108  NS_LOG_FUNCTION (this << "state:" << m_state);
109  WaitQueueEntryTimeout *wq = 0;
110 
111  while (BINDED == m_state)
112  {
113  // Is There some already received data ?
114  if (m_readBuffer.size () > 0)
115  {
116  ssize_t ret = ReadData ((uint8_t*) buf, count, peek);
117 
118  if ((ret > 0)&&(0 != m_peer))
119  {
120  // WakeUP peer because we made room
121  short po = POLLOUT;
122  m_peer->WakeWaiters (&po);
123  }
124  RETURNFREE (ret);
125  }
126 
127  // Should Wait data ?
128  if (noWait || m_shutRead)
129  {
130  RETURNFREE (0);
131  }
132  if (m_statusFlags & O_NONBLOCK)
133  {
134  // Socket do not want to wait
135  Current ()->err = EAGAIN;
136  RETURNFREE (-1);
137  }
138  // Before wait verify not closed by another thread !
139  if (BINDED != m_state)
140  {
141  Current ()->err = ENOTCONN;
142  RETURNFREE (-1);
143  }
144  if (!wq)
145  {
146  wq = new WaitQueueEntryTimeout (POLLIN | POLLHUP, GetRecvTimeout ());
147  }
148  AddWaitQueue (wq, true);
149  WaitPoint::Result res = wq->Wait ();
150  RemoveWaitQueue (wq, true);
151 
152  switch (res)
153  {
154  case WaitPoint::OK:
155  break;
156 
158  UtilsDoSignal ();
159  if (0 == m_readBuffer.size ())
160  {
161  Current ()->err = EINTR;
162  RETURNFREE (-1);
163  }
164  break;
165 
166  case WaitPoint::TIMEOUT:
167  if (0 == m_readBuffer.size ())
168  {
169  Current ()->err = EAGAIN;
170  RETURNFREE (-1);
171  }
172  break;
173  }
174  }
175 
176  Current ()->err = ENOTCONN;
177  RETURNFREE (-1);
178 }
179 
180 int
181 LocalDatagramSocketFd::Setsockopt (int level, int optname, const void *optval, socklen_t optlen)
182 {
183  Thread *current = Current ();
184  NS_LOG_FUNCTION (this << current << level << optname << optval << optlen);
185  NS_ASSERT (current != 0);
186 
187  if (level != SOL_SOCKET)
188  {
189  current->err = EINVAL;
190  return -1;
191  }
192 
193  switch (optname)
194  {
195  case SO_PASSCRED:
196  {
197  NS_LOG_DEBUG ("LocalDatagramSocketFd SO_PASSCRED NOT IMPLEMENTED");
198  current->err = EINVAL;
199  return -1;
200  }
201 
202  case SO_RCVBUF:
203  case SO_SNDBUF:
204  {
205  NS_LOG_DEBUG ("LocalDatagramSocketFd SO_RCVBUF and SO_SNDBUF ignored.");
206  return 0;
207  }
208  case SO_RCVLOWAT:
209  {
210  NS_LOG_DEBUG ("LocalDatagramSocketFd SO_RCVLOWAT ignored.");
211  return 0;
212  }
213  case SO_SNDLOWAT:
214  {
215  NS_LOG_DEBUG ("LocalDatagramSocketFd SO_SNDLOWAT ignored.");
216  return 0;
217  }
218 
219  case SO_RCVTIMEO:
220  {
221  if ((0 == optval) || (0 == optlen) || (optlen < sizeof(struct timeval)))
222  {
223  current->err = EINVAL;
224  return -1;
225  }
226 
227  m_recvTimeout = UtilsTimevalToTime ((struct timeval *) optval);
228 
229  return 0;
230  }
231 
232  case SO_SNDTIMEO:
233  {
234  if ((0 == optval) || (0 == optlen) || (optlen < sizeof(struct timeval)))
235  {
236  current->err = EINVAL;
237  return -1;
238  }
239 
240  m_sendTimeout = UtilsTimevalToTime ((struct timeval *) optval);
241 
242  return 0;
243  }
244 
245  default:
246  break;
247  }
248  current->err = EINVAL;
249  return -1;
250 }
251 
252 int
253 LocalDatagramSocketFd::Getsockopt (int level, int optname, void *optval, socklen_t *optlen)
254 {
255  Thread *current = Current ();
256  NS_LOG_FUNCTION (this << current << level << optname << optval << optlen);
257  NS_ASSERT (current != 0);
258 
259  if (level != SOL_SOCKET)
260  {
261  current->err = EINVAL;
262  return -1;
263  }
264 
265  switch (optname)
266  {
267  case SO_PASSCRED:
268  {
269  NS_LOG_DEBUG ("LocalDatagramSocketFd SO_PASSCRED NOT IMPLEMENTED");
270  current->err = EINVAL;
271  return -1;
272  }
273 
274  case SO_RCVBUF:
275  case SO_SNDBUF:
276  {
277  if ((0 == optval) || (0 == optlen) || ((*optlen) < sizeof(int)))
278  {
279  current->err = EINVAL;
280  return -1;
281  }
282 
283  int *ival = (int*)optval;
284 
285  *ival = LOCAL_SOCKET_MAX_BUFFER;
286 
287  (*optlen) = sizeof(int);
288 
289  return 0;
290  }
291  case SO_SNDLOWAT:
292  case SO_RCVLOWAT:
293  {
294  if ((0 == optval) || (0 == optlen) || ((*optlen) < sizeof(int)))
295  {
296  current->err = EINVAL;
297  return -1;
298  }
299 
300  int *ival = (int*)optval;
301 
302  *ival = 1;
303 
304  (*optlen) = sizeof(int);
305 
306  return 0;
307  }
308 
309  case SO_RCVTIMEO:
310  {
311  if ((0 == optval) || (0 == optlen) || ((*optlen) < sizeof(struct timeval)))
312  {
313  current->err = EINVAL;
314  return -1;
315  }
316 
317  struct timeval *tv = (struct timeval*)optval;
318 
320 
321  return 0;
322  }
323 
324  case SO_SNDTIMEO:
325  {
326  if ((0 == optval) || (0 == optlen) || ((*optlen) < sizeof(struct timeval)))
327  {
328  current->err = EINVAL;
329  return -1;
330  }
331 
332  struct timeval *tv = (struct timeval*)optval;
333 
335 
336  return 0;
337  }
338 
339  case SO_TYPE:
340  {
341  if ((0 == optval) || (0 == optlen) || ((*optlen) < sizeof(int)))
342  {
343  current->err = EINVAL;
344  return -1;
345  }
346 
347  int *ival = (int*)optval;
348 
349  *ival = SOCK_DGRAM;
350 
351  (*optlen) = sizeof(int);
352 
353  return 0;
354  }
355 
356  default:
357  {
358  current->err = EINVAL;
359  return -1;
360  }
361  }
362 
363  return -1;
364 }
365 
366 int
367 LocalDatagramSocketFd::Getsockname (struct sockaddr *name, socklen_t *namelen)
368 {
369  NS_LOG_FUNCTION (this);
370 
371  if ((0 == name) || (0 == namelen))
372  {
373  Current ()->err = EINVAL;
374  return -1;
375  }
376  struct sockaddr_un address;
377 
378  memset (&address, 0, sizeof(sockaddr_un));
379  address.sun_family = AF_UNIX;
380  if ((m_bindPath.length () > 0)&&(m_state != CLOSED))
381  {
382  std::string root = UtilsGetRealFilePath ("/");
383  std::string virtualPath = m_bindPath.substr (root.length () - 1);
384 
385  memcpy (&address.sun_path, virtualPath.c_str (), std::min (108, (int)virtualPath.length ()));
386  }
387 
388  socklen_t len = std::min ((int) *namelen, (int) sizeof(struct sockaddr_un));
389 
390  memcpy (name, &address, len);
391 
392  *namelen = len;
393 
394  return 0;
395 }
396 
397 int
398 LocalDatagramSocketFd::Getpeername (struct sockaddr *name, socklen_t *namelen)
399 {
400  NS_LOG_FUNCTION (this);
401 
402  if ((0 == name) || (0 == namelen))
403  {
404  Current ()->err = EINVAL;
405  return -1;
406  }
407  if ((m_state != CONNECTED) && (m_state != REMOTECLOSED))
408  {
409  Current ()->err = ENOTCONN;
410  return -1;
411  }
412  struct sockaddr_un address;
413 
414  memset (&address, 0, sizeof(sockaddr_un));
415  address.sun_family = AF_UNIX;
416  if (m_connectPath.length () > 0)
417  {
418  std::string root = UtilsGetRealFilePath ("/");
419  std::string virtualPath = m_connectPath.substr (root.length () - 1);
420 
421  memcpy (&address.sun_path, virtualPath.c_str (), std::min (108, (int)virtualPath.length ()));
422  }
423 
424  socklen_t len = std::min ((int) *namelen, (int) sizeof(struct sockaddr_un));
425 
426  memcpy (name, &address, len);
427 
428  *namelen = len;
429 
430  return 0;
431 }
432 
433 int
434 LocalDatagramSocketFd::Bind (const struct sockaddr *my_addr, socklen_t addrlen)
435 {
436  NS_LOG_FUNCTION (this);
437 
438  if (my_addr->sa_family != AF_UNIX)
439  {
440  Current ()->err = EINVAL;
441  return -1;
442  }
443 
444  if (m_state != CREATED)
445  {
446  return -1;
447  }
448 
449  std::string realPath = UtilsGetRealFilePath (std::string (((struct sockaddr_un*) my_addr)->sun_path));
450  struct sockaddr_un realAddr;
451 
452  memset (&realAddr, 0, sizeof(realAddr));
453  realAddr.sun_family = my_addr->sa_family;
454  memcpy (&(realAddr.sun_path), realPath.c_str (), std::min (108, (int) realPath.length ()));
455 
456  int realFd = ::socket (AF_UNIX, SOCK_DGRAM, 0);
457 
459 
460  int ret = ::bind (realFd, (struct sockaddr *) &realAddr, sizeof(realAddr));
461  NS_LOG_FUNCTION (this << "Bind: " << ret << "errno:" << errno);
462  if (0 == ret)
463  {
464  m_state = BINDED;
465  m_bindPath = realPath;
466  m_factory->RegisterBinder (m_bindPath, this);
467  }
468  else
469  {
470  Current ()->err = errno;
471  }
472  close (realFd);
473 
474  return ret;
475 }
476 
477 int
478 LocalDatagramSocketFd::Connect (const struct sockaddr *my_addr, socklen_t addrlen)
479 {
480  Thread *current = Current ();
481  NS_LOG_FUNCTION (this << current << my_addr << addrlen);
482  NS_ASSERT (current != 0);
483 
484  // first seek bind one
485  if (0 == m_factory)
486  {
487  Current ()->err = EINVAL;
488  return -1;
489  }
490  switch (m_state)
491  {
492  default:
493  case CREATED:
494  break;
495 
496  case BINDED:
497  {
498  Current ()->err = EADDRINUSE;
499  return -1;
500  }
501 
502  case CONNECTED:
503  {
504  Current ()->err = EISCONN;
505  return -1;
506  }
507  }
508 
509  std::string realPath = UtilsGetRealFilePath (std::string (((struct sockaddr_un*) my_addr)->sun_path));
510 
511  LocalSocketFd* l1 = m_factory->FindBinder (realPath, this->GetTypeId ());
512  LocalDatagramSocketFd *listener = dynamic_cast<LocalDatagramSocketFd*> (l1);
513 
514  if (0 != listener)
515  {
516  if (!listener->IsBinded ())
517  {
518  Current ()->err = ECONNREFUSED;
519  return -1;
520  }
521  m_state = CONNECTED;
522  m_connectPath = realPath;
523  m_peer = listener;
524 
525  listener->AddConnected (this);
526 
527  return 0;
528  }
529  else
530  {
531  current->err = ECONNREFUSED;
532  }
533 
534  return -1;
535 }
536 
537 int
539 {
540  NS_LOG_FUNCTION (this);
541  Current ()->err = EOPNOTSUPP;
542  return -1;
543 }
544 
545 int
547 {
548  NS_LOG_FUNCTION (this << how);
549  if (m_state == CLOSED)
550  {
551  Current ()->err = EPIPE;
552  return -1;
553  }
554  switch (how)
555  {
556  case SHUT_RD:
557  {
558  m_shutRead = true;
559  }
560  break;
561 
562  case SHUT_WR:
563  {
564 
565  m_shutWrite = true;
566  }
567  break;
568 
569  case SHUT_RDWR:
570  {
571  m_shutWrite = true;
572  m_shutRead = true;
573  }
574  break;
575  }
576  return 0;
577 }
578 
579 int
580 LocalDatagramSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
581 {
582  NS_LOG_FUNCTION (this);
583  Current ()->err = EOPNOTSUPP;
584  return -1;
585 }
586 
587 bool
589 {
590  switch (m_state)
591  {
592  case CLOSED:
593  return 1;
594  case CREATED:
595  return 1;
596 
597  case BINDED:
598  return m_readBufferSize > 0;
599 
600  case REMOTECLOSED:
601  case CONNECTED:
602  return 0;
603 
604  }
605  return 0;
606 }
607 
608 bool
610 {
612  || (CONNECTED != m_state);
613 }
614 
615 bool
617 {
618  NS_LOG_FUNCTION (this << " state:" << m_state);
619  return (REMOTECLOSED == m_state);
620 }
621 
622 ssize_t
623 LocalDatagramSocketFd::Recvmsg (struct msghdr *msg, int flags)
624 {
625  NS_LOG_FUNCTION (this);
626 
627  if (0 == msg)
628  {
629  Current ()->err = EINVAL;
630  return -1;
631  }
632 
633  if (CONNECTED == m_state)
634  {
635  Current ()->err = ENOTCONN;
636  return -1;
637  }
638 
639  size_t retval = 0;
640  for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
641  {
642  uint8_t *buf = (uint8_t *) msg->msg_iov[i].iov_base;
643  ssize_t len = msg->msg_iov[i].iov_len;
644  msg->msg_namelen = 0;
645 
646  ssize_t ret = Read (buf, len, (retval > 0) || (flags & MSG_DONTWAIT), (flags & MSG_PEEK));
647  NS_LOG_FUNCTION (this << "len:" << len << " read-> " << ret);
648  if (ret <= 0)
649  {
650  NS_LOG_FUNCTION (this << "4");
651 
652  break;
653  }
654  if (ret > 0)
655  {
656  retval += ret;
657  }
658  }
659 
660  if (retval > 0)
661  {
662  if ((!(flags & MSG_PEEK) && (m_readBufferSize > 0))
663  || ((flags & MSG_PEEK) && (m_readBufferSize > retval)))
664  {
665  msg->msg_flags |= MSG_TRUNC;
666  }
667  return retval;
668  }
669 
670  if (flags & MSG_DONTWAIT)
671  {
672  Current ()->err = EAGAIN;
673  }
674 
675  return -1;
676 }
677 
678 ssize_t
679 LocalDatagramSocketFd::Sendmsg (const struct msghdr *msg, int flags)
680 {
681  NS_LOG_FUNCTION (this << m_state);
682  LocalDatagramSocketFd* listener = 0;
683  LocalSocketFd* l1 = 0;
684  if (0 == msg)
685  {
686  Current ()->err = EINVAL;
687  return -1;
688  }
689 
690  if (CONNECTED == m_state)
691  {
692  listener = m_peer;
693  }
694  else if (CREATED == m_state)
695  {
696  if ((msg->msg_namelen < sizeof (struct sockaddr_un)) || (0 == msg->msg_name))
697  {
698  Current ()->err = EINVAL;
699  return -1;
700  }
701  struct sockaddr_un *addr = (struct sockaddr_un*) msg->msg_name;
702  // Seek peer
703 
704  std::string realPath = UtilsGetRealFilePath (std::string (addr->sun_path));
705 
706  // Do a write
707  l1 = m_factory->FindBinder (realPath, this->GetTypeId ());
708  listener = dynamic_cast<LocalDatagramSocketFd*> (l1);
709  }
710  else if (REMOTECLOSED == m_state)
711  {
712  Current ()->err = ECONNREFUSED;
713  return -1;
714  }
715  else
716  {
717  Current ()->err = ENOTCONN;
718  return -1;
719  }
720 
721  if (0 == listener)
722  {
723  Current ()->err = EACCES;
724  return -1;
725  }
726 
727  ssize_t retval = 0;
728  WaitQueueEntryTimeout *wq = 0;
729 
730  for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
731  {
732  uint8_t *buf = (uint8_t *) msg->msg_iov[i].iov_base;
733  ssize_t len = msg->msg_iov[i].iov_len;
734  size_t ret = 0;
735 
736  while (m_state < REMOTECLOSED)
737  {
738  ret = listener->DoRecvPacket (buf, len);
739 
740  switch (ret)
741  {
742  case 0: // NO ROOM
743  {
744  if (flags & MSG_DONTWAIT)
745  {
746  Current ()->err = EAGAIN;
747  RETURNFREE (-1);
748  }
749  if (!wq)
750  {
751  wq = new WaitQueueEntryTimeout (POLLOUT | POLLHUP, GetSendTimeout ());
752  }
753  AddWaitQueue (wq, true);
754  WaitPoint::Result res = wq->Wait ();
755  RemoveWaitQueue (wq, true);
756 
757  switch (res)
758  {
759  case WaitPoint::OK:
760  break;
762  {
763  UtilsDoSignal ();
764  Current ()->err = EINTR;
765  RETURNFREE (-1);
766  }
767  break;
768  case WaitPoint::TIMEOUT:
769  {
770  Current ()->err = EAGAIN;
771  RETURNFREE (-1);
772  }
773  break;
774  }
775 
776  if (m_state >= REMOTECLOSED)
777  {
778  Current ()->err = ECONNREFUSED;
779  RETURNFREE (-1);
780  }
781  continue;
782  }
783 
784  case - 1: // NOMEM !
785  RETURNFREE (-1);
786 
787  case - 2: // CLOSED !
788  {
789  Current ()->err = ECONNREFUSED;
790  RETURNFREE (-1);
791  }
792  }
793 
794  if (ret > 0)
795  {
796  retval += ret;
797  break;
798  }
799  }
800  }
801  RETURNFREE (retval);
802 }
803 
804 bool
806 {
807  return m_state == BINDED;
808 }
809 
810 ssize_t
811 LocalDatagramSocketFd::Write2Peer (const void *buf, size_t count, LocalDatagramSocketFd* peer)
812 {
813  NS_LOG_FUNCTION (this);
814 
815  // Verify peer state
816  if (0 == peer || !peer->IsBinded ())
817  {
818  Current ()->err = EPIPE;
819  return -1;
820  }
821 
822  ssize_t lg = m_peer->DoRecvPacket ((uint8_t*) buf, count);
823 
824  if (-2 == lg)
825  {
826  Current ()->err = EPIPE;
827  return -1;
828  }
829 
830  return lg;
831 }
832 
833 void
835 {
836  if ((m_bindPath.length () > 0) && (BINDED == m_state))
837  {
838  m_factory->UnRegisterBinder (m_bindPath);
839  m_bindPath = "";
840  m_state = CREATED;
841  }
842 }
843 
844 ssize_t
845 LocalDatagramSocketFd::Read (void *buf, size_t count)
846 {
847  return Read (buf, count, false, false);
848 }
849 bool
851 {
852  NS_LOG_FUNCTION (this << m_state);
853  return m_state >= REMOTECLOSED;
854 }
855 
856 void
858 {
859  NS_LOG_FUNCTION (this << m_state);
860  m_myPeers.insert (newone);
861 }
862 
863 void
865 {
866  NS_LOG_FUNCTION (this << m_state);
867  switch (m_state)
868  {
869  case BINDED:
870  {
871  m_myPeers.erase (freeOne);
872  if (andWakeUp)
873  {
874  int pi = POLLHUP;
875  WakeWaiters (&pi);
876  }
877  }
878  break;
879 
880  case CONNECTED:
881  {
882  m_peer = 0;
884  if (andWakeUp)
885  {
886  int pi = POLLHUP;
887  WakeWaiters (&pi);
888  }
889  }
890  break;
891  }
892 }
893 
894 void
896 {
897  m_state = CLOSED;
898  if (0 != m_peer)
899  {
900  LocalDatagramSocketFd* freeOne = m_peer;
901 
902  m_peer = 0;
903  freeOne->RemoveConnected (this, andWakeUp);
904  }
905  std::set<LocalDatagramSocketFd*> toFree = m_myPeers;
906 
907  m_myPeers.clear ();
908 
909  std::set<LocalDatagramSocketFd*>::iterator i;
910 
911  for (i = toFree.begin (); i != toFree.end (); ++i)
912  {
913  (*i)->RemoveConnected (this, andWakeUp);
914  }
915  toFree.clear ();
916 
917  if (m_bindPath.length () > 0)
918  {
919  m_factory->UnRegisterBinder (m_bindPath);
920  m_bindPath = "";
921  }
922 
923  ClearReadBuffer ();
924 
925  if (andWakeUp)
926  {
927  // WakeupRecv ();
928  int pi = POLLHUP;
929  WakeWaiters (&pi);
930  }
931 }
932 int
934 {
935  int ret = 0;
936 
937  if (CanRecv ())
938  {
939  ret |= POLLIN;
940  }
941  if (CanSend ())
942  {
943  ret |= POLLOUT;
944  }
945  if (HangupReceived ())
946  {
947  ret |= POLLHUP;
948  }
949 
950  if (ptable)
951  {
952  ptable->PollWait (this);
953  }
954 
955  return ret;
956 }
957 } // namespace ns3