aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/io/ioOperations.h
blob: dee66030d1e8abf1e51c5b58b0e987292015ebe4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/*
 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Defines the interface all connections use to communicate with the forwarder.
 *
 * @code
 *
 *   static IoOperations _template = {
 *      .closure           = NULL,
 *      .send              = &_etherConnection_Send,
 *      .getRemoteAddress  = &_etherConnection_GetRemoteAddress,
 *      .getAddressPair    = &_etherConnection_GetAddressPair,
 *      .getConnectionId   = &_etherConnection_GetConnectionId,
 *      .isUp              = &_etherConnection_IsUp,
 *      .isLocal           = &_etherConnection_IsLocal,
 *      .destroy           = &_etherConnection_DestroyOperations,
 *      .class             = &_etherConnection_Class,
 *      .getConnectionType = &_etherConnection_getConnectionType
 *   };
 *
 *   IoOperations *
 *   etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
 * AddressPair *pair)
 *   {
 *      _EtherState *etherConnState = parcMemory_Allocate(sizeof(_EtherState));
 *      // Fill in etherConnState with instance variables
 *
 *      IoOperations *io_ops = parcMemory_Allocate(sizeof(IoOperations));
 *      memcpy(io_ops, &_template, sizeof(IoOperations));
 *      io_ops->closure = etherConnState;
 *      // Add to connection table, send missives about connection state
 *
 *      return op_ops;
 *   }
 * @endcode
 *
 */

/**
 * I/O is built around a callback structure.  The connection table contains an
 * operations structure built around function pointers.  These allow the
 * connection table to be agnostic about underlying connections.
 */

#ifndef io_h
#define io_h

#include <src/core/message.h>
#include <src/core/ticks.h>
#include <src/io/addressPair.h>
#include <src/utils/address.h>

// packet types for probing
#define PACKET_TYPE_PROBE_REQUEST 5
#define PACKET_TYPE_PROBE_REPLY 6

struct io_ops;
typedef struct io_ops IoOperations;

/**
 * @typedef IoOperations
 * @abstract The IO Operations structure abstracts an connection's properties
 * and send() method
 * @constant context Implementation specific opaque data, passed back on each
 * call
 * @constant send function pointer to send a message, does not destroy the
 * message
 * @constant getRemoteAddress function pointer to return the "to" address
 * associated with the connection. Some connections might not have a specific
 * peer, such as multicast, where its the group address.
 * @constant isUp test if the connection is up, ready to send a message.
 * @constant isLocal test if the connection is local to the host.
 * @constant getConnectionId returns the hicn-light id for the connection.
 * @constant destroy releases a refernce count on the connection and possibly
 * destroys the connection.
 * @constant class A unique identifier for each class that instantiates
 * IoOperations.
 * @constant getConnectionType Returns the type of connection (TCP, UDP, L2,
 * etc.) of the underlying connection.
 * @discussion <#Discussion#>
 */
struct io_ops {
  void *closure;
  bool (*send)(IoOperations *ops, const Address *nexthop, Message *message);
  const Address *(*getRemoteAddress)(const IoOperations *ops);
  const AddressPair *(*getAddressPair)(const IoOperations *ops);
  bool (*isUp)(const IoOperations *ops);
  bool (*isLocal)(const IoOperations *ops);
  unsigned (*getConnectionId)(const IoOperations *ops);
  void (*destroy)(IoOperations **opsPtr);
  const void *(*class)(const IoOperations *ops);
  list_connections_type (*getConnectionType)(const IoOperations *ops);
  Ticks (*sendProbe)(IoOperations *ops, unsigned probeType, uint8_t *message);
};

/**
 * Returns the closure of the interface
 *
 * The creator of the closure sets this parameter to store its state.
 *
 * @param [in] ops A concrete instance of the interface
 *
 * @return The value set by the concrete instance of the interface.
 *
 * Example:
 * @clode
 * {

 * }
 * @endcode
 */
void *ioOperations_GetClosure(const IoOperations *ops);

