1
0
mirror of https://github.com/haiwen/ccnet-server.git synced 2025-06-07 20:54:42 +00:00
ccnet-server/lib/packet-io.c

240 lines
4.9 KiB
C
Raw Permalink Normal View History

2016-08-18 09:39:55 +00:00
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <config.h>
#include <stdint.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <glib.h>
#include "packet.h"
#include "packet-io.h"
#include "buffer.h"
static ssize_t /* Write "n" bytes to a descriptor. */
writen(evutil_socket_t fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
#ifndef WIN32
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
#else
if ( (nwritten = send(fd, (char *)ptr, nleft, 0)) <= 0) {
#endif
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return(-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
return(n);
}
static ssize_t /* Read "n" bytes from a descriptor. */
readn(evutil_socket_t fd, struct buffer *buf, size_t n)
{
size_t nleft;
ssize_t nread;
nleft = n;
while (nleft > 0) {
if ( (nread = buffer_read(buf, fd, nleft)) < 0) {
if (errno == EINTR)
nread = 0; /* and call read() again */
else
return(-1);
} else if (nread == 0)
break; /* EOF */
nleft -= nread;
}
return(n - nleft); /* return >= 0 */
}
CcnetPacketIO*
ccnet_packet_io_new (evutil_socket_t fd)
{
CcnetPacketIO *io;
io = g_malloc (sizeof(CcnetPacketIO));
io->fd = fd;
io->buffer = buffer_new ();
io->in_buf = buffer_new ();
return io;
}
void
ccnet_packet_io_free (CcnetPacketIO *io)
{
evutil_closesocket(io->fd);
buffer_free (io->buffer);
buffer_free (io->in_buf);
g_free (io);
}
void
ccnet_packet_prepare (CcnetPacketIO *io, int type, int id)
{
ccnet_header header;
header.version = 1;
header.type = type;
header.length = 0;
header.id = htonl (id);
buffer_add (io->buffer, &header, sizeof (header));
}
void
ccnet_packet_write_string (CcnetPacketIO *io, const char *str)
{
int len;
len = strlen(str);
buffer_add (io->buffer, str, len);
}
void
ccnet_packet_add (CcnetPacketIO *io, const char *buf, int len)
{
buffer_add (io->buffer, buf, len);
}
void
ccnet_packet_finish (CcnetPacketIO *io)
{
ccnet_header *header;
header = (ccnet_header *) BUFFER_DATA(io->buffer);
header->length = htons (BUFFER_LENGTH(io->buffer)
- CCNET_PACKET_LENGTH_HEADER);
}
void
ccnet_packet_send (CcnetPacketIO *io)
{
writen (io->fd, BUFFER_DATA (io->buffer), io->buffer->off);
buffer_drain (io->buffer, io->buffer->off);
}
void
ccnet_packet_finish_send (CcnetPacketIO *io)
{
ccnet_packet_finish (io);
ccnet_packet_send (io);
}
ccnet_packet *
ccnet_packet_io_read_packet (CcnetPacketIO* io)
{
ccnet_packet *packet;
int len;
buffer_drain (io->in_buf, io->in_buf->off);
if (readn (io->fd, io->in_buf, CCNET_PACKET_LENGTH_HEADER) <= 0)
return NULL;
packet = (ccnet_packet *) BUFFER_DATA(io->in_buf);
len = ntohs (packet->header.length);
if (len > 0) {
if (readn (io->fd, io->in_buf, len) <= 0)
return NULL;
}
/* Note: must reset packet since readn() may cause realloc of buffer */
packet = (ccnet_packet *) BUFFER_DATA(io->in_buf);
packet->header.length = len;
packet->header.id = ntohl (packet->header.id);
return packet;
}
void
ccnet_packet_io_set_callback (CcnetPacketIO *io,
got_packet_callback func,
void *user_data)
{
io->func = func;
io->user_data = user_data;
}
/* return 0 on EOF, -1 on error, 1 otherwise */
int
ccnet_packet_io_read (CcnetPacketIO *io)
{
int n;
ccnet_packet *packet;
int len;
again:
if ( (n = buffer_read(io->in_buf, io->fd, 1024)) < 0) {
if (errno == EINTR)
goto again;
g_warning ("read from connfd error: %s.\n", strerror(errno));
return -1;
}
if (n == 0) {
if (io->func)
io->func (NULL, io->user_data);
return 0;
}
while (BUFFER_LENGTH(io->in_buf) >= CCNET_PACKET_LENGTH_HEADER)
{
packet = (ccnet_packet *) BUFFER_DATA(io->in_buf);
len = ntohs (packet->header.length);
if (BUFFER_LENGTH (io->in_buf) - CCNET_PACKET_LENGTH_HEADER < len)
break;
packet->header.length = len;
packet->header.id = ntohl (packet->header.id);
io->func (packet, io->user_data);
buffer_drain (io->in_buf, len + CCNET_PACKET_LENGTH_HEADER);
}
return 1;
}
/* void */
/* ccnet_send_request (int req_id, const char *req) */
/* { */
/* ccnet_packet_prepear (CCNET_MSG_REQUEST, req_id); */
/* ccnet_packet_write_string (req); */
/* ccnet_packet_finish_send (); */
/* fprintf (stderr, "Send a request: id %d, cmd %s\n", req_id, req); */
/* } */