svn update: 51457 (latest:51480)
[framework/uifw/eet.git] / src / lib / eet_connection.c
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