/**
 * Release all memory related to the interface and implementation
 *
 * This function must release all referenced memory in the concrete
 * implementation and memory related to the IoOperations.  It should NULL the
 * input parameter.
 *
 * @param [in,out] opsPtr Pointer to interface.  Will be NULLed.
 *
 * Example:
 * @code
 *
 *   static void
 *   _etherConnection_InternalRelease(_EtherState *etherConnState)
 *   {
 *      // release internal state of _EtherState
 *   }
 *
 *   static void
 *   _etherConnection_Release(IoOperations **opsPtr)
 *   {
 *      IoOperations *ops = *opsPtr;
 *
 *      _EtherState *etherConnState = (_EtherState *)
 * ioOperations_GetClosure(ops);
 *      _etherConnection_InternalRelease(etherConnState);
 *
 *      parcMemory_Deallocate((void **) &ops);
 *   }
 *
 *   IoOperations *
 *   etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
 * AddressPair *pair)
 *   {
 *      size_t allocationSize = sizeof(_EtherState) + sizeof(IoOperations);
 *      IoOperations *ops = parcMemory_AllocateAndClear(allocationSize);
 *      if (ops) {
 *         // fill in other interface functions
 *         ops->destroy = &_etherConnection_Release;
 *         ops->closure = (uint8_t *) ops + sizeof(IoOperations);
 *
 *         _EtherState *etherConnState = ioOperations_GetClosure(ops);
 *         // fill in Ethernet state
 *      }
 *      return ops;
 *   }
 * @endcode
 */
void ioOperations_Release(IoOperations **opsPtr);

/**
 * Sends the specified Message out this connection
 *
 * The the implementation of send may queue the message, it must acquire a
 * reference to it.
 *
 * @param [in] ops The connection implementation.
 * @param [in] nexthop On multiple access networks, this parameter might be
 * used, usually NULL.
 * @param [in] message The message to send.  If the message will be queued, it
 * will be acquired.
 *
 * @return true The message was sent or queued
 * @retrun false An error occured and the message will not be sent or queued
 *
 * Example:
 * @code
 * {
 *     if (ioOperations_IsUp(conn->ops)) {
 *        return ioOperations_Send(conn->ops, NULL, message);
 *     }
 * }
 * @endcode
 */
bool ioOperations_Send(IoOperations *ops, const Address *nexthop,
                       Message *message);

/**
 * A connection is made up of a local and a remote address.  This function
 * returns the remote address.
 *
 * Represents the destination endpoint of the communication.
 *
 * @param [in] ops The connection implementation.
 *
 * @return non-null The remote address
 * @return null The connection does not have a remote address
 *
 * Example:
 * @code
 * {
 *    Address *local =  addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
 * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
 * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
 * addressPair_Create(local, remote); IoOperations *ops =
 * etherConnection_Create(forwarder, ether, pair);
 *
 *    const Address *test = ioOperations_GetRemoteAddress(ops);
 *    parcAssertTrue(addressEquals(test, remote), "Wrong remote address");
 *    ioOperations_Release(&ops);
 *    addressPair_Release(&pair);
 *    addressDestroy(&local);
 *    addressDestroy(&remote);
 * }
 * @endcode
 */
const Address *ioOperations_GetRemoteAddress(const IoOperations *ops);

/**
 * A connection is made up of a local and a remote address.  This function
 * returns the address pair.
 *
 * Represents the destination endpoint of the communication.
 *
 * @param [in] ops The connection implementation.
 *
 * @return non-null The address pair
 * @return null An error.
 *
 * Example:
 * @code
 * {
 *    Address *local =  addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
 * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
 * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
 * addressPair_Create(local, remote); IoOperations *ops =
 * etherConnection_Create(forwarder, ether, pair);
 *
 *    const AddressPair *test = ioOperations_GetAddressPair(ops);
 *    parcAssertTrue(addressPair(test, pair), "Wrong address pair");
 *    ioOperations_Release(&ops);
 *    addressPair_Release(&pair);
 *    addressDestroy(&local);
 *    addressDestroy(&remote);
 * }
 * @endcode
 */
