hmbdc
simplify-high-performance-messaging-programming
SendSession.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 #include "hmbdc/app/Logger.hpp"
4 #include "hmbdc/tips/tcpcast/Transport.hpp"
5 #include "hmbdc/tips/tcpcast/Messages.hpp"
6 #include "hmbdc/tips/TypeTagSet.hpp"
7 
8 #include "hmbdc/time/Time.hpp"
9 #include "hmbdc/pattern/MonoLockFreeBuffer.hpp"
10 #include "hmbdc/comm/inet/Misc.hpp"
11 
12 #include <boost/lexical_cast.hpp>
13 #include <boost/circular_buffer.hpp>
14 
15 #include <random>
16 #include <memory>
17 #include <utility>
18 #include <iostream>
19 #include <fcntl.h>
20 
21 namespace hmbdc { namespace tips { namespace tcpcast {
22 
23 namespace sendserver_detail {
24 struct SendServer;
25 }
26 
27 using ToSend = std::vector<iovec>;
28 using ToSendQueue = boost::circular_buffer<std::tuple<uint16_t //TypeTag
29  , ToSend
30  , size_t //total bytes above
32  >
33 >;
34 
35 namespace sendsession_detail {
36 
37 struct SendSession {
38  using ptr = std::shared_ptr<SendSession>;
39  SendSession(int fd
40  , ToSendQueue & toSendQueue
41  , size_t maxSendBatch
42  , TypeTagSet& outboundSubscriptions)
43  : readLen_(0)
44  , ready_(false)
45  , toSendQueue_(toSendQueue)
46  , toSendQueueIndex_(0)
47  , msghdr_{0}
48  , msghdrRelic_{0}
49  , msghdrRelicSize_(0)
50  , outboundSubscriptions_(outboundSubscriptions) {
51  msghdrRelic_.msg_iov = new iovec[maxSendBatch * 2]; //double for attachment
52  auto addrPort = hmbdc::comm::inet::getPeerIpPort(fd);
53  id_ = addrPort.first + ":" + std::to_string(addrPort.second);
54  auto forRead = dup(fd);
55  if (forRead == -1) {
56  HMBDC_THROW(std::runtime_error, "dup failed errno=" << errno);
57  }
58 
59  readFd_.fd = forRead;
60  hmbdc::app::utils::EpollTask::instance().add(
61  hmbdc::app::utils::EpollTask::EPOLLIN
62  | hmbdc::app::utils::EpollTask::EPOLLET, readFd_);
63  writeFd_.fd = fd;
64  hmbdc::app::utils::EpollTask::instance().add(
65  hmbdc::app::utils::EpollTask::EPOLLOUT
66  | hmbdc::app::utils::EpollTask::EPOLLET, writeFd_);
67  HMBDC_LOG_N("SendSession started: ", id());
68  }
69 
70  ~SendSession() {
71  clientSubscriptions_.exportTo([this](uint16_t tag, auto&&) {
72  outboundSubscriptions_.sub(tag);
73  });
74  delete [] msghdrRelic_.msg_iov;
75  HMBDC_LOG_N("SendSession retired: ", id());
76  }
77 
78  bool runOnce() HMBDC_RESTRICT {
79  if (hmbdc_unlikely(!doRead())) return false;
80  if (hmbdc_unlikely(writeFd_.isFdReady() && msghdrRelicSize_)) {
81  auto l = sendmsg(writeFd_.fd, &msghdrRelic_, MSG_NOSIGNAL|MSG_DONTWAIT);
82  if (hmbdc_unlikely(l < 0)) {
83  if (!writeFd_.checkErr()) {
84  HMBDC_LOG_C("sendmsg failed errno=", errno);
85  return false;
86  }
87  return true;
88  }
89  msghdrRelicSize_ -= size_t(l);
90  if (hmbdc_unlikely(msghdrRelicSize_)) {
91  comm::inet::extractRelicTo(msghdrRelic_, msghdrRelic_, l);
92  return true;
93  } else {
94  toSendQueueIndex_++;
95  }
96  }
97  for (; !msghdrRelicSize_ && writeFd_.isFdReady()
98  && toSendQueueIndex_ != toSendQueue_.size();) {
99  if (clientSubscriptions_.check(std::get<0>(toSendQueue_[toSendQueueIndex_]))) {
100  msghdr_.msg_iov = &(std::get<1>(toSendQueue_[toSendQueueIndex_])[0]);
101  msghdr_.msg_iovlen = std::get<1>(toSendQueue_[toSendQueueIndex_]).size();
102  auto l = sendmsg(writeFd_.fd, &msghdr_, MSG_NOSIGNAL|MSG_DONTWAIT);
103  if (hmbdc_unlikely(l < 0)) {
104  if (!writeFd_.checkErr()) {
105  HMBDC_LOG_C("sendmsg failed errno=", errno);
106  return false;
107  }
108  return true;
109  }
110  msghdrRelicSize_ = std::get<2>(toSendQueue_[toSendQueueIndex_]) - size_t(l);
111  if (hmbdc_unlikely(msghdrRelicSize_)) {
112  comm::inet::extractRelicTo(msghdrRelic_, msghdr_, l);
113  return true;
114  }
115  }
116  toSendQueueIndex_++;
117  }
118  return true;
119  }
120 
121  char const* id() const {
122  return id_.c_str();
123  }
124 
125  bool ready() const {
126  return ready_;
127  }
128 
129 private:
130  bool
131  doRead() HMBDC_RESTRICT {
132  if (hmbdc_unlikely(readFd_.isFdReady())) {
133  auto l = recv(readFd_.fd, data_ + readLen_, sizeof(data_) - readLen_, MSG_NOSIGNAL|MSG_DONTWAIT);
134  if (hmbdc_unlikely(l < 0)) {
135  if (!readFd_.checkErr()) {
136  HMBDC_LOG_C("recv failed errno=", errno);
137  return false;
138  }
139  } else {
140  readLen_ += l;
141  }
142  };
143  while (readLen_) {
144  auto p = std::find(data_, data_ + readLen_, '\t');
145  if (p != data_ + readLen_) {
146  *p = '\000';
147  std::string t(data_ + 1);
148  if (t.size() == 0) {
149  ready_ = true;
150  } else if (data_[0] == '+') {
151  auto tag = (uint16_t)std::stoi(t);
152  if (clientSubscriptions_.set(tag)) {
153  outboundSubscriptions_.add(tag);
154  }
155  } else if (data_[0] == '-') {
156  auto tag = (uint16_t)std::stoi(t);
157  if (clientSubscriptions_.unset(tag)) {
158  outboundSubscriptions_.sub(tag);
159  }
160  } else {
161  HMBDC_LOG_C("voilating protocle by ", id_);
162  return false;
163  }
164  memmove(data_, p + 1, readLen_ - (p - data_ + 1));
165  readLen_ -= p - data_ + 1;
166  } else {
167  break; //no complete type tag request
168  }
169  }
170  return true;
171  }
172  app::utils::EpollFd writeFd_;
173  app::utils::EpollFd readFd_;
174  char data_[16 * 1024];
175  size_t readLen_;
176  std::string id_;
177  bool ready_;
178 
180  ToSendQueue& toSendQueue_;
181  ToSendQueue::size_type toSendQueueIndex_;
182  msghdr msghdr_;
183  msghdr msghdrRelic_;
184  size_t msghdrRelicSize_;
185 
186  TypeTagSet clientSubscriptions_;
187  TypeTagSet& outboundSubscriptions_;
188 };
189 } //sendsession_detail
190 
192 
193 }}}
Definition: EpollTask.hpp:87
Definition: TypeTagSet.hpp:138
Definition: Base.hpp:12
Definition: LockFreeBufferMisc.hpp:89