protomsg 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +69 -1
- data/lib/templates/getters/string_getter.h +1 -1
- data/lib/templates/io.h +9 -4
- data/lib/templates/lengths.h +1 -1
- data/lib/templates/message_type.h +5 -0
- data/lib/templates/protomsg.h +63 -7
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Protocol Message Buffers for C. This gem generates C socket code for reading and writing messages described in the protomsg DSL.
|
4
4
|
|
5
|
-
==
|
5
|
+
== Overview
|
6
6
|
Input for a 'request' message:
|
7
7
|
|
8
8
|
request {
|
@@ -57,5 +57,73 @@ All message type and attribute names must be valid C identifiers. Valid attribut
|
|
57
57
|
string C string
|
58
58
|
raw Raw bytes
|
59
59
|
|
60
|
+
== Example
|
61
|
+
Once you have defined your message types, sending and receiving messages is easy. For example, given the following message type:
|
62
|
+
|
63
|
+
# ping_message.protomsg
|
64
|
+
ping {
|
65
|
+
int number
|
66
|
+
string message
|
67
|
+
}
|
68
|
+
|
69
|
+
response {
|
70
|
+
int code
|
71
|
+
}
|
72
|
+
|
73
|
+
Use the protomsg script:
|
74
|
+
|
75
|
+
$ protomsg ping_message.protomsg
|
76
|
+
Created protomsg.h
|
77
|
+
Created ping_message.h
|
78
|
+
Creates response_message.h
|
79
|
+
|
80
|
+
A number of utility macros are defined that make it easy to write clients and servers. An example client could be written as:
|
81
|
+
|
82
|
+
#include "response_message.h"
|
83
|
+
#include "ping_message.h"
|
84
|
+
|
85
|
+
int main(void) {
|
86
|
+
int error, server;
|
87
|
+
response *r;
|
88
|
+
ping *p;
|
89
|
+
|
90
|
+
// create the ping message
|
91
|
+
init_ping(p);
|
92
|
+
set_ping_number(p, 1);
|
93
|
+
set_ping_message(p, "Hello World!");
|
94
|
+
|
95
|
+
// connect to the server and send the message
|
96
|
+
connect_to_server("localhost", 9000, server, error);
|
97
|
+
write_ping(p, server, error);
|
98
|
+
|
99
|
+
// read a response message
|
100
|
+
read_response(r, server, error);
|
101
|
+
printf("Response code was: %llu\n", get_response_code(r));
|
102
|
+
}
|
103
|
+
|
104
|
+
And the corresponding server could be:
|
105
|
+
|
106
|
+
#include "response_message.h"
|
107
|
+
#include "ping_message.h"
|
108
|
+
|
109
|
+
int main(void) {
|
110
|
+
int error, server, client;
|
111
|
+
response *r;
|
112
|
+
ping *p;
|
113
|
+
|
114
|
+
// start a server and wait for a ping message
|
115
|
+
create_server_socket(9000, 1, server, error);
|
116
|
+
accept_client(server, client);
|
117
|
+
read_ping(p, client, error);
|
118
|
+
printf("Received ping: %llu, %s\n", get_ping_number(p), get_ping_message(p));
|
119
|
+
|
120
|
+
// create a response message and send
|
121
|
+
init_response(r);
|
122
|
+
set_response_code(r, 1);
|
123
|
+
write_response(r, client, error);
|
124
|
+
}
|
125
|
+
|
126
|
+
It's not necessary to use the included socket helper macros - you can use protomsg's 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
|
+
|
60
128
|
== Known Issues
|
61
129
|
All clients are servers are assumed to be on machines of the same endianess.
|
@@ -1 +1 @@
|
|
1
|
-
#define get_<%= @message_type.name %>_<%= @name %>(msg) (msg-><%= @name %>)
|
1
|
+
#define get_<%= @message_type.name %>_<%= @name %>(msg) ((char *)msg-><%= @name %>)
|
data/lib/templates/io.h
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#define write_<%= @name %>(msg, sock, error) {\
|
2
|
+
error = 0;\
|
2
3
|
ssize_t written = writev(sock, (const struct iovec *)msg, <%= variable_attributes.size + 1 %>);\
|
3
4
|
if(written != <%= @name %>_length(msg)){\
|
4
5
|
error = errno;\
|
@@ -10,9 +11,13 @@
|
|
10
11
|
msg->header_length = sizeof(<%= @name %>_header);\
|
11
12
|
msg->header = (<%= @name %>_header *)malloc(sizeof(<%= @name %>_header));\
|
12
13
|
read_struct(sock, msg->header, sizeof(<%= @name %>_header), error);\
|
13
|
-
if(error
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
if(!error) {\
|
15
|
+
if(msg->header->_version == PROTO_MESSAGE_VERSION && msg->header->_type == <%= @name.upcase %>_MESSAGE_TYPE) {\
|
16
|
+
<% variable_attributes.each do |attr| %>msg-><%= attr.name %>_length = msg->header-><%= attr.name %>_length;\
|
17
|
+
msg-><%= attr.name %> = malloc(msg->header-><%= attr.name %>_length);\
|
18
|
+
<% end %>readv(sock, (const struct iovec *)msg + 1, <%= variable_attributes.size %>);\
|
19
|
+
} else {\
|
20
|
+
error = INVALID_PROTOMSG_HEADER;\
|
21
|
+
}\
|
17
22
|
}\
|
18
23
|
}
|
data/lib/templates/lengths.h
CHANGED
@@ -1,2 +1,2 @@
|
|
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 +
|
2
|
+
<% end %>#define <%= @name %>_length(msg) (msg->header_length <%= variable_attributes.size > 0 ? ("+ " + variable_attributes.collect {|attr| "msg->#{attr.name}_length"}.join(" + ")) : '' %>)
|
@@ -9,6 +9,9 @@
|
|
9
9
|
#include <unistd.h>
|
10
10
|
#include "protomsg.h"
|
11
11
|
|
12
|
+
#ifndef __protomsg_<%= @name %>__
|
13
|
+
#define __protomsg_<%= @name %>__
|
14
|
+
|
12
15
|
#define <%= @name.upcase %>_MESSAGE_TYPE <%= @type_number %>
|
13
16
|
|
14
17
|
<%= header %>
|
@@ -23,3 +26,5 @@
|
|
23
26
|
<%= memory %>
|
24
27
|
// io
|
25
28
|
<%= io %>
|
29
|
+
|
30
|
+
#endif
|
data/lib/templates/protomsg.h
CHANGED
@@ -1,21 +1,77 @@
|
|
1
|
+
#include <sys/socket.h>
|
2
|
+
#include <sys/types.h>
|
3
|
+
#include <arpa/inet.h>
|
4
|
+
#include <netdb.h>
|
1
5
|
#include <stdio.h>
|
6
|
+
#include <errno.h>
|
2
7
|
|
3
8
|
#ifndef __protomsg__
|
4
9
|
#define __protomsg__
|
5
10
|
|
6
|
-
#define PROTO_MESSAGE_VERSION
|
11
|
+
#define PROTO_MESSAGE_VERSION 1
|
12
|
+
#define INVALID_PROTOMSG_HEADER 1
|
13
|
+
|
7
14
|
#define read_struct(sock, structure, size, error) {\
|
8
|
-
ssize_t bytes_read = 0, bytes_total = 0;\
|
9
15
|
error = 0;\
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
16
|
+
ssize_t _bytes_read = 0, _bytes_total = 0;\
|
17
|
+
while(_bytes_total < size) {\
|
18
|
+
_bytes_read = read(sock, structure + _bytes_total, size - _bytes_total);\
|
19
|
+
if(_bytes_read != -1) {\
|
20
|
+
_bytes_total += _bytes_read;\
|
14
21
|
} else {\
|
15
22
|
error = errno;\
|
16
|
-
|
23
|
+
_bytes_total = size;\
|
24
|
+
}\
|
25
|
+
}\
|
26
|
+
}
|
27
|
+
|
28
|
+
#define create_server_socket(port, queue, sock, error) {\
|
29
|
+
error = 0;\
|
30
|
+
sock = socket(AF_INET, SOCK_STREAM, 0);\
|
31
|
+
struct sockaddr_in _servaddr;\
|
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) {\
|
38
|
+
error = errno;\
|
39
|
+
} else {\
|
40
|
+
error = listen(sock, queue);\
|
41
|
+
if(error) {\
|
42
|
+
error = errno;\
|
17
43
|
}\
|
18
44
|
}\
|
19
45
|
}
|
20
46
|
|
47
|
+
#define accept_client(sock, client) {\
|
48
|
+
client = accept(sock, NULL, NULL);\
|
49
|
+
}
|
50
|
+
|
51
|
+
#define connect_to_server(address, port, sock, error) {\
|
52
|
+
error = 0;\
|
53
|
+
sock = socket(AF_INET, SOCK_STREAM, 0);\
|
54
|
+
struct sockaddr _servaddr;\
|
55
|
+
socklen_t _servaddr_length;\
|
56
|
+
get_socket_addr_from_hostname(address, _servaddr, _servaddr_length, error);\
|
57
|
+
if(!error) {\
|
58
|
+
((struct sockaddr_in *) &_servaddr)->sin_port = htons(port);\
|
59
|
+
error = connect(sock, (struct sockaddr *) &_servaddr, sizeof(_servaddr));\
|
60
|
+
}\
|
61
|
+
}
|
62
|
+
|
63
|
+
#define get_socket_addr_from_hostname(host, servaddr, length, error) {\
|
64
|
+
struct addrinfo _hints, *_result;\
|
65
|
+
memset(&_hints, 0, sizeof(_hints));\
|
66
|
+
_hints.ai_family = AF_INET;\
|
67
|
+
_hints.ai_socktype = SOCK_STREAM;\
|
68
|
+
_hints.ai_protocol = IPPROTO_TCP;\
|
69
|
+
error = getaddrinfo(host, NULL, &_hints, &_result);\
|
70
|
+
if(!error) {\
|
71
|
+
length = _result->ai_addrlen;\
|
72
|
+
memcpy(&servaddr, _result->ai_addr, length);\
|
73
|
+
freeaddrinfo(_result);\
|
74
|
+
}\
|
75
|
+
}
|
76
|
+
|
21
77
|
#endif
|