esp8266ndn
NDN Arduino library for ESP8266 and more
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
memif.hpp
Go to the documentation of this file.
1#ifndef NDNPH_PORT_TRANSPORT_MEMIF_HPP
2#define NDNPH_PORT_TRANSPORT_MEMIF_HPP
3
4#include "../../face/transport-rxqueue.hpp"
5extern "C" {
6#include <libmemif.h>
7}
8
9#ifndef NDNPH_MEMIF_RXBURST
11#define NDNPH_MEMIF_RXBURST 64
12#endif
13
14namespace ndnph {
15namespace port_transport_memif {
16
17#ifdef NDNPH_MEMIF_DEBUG
18#define NDNPH_MEMIF_PRINT_ERR(func) \
19 do { \
20 fprintf(stderr, "MemifTransport " #func " %d %s\n", err, memif_strerror(err)); \
21 } while (false)
22#else
23#define NDNPH_MEMIF_PRINT_ERR(func) \
24 do { \
25 (void)err; \
26 } while (false)
27#endif
28
35class MemifTransport : public virtual Transport {
36public:
37 enum class Role {
38 CLIENT = 0,
39 SERVER = 1,
40 };
41
42 using DefaultDataroom = std::integral_constant<uint16_t, 2048>;
43
44 struct Options {
46 const char* socketName;
47 uint32_t id;
48 uint16_t dataroom;
49 uint16_t ringCapacity;
50 };
51
58 bool begin(const char* socketName, uint32_t id, uint16_t dataroom = 0) {
59 Options opts{};
60 opts.socketName = socketName;
61 opts.id = id;
62 opts.dataroom = dataroom;
63 return begin(opts);
64 }
65
67 bool begin(Options opts) {
68 end();
69 if (opts.socketName == nullptr || opts.dataroom > 0x8000) {
70 return false;
71 }
72 if (opts.dataroom == 0) {
73 opts.dataroom = 2048;
74 }
75 if (opts.ringCapacity == 0) {
76 opts.ringCapacity = 1024;
77 }
78
79 memif_socket_args_t sa{};
80 strncpy(sa.path, opts.socketName, sizeof(sa.path));
81 strncpy(sa.app_name, "NDNph", sizeof(sa.app_name));
82 int err = memif_create_socket(&m_sock, &sa, this);
83 if (err != MEMIF_ERR_SUCCESS) {
84 NDNPH_MEMIF_PRINT_ERR(memif_create_socket);
85 return false;
86 }
87
88 memif_conn_args_t ca{};
89 ca.is_master = static_cast<uint8_t>(opts.role == Role::SERVER);
90 ca.socket = m_sock;
91 ca.interface_id = opts.id;
92 for (ca.buffer_size = 64; ca.buffer_size < opts.dataroom;) {
93 ca.buffer_size <<= 1;
94 // libmemif internally assumes buffer_size to be power of two
95 // https://github.com/FDio/vpp/blob/v22.02/extras/libmemif/src/main.c#L1538
96 }
97 m_dataroom = ca.buffer_size;
98 for (ca.log2_ring_size = 4;
99 ca.log2_ring_size < 14 && (1 << ca.log2_ring_size) < opts.ringCapacity;) {
100 ++ca.log2_ring_size;
101 }
102 err = memif_create(&m_conn, &ca, MemifTransport::handleConnect,
103 MemifTransport::handleDisconnect, MemifTransport::handleInterrupt, this);
104 if (err != MEMIF_ERR_SUCCESS) {
105 NDNPH_MEMIF_PRINT_ERR(memif_create);
106 return false;
107 }
108
109 return true;
110 }
111
113 bool end() {
114 if (m_conn != nullptr) {
115 int err = memif_delete(&m_conn);
116 if (err != MEMIF_ERR_SUCCESS) {
117 NDNPH_MEMIF_PRINT_ERR(memif_delete);
118 return false;
119 }
120 }
121
122 if (m_sock != nullptr) {
123 int err = memif_delete_socket(&m_sock);
124 if (err != MEMIF_ERR_SUCCESS) {
125 NDNPH_MEMIF_PRINT_ERR(memif_delete_socket);
126 return false;
127 }
128 }
129
130 m_dataroom = 0;
131 return true;
132 }
133
135 uint16_t getDataroom() const {
136 return m_dataroom;
137 }
138
139private:
140 bool doIsUp() const final {
141 return m_isUp;
142 }
143
144 void doLoop() final {
145 if (m_sock == nullptr) {
146 return;
147 }
148
149 int err = memif_poll_event(m_sock, 0);
150 if (err != MEMIF_ERR_SUCCESS) {
151 NDNPH_MEMIF_PRINT_ERR(memif_poll_event);
152 }
153 }
154
155 bool doSend(const uint8_t* pkt, size_t pktLen, uint64_t) final {
156 if (!m_isUp) {
157#ifdef NDNPH_MEMIF_DEBUG
158 fprintf(stderr, "MemifTransport send drop=transport-disconnected\n");
159#endif
160 return false;
161 }
162
163 if (pktLen > m_dataroom) {
164#ifdef NDNPH_MEMIF_DEBUG
165 fprintf(stderr, "MemifTransport send drop=pkt-too-long len=%zu\n", pktLen);
166#endif
167 return false;
168 }
169
170 memif_buffer_t b{};
171 uint16_t nAlloc = 0;
172 int err = memif_buffer_alloc(m_conn, 0, &b, 1, &nAlloc, pktLen);
173 if (err != MEMIF_ERR_SUCCESS || nAlloc != 1) {
174 NDNPH_MEMIF_PRINT_ERR(memif_buffer_alloc);
175 return false;
176 }
177
178 NDNPH_ASSERT(b.len >= pktLen);
179 NDNPH_ASSERT((b.flags & MEMIF_BUFFER_FLAG_NEXT) == 0);
180 std::copy_n(pkt, pktLen, static_cast<uint8_t*>(b.data));
181 b.len = pktLen;
182
183 uint16_t nTx = 0;
184 err = memif_tx_burst(m_conn, 0, &b, 1, &nTx);
185 if (err != MEMIF_ERR_SUCCESS || nTx != 1) {
186 NDNPH_MEMIF_PRINT_ERR(memif_tx_burst);
187 return false;
188 }
189 return true;
190 }
191
192 static int handleConnect(memif_conn_handle_t conn, void* self0) {
193 MemifTransport* self = reinterpret_cast<MemifTransport*>(self0);
194 NDNPH_ASSERT(self->m_conn == conn);
195 self->m_isUp = true;
196#ifdef NDNPH_MEMIF_DEBUG
197 fprintf(stderr, "MemifTransport connected\n");
198#endif
199
200 int err = memif_refill_queue(conn, 0, -1, 0);
201 if (err != MEMIF_ERR_SUCCESS) {
202 NDNPH_MEMIF_PRINT_ERR(memif_refill_queue);
203 }
204 return 0;
205 }
206
207 static int handleDisconnect(memif_conn_handle_t conn, void* self0) {
208 MemifTransport* self = reinterpret_cast<MemifTransport*>(self0);
209 NDNPH_ASSERT(self->m_conn == conn);
210 self->m_isUp = false;
211#ifdef NDNPH_MEMIF_DEBUG
212 fprintf(stderr, "MemifTransport disconnected\n");
213#endif
214 return 0;
215 }
216
217 static int handleInterrupt(memif_conn_handle_t conn, void* self0, uint16_t qid) {
218 MemifTransport* self = reinterpret_cast<MemifTransport*>(self0);
219 NDNPH_ASSERT(self->m_conn == conn);
220
221 std::array<memif_buffer_t, NDNPH_MEMIF_RXBURST> burst{};
222 uint16_t nRx = 0;
223 int err = memif_rx_burst(conn, qid, burst.data(), burst.size(), &nRx);
224 if (err != MEMIF_ERR_SUCCESS) {
225 NDNPH_MEMIF_PRINT_ERR(memif_rx_burst);
226 return 0;
227 }
228
229 for (uint16_t i = 0; i < nRx; ++i) {
230 const memif_buffer_t& b = burst[i];
231 self->invokeRxCallback(static_cast<const uint8_t*>(b.data), b.len);
232 }
233
234 err = memif_refill_queue(conn, qid, nRx, 0);
235 if (err != MEMIF_ERR_SUCCESS) {
236 NDNPH_MEMIF_PRINT_ERR(memif_rx_burst);
237 }
238 return 0;
239 }
240
241private:
242 memif_socket_handle_t m_sock = nullptr;
243 memif_conn_handle_t m_conn = nullptr;
244 uint16_t m_dataroom = 0;
245 bool m_isUp = false;
246};
247
248#undef NDNPH_MEMIF_PRINT_ERR
249
250} // namespace port_transport_memif
251
253
254} // namespace ndnph
255
256#endif // NDNPH_PORT_TRANSPORT_MEMIF_HPP
A transport that communicates via libmemif.
Definition memif.hpp:35
uint16_t getDataroom() const
Return actual dataroom.
Definition memif.hpp:135
void doLoop() final
Definition memif.hpp:144
bool begin(Options opts)
Start transport with advanced options.
Definition memif.hpp:67
bool doIsUp() const final
Definition memif.hpp:140
bool doSend(const uint8_t *pkt, size_t pktLen, uint64_t) final
Definition memif.hpp:155
bool end()
Stop transport.
Definition memif.hpp:113
std::integral_constant< uint16_t, 2048 > DefaultDataroom
Definition memif.hpp:42
bool begin(const char *socketName, uint32_t id, uint16_t dataroom=0)
Start transport.
Definition memif.hpp:58
Base class of low-level transport.
Definition transport.hpp:10
#define NDNPH_ASSERT(x)
Definition common.hpp:30
#define NDNPH_MEMIF_PRINT_ERR(func)
Definition memif.hpp:23
Definition fs.hpp:33
port_transport_memif::MemifTransport MemifTransport
Definition memif.hpp:252
uint16_t ringCapacity
Definition memif.hpp:49
const char * socketName
Definition memif.hpp:46