const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops);

/**
 * Returns true if the underlying connection is in operation
 *
 * An UP connection is able to send and receive packets. If a subsystem needs to
 * take actions when a connection goes UP or DOWN, it should subscribe as a
 * Missive listener.
 *
 * @param [in] ops The connection implementation.
 *
 * @return true The connection is UP
 * @return false The connection is not UP
 *
 * Example:
 * @code
 * {
 *     if (ioOperations_IsUp(conn->ops)) {
 *        return ioOperations_Send(conn->ops, NULL, message);
 *     }
 * }
 * @endcode
 */
bool ioOperations_IsUp(const IoOperations *ops);

/**
 * If the remote address is local to this system, returns true
 *
 * Will return true if an INET or INET6 connection is on localhost.  Will return
 * true for AF_UNIX.  An Ethernet connection is not local.
 *
 * @param [in] ops The connection implementation.
 *
 * @return true The remote address is local to the system
 * @return false The remote address is not local
 *
 * Example:
 * @code
 * {
 *     // Is the ingress connection remote?  If so check for non-zero and
 * decrement if (!ioOperations(ingressConnectionOps) { uint8_t hoplimit =
 * message_GetHopLimit(interestMessage); if (hoplimit == 0) {
 *           // error
 *        } else {
 *           hoplimit--;
 *        }
 *        // take actions on hoplimit
 *     }
 * }
 * @endcode
 */
bool ioOperations_IsLocal(const IoOperations *ops);

/**
 * Returns the connection ID represented by this IoOperations in the
 * ConnectionTable.
 *
 * <#Paragraphs Of Explanation#>
 *
 * @param [in] ops The connection implementation.
 *
 * @return number The connection ID in the connection table.
 *
 * Example:
 * @code
 * {
 *     unsigned id = ioOperations_GetConnectionId(ingressIoOps);
 *     const Connection *conn =
 * connectionTable_FindById(forwarder->connectionTable, id);
 * }
 * @endcode
 */
unsigned ioOperations_GetConnectionId(const IoOperations *ops);

/**
 * A pointer that represents the class of the connection
 *
 * Each concrete implementation has a class pointer that is unique to the
 * implementation (not instance). Each implementation is free to choose how to
 * determine the value, so long as it is unique on the system. This is a
 * system-local value.
 *
 * @param [in] ops The connection implementation.
 *
 * @return non-null A pointer value unique to the implementation (not instance).
 *
 * Example:
 * @code
 *   bool
 *   etherConnection_IsInstanceOf(const Connection *conn)
 *   {
 *      bool result = false;
 *      if (conn != NULL) {
 *         IoOperations *ops = connection_GetIoOperations(conn);
 *         const void *class = ioOperations_Class(ops);
 *         result = (class == _etherConnection_Class(ops));
 *      }
 *      return result;
 *   }
 * @endcode
 */
const void *ioOperations_Class(const IoOperations *ops);

/**
 * Returns the transport type of the connection (TCP, UDP, L2, etc.).
 *
 * TCP and AF_UNIX are both stream connections and will both return
 * "Connection_TCP". Ethernet will return "Connection_L2".
 *
 * @param [in] ops The connection implementation.
 *
 * @return Connection_TCP A TCP4, TCP6, or AF_UNIX connection
 * @return Connection_UDP A UDP4 or UDP6 connection
 * @return Connection_L2 An Ethernet connection
 *
 * Example:
 * @code
 * {
 *     ConnectionType type =
 * ioOperations_GetConnectionType(connection_GetIoOperations(connection));
 *     Connection *Conn =
 * Connection_Create(connection_GetConnectionId(connection), localAddress,
 * remoteAddress, type);
 * }
 * @endcode
 */
list_connections_type ioOperations_GetConnectionType(const IoOperations *ops);

Ticks ioOperations_SendProbe(IoOperations *ops, unsigned probeType,
                             uint8_t *message);
#endif  // io_h