CARMA C++
netbuf.h
1 #ifndef netbuf_h
2 #define netbuf_h
3 
4 #include <stddef.h> /* size_t */
5 
6 /*
7  * This header describes an interface for sending and receiving messages
8  * over byte-oriented streams that are accessed via a file descriptor.
9  * It is intended to be used for communication between machines that may
10  * have different architectures. Messages are composed of a few primitive
11  * datatypes which are packed into network byte-order for transmission
12  * and unpacked back to host-byte order on receipt. Method functions for
13  * packing, unpacking, reading and writing messages are provided below.
14  */
15 
16 /*
17  * Each network message is preceded by a 32-bit byte-count and a
18  * 32-bit opcode. The byte-count includes both of these items.
19  * The following enumerates the length of the message prefix in bytes.
20  */
21 enum {NET_PREFIX_LEN = 8};
22 
23 /*
24  * List the packed sizes of each of the supported network data types.
25  */
26 typedef enum {
27  NET_CHAR_SIZE = 1,
28  NET_SHORT_SIZE = 2,
29  NET_LONG_SIZE = 4,
30  NET_FLOAT_SIZE = 4,
31  NET_DOUBLE_SIZE = 8,
32  NET_INT_SIZE = 4,
33 } NetTypeSize;
34 
35 namespace sza {
36  namespace array {
37  /*
38  * Declare an object type to encapsulate network messages in packed
39  * form. All members of this structure should be treated as private.
40  * An object of this type is encapsulated in both of the read and write
41  * stream structures described later.
42  */
43  typedef struct NetBuf {
44  unsigned char *buf; /* The network I/O buffer */
45  long size; /* The allocated size of buf[] */
46  long nget; /* The number of bytes extracted from the buffer */
47  long nput; /* The number of bytes added to the buffer */
48  int external; /* True if buf[] is an externally provided buffer */
49  } NetBuf;
50 
51  }
52 }
53 
54 /*
55  * The following functions are used to create and destroy a network
56  * buffer object. Note that this is performed for you by new_NetReadStr()
57  * and new_NetSendStr() [see below].
58  */
59 sza::array::NetBuf *new_NetBuf(long size); /* NetBuf constructor */
60 sza::array::NetBuf *del_NetBuf(sza::array::NetBuf *net); /* NetBuf desctructor */
61 
62 /*
63  * Return the size that was passed to new_NetBuf(). Note that this differs
64  * from net->size by NET_PREFIX_LEN.
65  */
66 long size_NetBuf(sza::array::NetBuf *net);
67 
68 /*
69  * NetBuf containers created with a buffer 'size' of zero must have
70  * an external buffer supplied before use.
71  */
72 void *net_set_buffer(sza::array::NetBuf *net, void *buf, size_t length);
73 /*
74  * When an external buffer is being used to format messages for
75  * output, net_inc_nput() can be used to increment the recorded length
76  * of the message to account for externally formatted data in the
77  * provided buffer. net_inc_nput() returns the buffer index of the
78  * next byte in the buffer. It can thus also be used to determine the
79  * buffer index of the current end-of-message by sending nbytes=0.
80  */
81 long net_inc_nput(sza::array::NetBuf *net, long nbytes);
82 
83 /*
84  * After reading a message into a NetBuf buffer, as described later,
85  * the following method functions should be used to unpack the
86  * primitive datatype components of the message. To extract a message
87  * first call net_start_get() to read the message header, then use the
88  * net_get_*() functions to sequentially unpack each component of the
89  * message body, then finally call net_end_get() to verify that all
90  * of the bytes in the message have been extracted.
91  */
92 int net_start_get(sza::array::NetBuf *net, int *opcode);
93 int net_end_get(sza::array::NetBuf *net);
94 int net_get_char(sza::array::NetBuf *net, long ndata, unsigned char *data);
95 int net_get_short(sza::array::NetBuf *net, long ndata, unsigned short *data);
96 int net_get_int(sza::array::NetBuf *net, int ndata, unsigned int *data);
97 int net_get_long(sza::array::NetBuf *net, long ndata, unsigned long *data);
98 int net_get_float(sza::array::NetBuf *net, long ndata, float *data);
99 int net_get_double(sza::array::NetBuf *net, long ndata, double *data);
100 int net_inc_nget(sza::array::NetBuf *net, long nbytes);
101 
102 /*
103  * The following method functions are used for packing
104  * primitive datatype components of a network message into a
105  * NetBuf buffer. To compose a new message first call
106  * net_start_put() to prepend the standard message prefix,
107  * then use the net_put_*() functions to pack one or more
108  * items into subsequent bytes of the message, then finally
109  * call net_end_put() to insert the final message byte-count
110  * at the start of the message. The message is then ready to
111  * be sent over a stream with nss_send_msg() as described below.
112  *
113  * Note that the opcode argument of net_start_put() is intended to be
114  * used by the application to enumerate the type of message being
115  * sent.
116  */
117 int net_start_put(sza::array::NetBuf *net, int opcode);
118 int net_end_put(sza::array::NetBuf *net);
119 int net_put_char(sza::array::NetBuf *net, long ndata, unsigned char *data);
120 int net_put_short(sza::array::NetBuf *net, long ndata, unsigned short *data);
121 int net_put_long(sza::array::NetBuf *net, long ndata, unsigned long *data);
122 int net_put_int(sza::array::NetBuf *net, long ndata, unsigned int *data);
123 int net_put_float(sza::array::NetBuf *net, long ndata, float *data);
124 int net_put_double(sza::array::NetBuf *net, long ndata, double *data);
125 
126 namespace sza {
127  namespace array {
128  /*
129  * Declare an object to encapsulate the process of reading messages
130  * from a network input stream.
131  */
132  typedef struct NetReadStr {
133  NetBuf *net; /* Network I/O buffer container */
134  long msglen; /* The target message length (bytes) */
135  int fd; /* A stream file-descriptor open for reading */
136  enum NetReadId { /* (Do not change the ordering below) */
137  NET_READ_SIZE, /* The message byte-count is being read */
138  NET_READ_DATA, /* The message body is being read */
139  NET_READ_DONE, /* The message has been completely read */
140  NET_READ_CLOSED, /* Closed connection detected at start of message */
141  NET_READ_ERROR /* I/O error detected while reading */
142  } state;
143  } NetReadStr;
144  }
145 }
146 
147 /*
148  * The following functions must be used to attach/detach to a given open,
149  * readable byte stream. Note that the file-descriptor can refer to
150  * a blocking or non-blocking stream. The 'size' argument specifies
151  * the maximum expected size of a network message.
152  */
153 sza::array::NetReadStr *new_NetReadStr(int fd, long size); /* NetReadStr constructor */
154 sza::array::NetReadStr *del_NetReadStr(sza::array::NetReadStr *nrs); /* NetReadStr destructor */
155 void attach_NetReadStr(sza::array::NetReadStr *nrs, int fd);/* Assign a new stream fd */
156 
157 /*
158  * A single message is read through one or more calls to
159  * nrs_read_stream(). If the file-descriptor is set up to use
160  * non-blocking I/O then this may require more than one call. When
161  * a complete message has been read, nrs_read_stream() will return
162  * NET_READ_DONE. The resulting message can be found in nrs->net,
163  * and can be decoded as described earlier, via calls to net_start_get(),
164  * net_get_*() and net_end_get(). Other nrs_read_msg() return values
165  * are listed above in the declaration of the 'state' member of the
166  * NetReadStr object.
167  */
168 int nrs_read_msg(sza::array::NetReadStr *nrs);
169 
170 namespace sza {
171  namespace array {
172  /*
173  * Declare an object to encapsulate the process of writing messages
174  * to a network output stream.
175  */
176  typedef struct NetSendStr {
177  NetBuf *net; /* Network I/O buffer container */
178  int fd; /* A stream file-descriptor open for writing */
179  enum NetSendId {
180  NET_SEND_DATA, /* Message is in the process of being written */
181  NET_SEND_DONE, /* Message has been completely sent */
182  NET_SEND_CLOSED, /* Closed connection detected */
183  NET_SEND_ERROR /* Write I/O error detected */
184  } state;
185  } NetSendStr;
186  }
187 }
188 
189 /*
190  * The following functions must be used to attach/detach to a given open,
191  * writable byte stream. Note that the file-descriptor can refer to
192  * a blocking or non-blocking stream. The 'size' argument specifies
193  * the maximum expected size of a network message.
194  */
195 sza::array::NetSendStr *new_NetSendStr(int fd, long size); /* NetSendStr constructor */
196 sza::array::NetSendStr *del_NetSendStr(sza::array::NetSendStr *nss); /* NetSendStr destructor */
197 void attach_NetSendStr(sza::array::NetSendStr *nss, int fd);/* Assign a new stream fd */
198 
199 /*
200  * Once a message has been completely composed in nss->net via calls
201  * to net_start_put(), net_put_*() and net_end_put(), it can be sent with
202  * one or more calls to nss_send_msg(). If the stream has been set up for
203  * non-blocking I/O then more than one call may be required. When the
204  * message has been completely sent, nss_send_msg() returns NET_SEND_DONE.
205  * Other return values are listed above in the declaration of the 'state'
206  * member of the NetSendStr object.
207  */
208 int nss_send_msg(sza::array::NetSendStr *nss);
209 
210 #endif