VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gmsg.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gmsg.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gmsg.h"
23 #include "gprocess.h"
24 #include "gstr.h"
25 #include <cstring> // memcpy
26 #include <stdexcept>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/uio.h>
31 
32 ssize_t G::Msg::send( int fd , const void * buffer , size_t size , int flags ,
33  int fd_to_send )
34 {
35  return sendto( fd , buffer , size , flags , nullptr , 0 , fd_to_send ) ;
36 }
37 
38 ssize_t G::Msg::sendto( int fd , const void * buffer , size_t size , int flags ,
39  const sockaddr * address_p , socklen_t address_n , int fd_to_send )
40 {
41  static struct ::msghdr msg_zero ;
42  struct ::msghdr msg = msg_zero ;
43 
44  msg.msg_name = const_cast<sockaddr*>(address_p) ;
45  msg.msg_namelen = address_n ;
46 
47  static struct ::iovec io_zero ;
48  struct ::iovec io = io_zero ;
49  io.iov_base = const_cast<void*>(buffer) ;
50  io.iov_len = size ;
51  msg.msg_iov = &io ;
52  msg.msg_iovlen = 1 ;
53 
54  char control_buffer[CMSG_SPACE(sizeof(int))] ;
55  if( fd_to_send == -1 )
56  {
57  msg.msg_control = nullptr ;
58  msg.msg_controllen = 0U ;
59  }
60  else
61  {
62  std::memset( control_buffer , 0 , sizeof(control_buffer) ) ;
63  msg.msg_control = control_buffer ;
64  msg.msg_controllen = sizeof(control_buffer) ;
65 
66  struct ::cmsghdr * cmsg = CMSG_FIRSTHDR( &msg ) ;
67  cmsg->cmsg_len = CMSG_LEN( sizeof(int) ) ;
68  cmsg->cmsg_level = SOL_SOCKET ;
69  cmsg->cmsg_type = SCM_RIGHTS ;
70  std::memcpy( CMSG_DATA(cmsg) , &fd_to_send , sizeof(int) ) ;
71  }
72 
73  return ::sendmsg( fd , &msg , flags | MSG_NOSIGNAL ) ;
74 }
75 
76 ssize_t G::Msg::recv( int fd , void * buffer , size_t size , int flags ,
77  int * fd_received_p )
78 {
79  return recvfrom( fd , buffer , size , flags , nullptr , nullptr , fd_received_p ) ;
80 }
81 
82 ssize_t G::Msg::recvfrom( int fd , void * buffer , size_t size , int flags ,
83  sockaddr * address_p , socklen_t * address_np , int * fd_received_p )
84 {
85  static struct ::msghdr msg_zero ;
86  struct ::msghdr msg = msg_zero ;
87 
88  msg.msg_name = address_p ;
89  msg.msg_namelen = address_np == nullptr ? socklen_t(0) : *address_np ;
90 
91  struct ::iovec io ;
92  io.iov_base = buffer ;
93  io.iov_len = size ;
94  msg.msg_iov = &io ;
95  msg.msg_iovlen = 1 ;
96 
97  char control_buffer[CMSG_SPACE(sizeof(int))] ;
98  msg.msg_control = control_buffer ;
99  msg.msg_controllen = sizeof(control_buffer) ;
100 
101  ssize_t rc = ::recvmsg( fd , &msg , flags ) ;
102  int e = G::Process::errno_() ;
103  if( rc >= 0 && msg.msg_controllen > 0U && fd_received_p != nullptr )
104  {
105  struct cmsghdr * cmsg = CMSG_FIRSTHDR( &msg ) ;
106  if( cmsg != nullptr && cmsg->cmsg_type == SCM_RIGHTS )
107  {
108  std::memcpy( fd_received_p , CMSG_DATA(cmsg) , sizeof(int) ) ;
109  }
110  }
111  if( rc >= 0 && address_np != nullptr )
112  {
113  *address_np = msg.msg_namelen ;
114  }
115  G::Process::errno_( G::SignalSafe() , e ) ;
116  return rc ; // with errno
117 }
118 
119 bool G::Msg::fatal( int error )
120 {
121  return !(
122  error == 0 ||
123  error == EAGAIN ||
124  error == EINTR ||
125  error == EMSGSIZE || // moot
126  error == ENOBUFS ||
127  error == ENOMEM ||
128  false ) ;
129 }
130 
131 /// \file gmsg.cpp
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:36
static ssize_t send(int, const void *, size_t, int, int fd_to_send=-1)
A send() replacement using sendmsg().
Definition: gmsg.cpp:32
static ssize_t sendto(int, const void *, size_t, int, const sockaddr *, socklen_t, int fd_to_send=-1)
A sendto() replacement using sendmsg().
Definition: gmsg.cpp:38
static ssize_t recvfrom(int, void *, size_t, int, sockaddr *, socklen_t *, int *fd_received_p=nullptr)
A recvfrom() replacement using recvmsg().
Definition: gmsg.cpp:82
static ssize_t recv(int, void *, size_t, int, int *fd_received_p=nullptr)
A recv() replacement using recvmsg().
Definition: gmsg.cpp:76
static bool fatal(int error)
Returns true if the error value indicates a permanent problem with the socket.
Definition: gmsg.cpp:119