protomsg 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -6
- data/lib/templates/io.h +21 -12
- data/lib/templates/lengths.h +2 -1
- data/lib/templates/memory.h +5 -0
- data/lib/templates/protomsg.h +32 -19
- data/lib/templates/setters/string_setter.h +1 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= protomsg
|
2
2
|
|
3
|
-
Protocol Message Buffers for C. This gem generates C socket code for reading and writing messages described in the protomsg DSL.
|
3
|
+
Protocol Message Buffers for C. This gem generates C socket code for reading and writing messages described in the protomsg DSL. The code is highly optimised and often similar to what you would write by hand manually.
|
4
4
|
|
5
5
|
== Overview
|
6
6
|
Input for a 'request' message:
|
@@ -34,7 +34,7 @@ Output is a header file of macros for reading, writing and manipulating request
|
|
34
34
|
write_request
|
35
35
|
read_request
|
36
36
|
|
37
|
-
The macros generate highly optimised
|
37
|
+
The macros generate highly optimised copy free socket code (using scatter/gather IO functions), and automatically check message sanity and handle incomplete reads and writes. The generated code is often very similar to what you would write by hand, and in some cases is even faster.
|
38
38
|
|
39
39
|
== Usage
|
40
40
|
Call the protomsg script with the message types input file.
|
@@ -58,7 +58,7 @@ All message type and attribute names must be valid C identifiers. Valid attribut
|
|
58
58
|
raw Raw bytes
|
59
59
|
|
60
60
|
== Example
|
61
|
-
Once you have defined your message types, sending and receiving messages is easy. For example, given the following message type:
|
61
|
+
Once you have defined your message types, sending and receiving messages is easy. For example, given the following message type definitions:
|
62
62
|
|
63
63
|
# ping_message.protomsg
|
64
64
|
ping {
|
@@ -113,7 +113,7 @@ And the corresponding server could be:
|
|
113
113
|
|
114
114
|
// start a server and wait for a ping message
|
115
115
|
create_server_socket(9000, 1, server, error);
|
116
|
-
accept_client(server, client);
|
116
|
+
accept_client(server, client, error);
|
117
117
|
read_ping(p, client, error);
|
118
118
|
printf("Received ping: %llu, %s\n", get_ping_number(p), get_ping_message(p));
|
119
119
|
|
@@ -123,7 +123,7 @@ And the corresponding server could be:
|
|
123
123
|
write_response(r, client, error);
|
124
124
|
}
|
125
125
|
|
126
|
-
It's not necessary to use the included socket helper macros - you can use
|
126
|
+
It's not necessary to use the included socket helper macros - you can use proto messages over any socket - but for simple client/server applications like this they help reduce the amount of code required to get something running quickly.
|
127
127
|
|
128
128
|
== Known Issues
|
129
|
-
All clients are servers are assumed to be on machines of the same endianess.
|
129
|
+
All clients are servers are assumed to be on machines of the same endianess. The simple socket creation macros can't create IP6 sockets as yet. Writev is used to send messages; an error is currently raised when an incomplete write completes, rather than restart the write where it was left off.
|
data/lib/templates/io.h
CHANGED
@@ -1,23 +1,32 @@
|
|
1
1
|
#define write_<%= @name %>(msg, sock, error) {\
|
2
2
|
error = 0;\
|
3
|
-
ssize_t
|
4
|
-
if(
|
3
|
+
ssize_t _written = writev(sock, (const struct iovec *)msg, <%= variable_attributes.size + 1 %>);\
|
4
|
+
if(_written != <%= @name %>_length(msg)){\
|
5
5
|
error = errno;\
|
6
6
|
}\
|
7
7
|
}
|
8
8
|
|
9
9
|
#define read_<%= @name %>(msg, sock, error) {\
|
10
|
-
|
11
|
-
msg
|
12
|
-
|
13
|
-
|
10
|
+
error = 0;\
|
11
|
+
if(!msg) {\
|
12
|
+
msg = (<%= @name %> *) malloc(sizeof(<%= @name %>));\
|
13
|
+
msg->header_length = sizeof(<%= @name %>_header);\
|
14
|
+
msg->header = (<%= @name %>_header *)malloc(sizeof(<%= @name %>_header));\
|
15
|
+
}\
|
16
|
+
safe_read(sock, msg->header, sizeof(<%= @name %>_header), error);\
|
14
17
|
if(!error) {\
|
15
|
-
if(msg->header->_version
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
} else {
|
20
|
-
|
18
|
+
if(msg->header->_version != PROTO_MESSAGE_VERSION) {\
|
19
|
+
error = INVALID_PROTOMSG_VERSION;\
|
20
|
+
} else if(msg->header->_type != <%= @name.upcase %>_MESSAGE_TYPE) {\
|
21
|
+
error = INVALID_MESSAGE_TYPE;\
|
22
|
+
} else {\<% if variable_attributes.size > 0 %>
|
23
|
+
if(msg-><%= variable_attributes.first.name %>)\
|
24
|
+
free(msg-><%= variable_attributes.first.name %>);\
|
25
|
+
msg-><%= variable_attributes.first.name %> = malloc(<%= @name %>_variable_length(msg));\
|
26
|
+
<% variable_attributes.each_with_index do |attr, index| %>msg-><%= attr.name %>_length = msg->header-><%= attr.name %>_length;\<% if index > 0 %>
|
27
|
+
msg-><%= attr.name %> = msg-><%= variable_attributes.first.name %> + <%= variable_attributes[0..index-1].collect {|attr| "msg->header->#{attr.name}_length" }.join(" + ") %>;\<% end %>
|
28
|
+
<% end %>safe_read(sock, msg-><%= variable_attributes.first.name %>, <%= @name %>_variable_length(msg), error);\<% else %>
|
29
|
+
;\<% end %>
|
21
30
|
}\
|
22
31
|
}\
|
23
32
|
}
|
data/lib/templates/lengths.h
CHANGED
@@ -1,2 +1,3 @@
|
|
1
1
|
<% variable_attributes.each do |attr| %>#define <%= @name %>_<%= attr.name %>_length(msg) (msg-><%= attr.name %>_length)
|
2
|
-
<% end %>#define <%= @name %>_length(msg) (msg->header_length <%= variable_attributes.size > 0 ? ("+ " + variable_attributes.collect {|attr| "msg->#{attr.name}_length"}.join(" + ")) : '' %>)
|
2
|
+
<% end %>#define <%= @name %>_length(msg) (msg->header_length <%= variable_attributes.size > 0 ? ("+ " + variable_attributes.collect {|attr| "msg->#{attr.name}_length"}.join(" + ")) : '' %>)<% if variable_attributes.size > 0 %>
|
3
|
+
#define <%= @name %>_variable_length(msg) (<%= variable_attributes.collect {|attr| "msg->#{attr.name}_length"}.join(" + ")%>)<% end %>
|
data/lib/templates/memory.h
CHANGED
data/lib/templates/protomsg.h
CHANGED
@@ -8,14 +8,15 @@
|
|
8
8
|
#ifndef __protomsg__
|
9
9
|
#define __protomsg__
|
10
10
|
|
11
|
-
#define PROTO_MESSAGE_VERSION
|
12
|
-
#define
|
11
|
+
#define PROTO_MESSAGE_VERSION 1
|
12
|
+
#define INVALID_PROTOMSG_VERSION 1
|
13
|
+
#define INVALID_MESSAGE_TYPE 2
|
13
14
|
|
14
|
-
#define
|
15
|
+
#define safe_read(sock, buffer, size, error) {\
|
15
16
|
error = 0;\
|
16
17
|
ssize_t _bytes_read = 0, _bytes_total = 0;\
|
17
18
|
while(_bytes_total < size) {\
|
18
|
-
_bytes_read = read(sock,
|
19
|
+
_bytes_read = read(sock, buffer + _bytes_total, size - _bytes_total);\
|
19
20
|
if(_bytes_read != -1) {\
|
20
21
|
_bytes_total += _bytes_read;\
|
21
22
|
} else {\
|
@@ -28,35 +29,47 @@
|
|
28
29
|
#define create_server_socket(port, queue, sock, error) {\
|
29
30
|
error = 0;\
|
30
31
|
sock = socket(AF_INET, SOCK_STREAM, 0);\
|
31
|
-
|
32
|
-
memset(&_servaddr, 0, sizeof(_servaddr));\
|
33
|
-
_servaddr.sin_family = AF_INET;\
|
34
|
-
_servaddr.sin_addr.s_addr = htonl(INADDR_ANY);\
|
35
|
-
_servaddr.sin_port = htons(port);\
|
36
|
-
error = bind(sock, (const struct sockaddr *)&_servaddr, sizeof(_servaddr));\
|
37
|
-
if(error) {\
|
32
|
+
if(sock == -1) {\
|
38
33
|
error = errno;\
|
39
34
|
} else {\
|
40
|
-
|
35
|
+
struct sockaddr_in _servaddr;\
|
36
|
+
memset(&_servaddr, 0, sizeof(_servaddr));\
|
37
|
+
_servaddr.sin_family = AF_INET;\
|
38
|
+
_servaddr.sin_addr.s_addr = htonl(INADDR_ANY);\
|
39
|
+
_servaddr.sin_port = htons(port);\
|
40
|
+
error = bind(sock, (const struct sockaddr *)&_servaddr, sizeof(_servaddr));\
|
41
41
|
if(error) {\
|
42
42
|
error = errno;\
|
43
|
+
} else {\
|
44
|
+
error = listen(sock, queue);\
|
45
|
+
if(error) {\
|
46
|
+
error = errno;\
|
47
|
+
}\
|
43
48
|
}\
|
44
49
|
}\
|
45
50
|
}
|
46
51
|
|
47
|
-
#define accept_client(sock, client) {\
|
52
|
+
#define accept_client(sock, client, error) {\
|
48
53
|
client = accept(sock, NULL, NULL);\
|
54
|
+
if(client == -1)\
|
55
|
+
error = errno;\
|
49
56
|
}
|
50
57
|
|
51
58
|
#define connect_to_server(address, port, sock, error) {\
|
52
59
|
error = 0;\
|
53
60
|
sock = socket(AF_INET, SOCK_STREAM, 0);\
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
61
|
+
if(sock == -1) {\
|
62
|
+
error = errno;\
|
63
|
+
} else {\
|
64
|
+
struct sockaddr _servaddr;\
|
65
|
+
socklen_t _servaddr_length;\
|
66
|
+
get_socket_addr_from_hostname(address, _servaddr, _servaddr_length, error);\
|
67
|
+
if(!error) {\
|
68
|
+
((struct sockaddr_in *) &_servaddr)->sin_port = htons(port);\
|
69
|
+
if(connect(sock, (struct sockaddr *) &_servaddr, sizeof(_servaddr))) {\
|
70
|
+
error = errno;\
|
71
|
+
}\
|
72
|
+
}\
|
60
73
|
}\
|
61
74
|
}
|
62
75
|
|
@@ -1,4 +1,4 @@
|
|
1
1
|
#define set_<%= @message_type.name %>_<%= @name %>(msg, val) {\
|
2
2
|
msg-><%= @name %> = val;\
|
3
|
-
msg-><%= @name %>_length = msg->header-><%= @name %>_length = (val) ? (strlen(val) + 1) : 0;\
|
3
|
+
msg-><%= @name %>_length = msg->header-><%= @name %>_length = ((val) ? (strlen(val) + 1) : 0);\
|
4
4
|
}
|