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 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
- == Example
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 == 0) {\
14
- <% variable_attributes.each do |attr| %>msg-><%= attr.name %>_length = msg->header-><%= attr.name %>_length;\
15
- msg-><%= attr.name %> = malloc(msg->header-><%= attr.name %>_length);\
16
- <% end %>readv(sock, (const struct iovec *)msg + 1, <%= variable_attributes.size %>);\
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
  }
@@ -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 + <%= 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(" + ")) : '' %>)
@@ -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
@@ -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 1
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
- while(bytes_total < size) {\
11
- bytes_read = read(sock, structure + bytes_total, size - bytes_total);\
12
- if(bytes_read != -1) {\
13
- bytes_total += bytes_read;\
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
- bytes_total = size;\
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
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
7
+ - 6
8
8
  - 0
9
- version: 0.5.0
9
+ version: 0.6.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Will Cannings