diff options
Diffstat (limited to 'libraries/eet/src/lib/eet_connection.c')
-rw-r--r-- | libraries/eet/src/lib/eet_connection.c | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/libraries/eet/src/lib/eet_connection.c b/libraries/eet/src/lib/eet_connection.c new file mode 100644 index 0000000..6171b7e --- /dev/null +++ b/libraries/eet/src/lib/eet_connection.c | |||
@@ -0,0 +1,249 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif /* ifdef HAVE_CONFIG_H */ | ||
4 | |||
5 | #ifdef HAVE_ALLOCA_H | ||
6 | # include <alloca.h> | ||
7 | #elif defined __GNUC__ | ||
8 | # define alloca __builtin_alloca | ||
9 | #elif defined _AIX | ||
10 | # define alloca __alloca | ||
11 | #elif defined _MSC_VER | ||
12 | # include <malloc.h> | ||
13 | # define alloca _alloca | ||
14 | #else /* ifdef HAVE_ALLOCA_H */ | ||
15 | # include <stddef.h> | ||
16 | # ifdef __cplusplus | ||
17 | extern "C" | ||
18 | # endif /* ifdef __cplusplus */ | ||
19 | void *alloca(size_t); | ||
20 | #endif /* ifdef HAVE_ALLOCA_H */ | ||
21 | |||
22 | #include <string.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | #ifdef HAVE_NETINET_IN_H | ||
26 | # include <netinet/in.h> | ||
27 | #endif /* ifdef HAVE_NETINET_IN_H */ | ||
28 | |||
29 | #ifdef _WIN32 | ||
30 | # include <winsock2.h> | ||
31 | #endif /* ifdef _WIN32 */ | ||
32 | |||
33 | #include <Eina.h> | ||
34 | |||
35 | #include "Eet.h" | ||
36 | #include "Eet_private.h" | ||
37 | |||
38 | #define MAGIC_EET_DATA_PACKET 0x4270ACE1 | ||
39 | |||
40 | struct _Eet_Connection | ||
41 | { | ||
42 | Eet_Read_Cb *eet_read_cb; | ||
43 | Eet_Write_Cb *eet_write_cb; | ||
44 | void *user_data; | ||
45 | |||
46 | size_t allocated; | ||
47 | size_t size; | ||
48 | size_t received; | ||
49 | |||
50 | void *buffer; | ||
51 | }; | ||
52 | |||
53 | EAPI Eet_Connection * | ||
54 | eet_connection_new(Eet_Read_Cb *eet_read_cb, | ||
55 | Eet_Write_Cb *eet_write_cb, | ||
56 | const void *user_data) | ||
57 | { | ||
58 | Eet_Connection *conn; | ||
59 | |||
60 | if (!eet_read_cb || !eet_write_cb) | ||
61 | return NULL; | ||
62 | |||
63 | conn = calloc(1, sizeof (Eet_Connection)); | ||
64 | if (!conn) | ||
65 | return NULL; | ||
66 | |||
67 | conn->eet_read_cb = eet_read_cb; | ||
68 | conn->eet_write_cb = eet_write_cb; | ||
69 | conn->user_data = (void *)user_data; | ||
70 | |||
71 | return conn; | ||
72 | } /* eet_connection_new */ | ||
73 | |||
74 | EAPI int | ||
75 | eet_connection_received(Eet_Connection *conn, | ||
76 | const void *data, | ||
77 | size_t size) | ||
78 | { | ||
79 | if ((!conn) || (!data) || (!size)) | ||
80 | return size; | ||
81 | |||
82 | do { | ||
83 | size_t copy_size; | ||
84 | |||
85 | if (conn->size == 0) | ||
86 | { | ||
87 | const int *msg; | ||
88 | size_t packet_size; | ||
89 | |||
90 | if (size < sizeof (int) * 2) | ||
91 | break; | ||
92 | |||
93 | msg = data; | ||
94 | /* Check the magic */ | ||
95 | if (ntohl(msg[0]) != MAGIC_EET_DATA_PACKET) | ||
96 | break; | ||
97 | |||
98 | packet_size = ntohl(msg[1]); | ||
99 | /* Message should always be under 64K */ | ||
100 | if (packet_size > 64 * 1024) | ||
101 | break; | ||
102 | |||
103 | data = (void *)(msg + 2); | ||
104 | size -= sizeof (int) * 2; | ||
105 | if ((size_t)packet_size <= size) | ||
106 | { | ||
107 | /* Not a partial receive, go the quick way. */ | ||
108 | if (!conn->eet_read_cb(data, packet_size, conn->user_data)) | ||
109 | break; | ||
110 | |||
111 | data = (void *)((char *)data + packet_size); | ||
112 | size -= packet_size; | ||
113 | |||
114 | conn->received = 0; | ||
115 | continue; | ||
116 | } | ||
117 | |||
118 | conn->size = packet_size; | ||
119 | if (conn->allocated < conn->size) | ||
120 | { | ||
121 | void *tmp; | ||
122 | |||
123 | tmp = realloc(conn->buffer, conn->size); | ||
124 | if (!tmp) | ||
125 | break; | ||
126 | |||
127 | conn->buffer = tmp; | ||
128 | conn->allocated = conn->size; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* Partial receive */ | ||
133 | copy_size = | ||
134 | (conn->size - conn->received >= | ||
135 | size) ? size : conn->size - conn->received; | ||
136 | memcpy((char *)conn->buffer + conn->received, data, copy_size); | ||
137 | |||
138 | conn->received += copy_size; | ||
139 | data = (void *)((char *)data + copy_size); | ||
140 | size -= copy_size; | ||
141 | |||
142 | if (conn->received == conn->size) | ||
143 | { | ||
144 | size_t data_size; | ||
145 | |||
146 | data_size = conn->size; | ||
147 | conn->size = 0; | ||
148 | conn->received = 0; | ||
149 | |||
150 | /* Completed a packet. */ | ||
151 | if (!conn->eet_read_cb(conn->buffer, data_size, conn->user_data)) | ||
152 | { | ||
153 | /* Something goes wrong. Stop now. */ | ||
154 | size += data_size; | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | } while (size > 0); | ||
159 | |||
160 | return size; | ||
161 | } /* eet_connection_received */ | ||
162 | |||
163 | static Eina_Bool | ||
164 | _eet_connection_raw_send(Eet_Connection *conn, | ||
165 | void *data, | ||
166 | int data_size) | ||
167 | { | ||
168 | int *message; | ||
169 | |||
170 | /* Message should never be above 64K */ | ||
171 | if (data_size > 64 * 1024) | ||
172 | return EINA_FALSE; | ||
173 | |||
174 | message = alloca(data_size + sizeof (int) * 2); | ||
175 | message[0] = htonl(MAGIC_EET_DATA_PACKET); | ||
176 | message[1] = htonl(data_size); | ||
177 | |||
178 | memcpy(message + 2, data, data_size); | ||
179 | |||
180 | conn->eet_write_cb(message, | ||
181 | data_size + sizeof (int) * 2, | ||
182 | conn->user_data); | ||
183 | return EINA_TRUE; | ||
184 | } /* _eet_connection_raw_send */ | ||
185 | |||
186 | EAPI Eina_Bool | ||
187 | eet_connection_send(Eet_Connection *conn, | ||
188 | Eet_Data_Descriptor *edd, | ||
189 | const void *data_in, | ||
190 | const char *cipher_key) | ||
191 | { | ||
192 | void *flat_data; | ||
193 | int data_size; | ||
194 | Eina_Bool ret = EINA_FALSE; | ||
195 | |||
196 | flat_data = eet_data_descriptor_encode_cipher(edd, | ||
197 | data_in, | ||
198 | cipher_key, | ||
199 | &data_size); | ||
200 | if (!flat_data) | ||
201 | return EINA_FALSE; | ||
202 | |||
203 | if (_eet_connection_raw_send(conn, flat_data, data_size)) | ||
204 | ret = EINA_TRUE; | ||
205 | |||
206 | free(flat_data); | ||
207 | return ret; | ||
208 | } /* eet_connection_send */ | ||
209 | |||
210 | EAPI Eina_Bool | ||
211 | eet_connection_node_send(Eet_Connection *conn, | ||
212 | Eet_Node *node, | ||
213 | const char *cipher_key) | ||
214 | { | ||
215 | void *data; | ||
216 | int data_size; | ||
217 | Eina_Bool ret = EINA_FALSE; | ||
218 | |||
219 | data = eet_data_node_encode_cipher(node, cipher_key, &data_size); | ||
220 | if (!data) | ||
221 | return EINA_FALSE; | ||
222 | |||
223 | if (_eet_connection_raw_send(conn, data, data_size)) | ||
224 | ret = EINA_TRUE; | ||
225 | |||
226 | free(data); | ||
227 | return ret; | ||
228 | } /* eet_connection_node_send */ | ||
229 | |||
230 | EAPI void * | ||
231 | eet_connection_close(Eet_Connection *conn, | ||
232 | Eina_Bool *on_going) | ||
233 | { | ||
234 | void *user_data; | ||
235 | |||
236 | if (!conn) | ||
237 | return NULL; | ||
238 | |||
239 | if (on_going) | ||
240 | *on_going = conn->received == 0 ? EINA_FALSE : EINA_TRUE; | ||
241 | |||
242 | user_data = conn->user_data; | ||
243 | |||
244 | free(conn->buffer); | ||
245 | free(conn); | ||
246 | |||
247 | return user_data; | ||
248 | } /* eet_connection_close */ | ||
249 | |||