efl/src/lib/eet/eet_connection.c

233 lines
6.1 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* ifdef HAVE_CONFIG_H */
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
# define alloca __builtin_alloca
#elif defined _AIX
# define alloca __alloca
#elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
#else /* ifdef HAVE_ALLOCA_H */
# include <stddef.h>
# ifdef __cplusplus
extern "C"
# endif /* ifdef __cplusplus */
void *alloca(size_t);
#endif /* ifdef HAVE_ALLOCA_H */
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif /* ifdef HAVE_NETINET_IN_H */
#ifdef _WIN32
# include <winsock2.h>
#endif /* ifdef _WIN32 */
#include <Eina.h>
#include "Eet.h"
#include "Eet_private.h"
/* max message size: 1Gb - raised from original 64Kb */
#define MAX_MSG_SIZE (1024 * 1024 * 1024)
#define MAGIC_EET_DATA_PACKET 0x4270ACE1
struct _Eet_Connection
{
Eet_Read_Cb *eet_read_cb;
Eet_Write_Cb *eet_write_cb;
void *user_data;
size_t allocated;
size_t size;
size_t received;
void *buffer;
};
EAPI Eet_Connection *
eet_connection_new(Eet_Read_Cb *eet_read_cb,
Eet_Write_Cb *eet_write_cb,
const void *user_data)
{
Eet_Connection *conn;
if ((!eet_read_cb) || (!eet_write_cb)) return NULL;
conn = calloc(1, sizeof (Eet_Connection));
if (!conn) return NULL;
conn->eet_read_cb = eet_read_cb;
conn->eet_write_cb = eet_write_cb;
conn->user_data = (void *)user_data;
return conn;
}
EAPI int
eet_connection_received(Eet_Connection *conn,
const void *data,
size_t size)
{
if ((!conn) || (!data) || (!size)) return size;
do
{
size_t copy_size;
if (conn->size == 0)
{
const int *msg;
size_t packet_size;
if (size < (sizeof(int) * 2)) break;
msg = data;
/* Check the magic */
if (ntohl(msg[0]) != MAGIC_EET_DATA_PACKET) break;
packet_size = ntohl(msg[1]);
/* Message should always be under MAX_MSG_SIZE */
if (packet_size > MAX_MSG_SIZE) break;
data = (void *)(msg + 2);
size -= sizeof(int) * 2;
if ((size_t)packet_size <= size)
{
/* Not a partial receive, go the quick way. */
if (!conn->eet_read_cb(data, packet_size, conn->user_data))
break;
data = (void *)((char *)data + packet_size);
size -= packet_size;
conn->received = 0;
continue;
}
conn->size = packet_size;
if (conn->allocated < conn->size)
{
void *tmp;
tmp = realloc(conn->buffer, conn->size);
if (!tmp) break;
conn->buffer = tmp;
conn->allocated = conn->size;
}
}
/* Partial receive */
copy_size =
(conn->size - conn->received >=
size) ? size : conn->size - conn->received;
memcpy((char *)conn->buffer + conn->received, data, copy_size);
conn->received += copy_size;
data = (void *)((char *)data + copy_size);
size -= copy_size;
if (conn->received == conn->size)
{
size_t data_size;
data_size = conn->size;
conn->size = 0;
conn->received = 0;
/* Completed a packet. */
if (!conn->eet_read_cb(conn->buffer, data_size, conn->user_data))
{
/* Something goes wrong. Stop now. */
size += data_size;
break;
}
}
}
while (size > 0);
return size;
}
static Eina_Bool
_eet_connection_raw_send(Eet_Connection *conn,
void *data,
int data_size)
{
int *message;
/* Message should always be under MAX_MSG_SIZE */
if (data_size > MAX_MSG_SIZE) return EINA_FALSE;
message = alloca(data_size + (sizeof(int) * 2));
message[0] = htonl(MAGIC_EET_DATA_PACKET);
message[1] = htonl(data_size);
memcpy(message + 2, data, data_size);
conn->eet_write_cb(message,
data_size + (sizeof(int) * 2),
conn->user_data);
return EINA_TRUE;
}
EAPI Eina_Bool
eet_connection_empty(Eet_Connection *conn)
{
return conn->size ? EINA_FALSE : EINA_TRUE;
}
EAPI Eina_Bool
eet_connection_send(Eet_Connection *conn,
Eet_Data_Descriptor *edd,
const void *data_in,
const char *cipher_key)
{
void *flat_data;
int data_size;
Eina_Bool ret = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, EINA_FALSE);
flat_data = eet_data_descriptor_encode_cipher(edd,
data_in,
cipher_key,
&data_size);
if (!flat_data) return EINA_FALSE;
if (_eet_connection_raw_send(conn, flat_data, data_size)) ret = EINA_TRUE;
free(flat_data);
return ret;
}
EAPI Eina_Bool
eet_connection_node_send(Eet_Connection *conn,
Eet_Node *node,
const char *cipher_key)
{
void *data;
int data_size;
Eina_Bool ret = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, EINA_FALSE);
data = eet_data_node_encode_cipher(node, cipher_key, &data_size);
if (!data) return EINA_FALSE;
if (_eet_connection_raw_send(conn, data, data_size))
ret = EINA_TRUE;
free(data);
return ret;
}
EAPI void *
eet_connection_close(Eet_Connection *conn,
Eina_Bool *on_going)
{
void *user_data;
if (!conn) return NULL;
if (on_going) *on_going = conn->received == 0 ? EINA_FALSE : EINA_TRUE;
user_data = conn->user_data;
free(conn->buffer);
free(conn);
return user_data;
}