libutil++  1.9.3
 All Classes Functions Variables
Pipe.cpp
1 /*
2 ** libutil++
3 ** $Id: Pipe.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: Pipe.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "Pipe.h"
12 
13 #include <unistd.h>
14 #include <fcntl.h>
15 
16 using namespace sella::net;
17 
18 Pipe::Pipe(bool nonBlock) throw (SocketException) {
19  if (::pipe(fd) != 0) {
20  THROW2(SocketException, "pipe()");
21  }
22 
23  if (nonBlock) {
24  fcntl(fd[0], F_SETFL, O_NONBLOCK);
25  }
26 }
27 
28 Pipe::~Pipe() {
29  close(fd[0]);
30  close(fd[1]);
31 }
32 
33 ssize_t Pipe::write(const void *data, size_t len) throw (SocketException) {
34  ssize_t c, r = len;
35  int flg;
36 
37  do {
38  if ((c = ::write(fd[1], data, len)) < 0) {
39  switch (errno) {
40  case EINTR:
41  case EMSGSIZE:
42  case ENOBUFS:
43  break;
44 
45 #if ((EAGAIN) != (EWOULDBLOCK)) /* Same value in Linux, but both are checked for completeness. */
46  case EAGAIN:
47 #endif
48  case EWOULDBLOCK:
49  if ((flg = fcntl(fd[1], F_GETFL)) != -1 && (flg & O_NONBLOCK)) {
50  THROW_CODE(SocketException, EWOULDBLOCK, "Nonblocking socket would have blocked");
51  }
52 
53  THROW_CODE(SocketException, EWOULDBLOCK, "Send timed out");
54  }
55 
56  THROW2(SocketException, "write()");
57  } else if (c == 0) { /* Orderly socket shutdown detected */
58  break;
59  }
60  } while ((r -= c) > 0);
61 
62  return len;
63 }
64 
65 ssize_t Pipe::write(const std::string &data) throw (SocketException) {
66  return write((const void*) data.c_str(), data.size());
67 }
68 
69 ssize_t Pipe::write(const std::vector<uint8_t> &data) throw (SocketException) {
70  return write((const void*) data.data(), data.size());
71 }
72 
73 ssize_t Pipe::read(void *data, size_t len) throw (SocketException) {
74  ssize_t c;
75  int flg;
76 
77  if ((c = ::read(fd[0], data, len)) < 0) {
78  switch (errno) {
79  case EINTR:
80  break;
81 
82 #if ((EAGAIN) != (EWOULDBLOCK)) /* Same value in Linux, but both are checked for completeness. */
83  case EAGAIN:
84 #endif
85  case EWOULDBLOCK:
86  if ((flg = fcntl(fd[0], F_GETFL)) != -1 && (flg & O_NONBLOCK)) {
87  THROW_CODE(SocketException, EWOULDBLOCK, "Nonblocking socket would have blocked");
88  }
89 
90  THROW_CODE(SocketException, EWOULDBLOCK, "Receive timed out");
91  }
92 
93  THROW2(SocketException, "read()");
94  }
95 
96  return c;
97 }
98 
99 ssize_t Pipe::read(std::string &data, size_t len) throw (SocketException) {
100  uint8_t buf[len];
101  ssize_t size = read(buf, len);
102 
103  std::string(buf, buf + len).swap(data);
104 
105  return size;
106 }
107 
108 ssize_t Pipe::read(std::vector<uint8_t> &data, size_t len) throw (SocketException) {
109  uint8_t buf[len];
110  ssize_t size = read(buf, len);
111 
112  std::vector<uint8_t>(buf, buf + len).swap(data);
113 
114  return size;
115 }
116 
117 int Pipe::getWriteFD(void) {
118  return fd[1];
119 }
120 
121 int Pipe::getReadFD(void) {
122  return fd[0];
123 }
124 
125 const Pipe::shared Pipe::shared_ptr(bool nonBlock) throw (SocketException) {
126  return std::make_shared<Pipe>(nonBlock);
127 }
128 
129 /*
130 ** vim: noet ts=3 sw=3
131 */