lock.h:
#ifndef __LOCK_H__
#define __LOCK_H__
#include <pthread.h>
class MutexLocker
{
public:
MutexLocker();
~MutexLocker();
void lock();
void unlock();
private:
pthread_mutex_t m_locker;
};
class RWLocker
{
public:
RWLocker();
~RWLocker();
void rdlock();
void wrlock();
void unlock();
private:
pthread_rwlock_t m_locker;
};
#endif
lock.cpp:
#include <cstdio>
#include <cstdlib>
#include <error.h>
#include <cstring>
#include "lock.h"
MutexLocker::MutexLocker()
{
int error_no = 0;
if (0 != (error_no = pthread_mutex_init(&m_locker, NULL)))
{
printf("pthread_mutex_init error: %s\n", strerror(error_no));
exit(1);
}
}
MutexLocker::~MutexLocker()
{
int error_no = 0;
if (0 != (error_no = pthread_mutex_destroy(&m_locker)))
{
printf("pthread_mutex_destroy error: %s\n", strerror(error_no));
exit(1);
}
}
void MutexLocker::lock()
{
int error_no = 0;
if (0 != (error_no = pthread_mutex_lock(&m_locker)))
{
printf("pthread_mutex_lock error: %s\n", strerror(error_no));
exit(1);
}
}
void MutexLocker::unlock()
{
int error_no = 0;
if (0 != (error_no = pthread_mutex_unlock(&m_locker)))
{
printf("pthread_mutex_unlock error: %s\n", strerror(error_no));
exit(1);
}
}
RWLocker::RWLocker()
{
int error_no = 0;
if (0 != (error_no = pthread_rwlock_init(&m_locker, NULL)))
{
printf("pthread_rwlock_init error: %s\n", strerror(error_no));
exit(1);
}
}
RWLocker::~RWLocker()
{
int error_no = 0;
if (0 != (error_no = pthread_rwlock_destroy(&m_locker)))
{
printf("pthread_rwlock_destroy error: %s\n", strerror(error_no));
exit(1);
}
}
void RWLocker::rdlock()
{
int error_no = 0;
if (0 != (error_no = pthread_rwlock_rdlock(&m_locker)))
{
printf("pthread_rwlock_rdlock error: %s\n", strerror(error_no));
exit(1);
}
}
void RWLocker::wrlock()
{
int error_no = 0;
if (0 != (error_no = pthread_rwlock_wrlock(&m_locker)))
{
printf("pthread_rwlock_wrlock error: %s\n", strerror(error_no));
exit(1);
}
}
void RWLocker::unlock()
{
int error_no = 0;
if (0 != (error_no = pthread_rwlock_unlock(&m_locker)))
{
printf("pthread_rwlock_unlock error: %s\n", strerror(error_no));
exit(1);
}
}
types.h:
#ifndef __TYPES_H__
#define __TYPES_H__
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint32_t seq_type;
typedef uint32_t time_type;
#endif
common.h:
#ifndef __COMMON_H__
#define __COMMON_H__
#include "types.h"
time_type getcurtime();
void big2little(void * object, int size);
#endif
common.cpp:
#include <cstdio>
#include <sys/time.h>
#include "common.h"
time_type getcurtime()
{
static struct timeval base;
static bool first_time = true;
if (first_time)
{
gettimeofday(&base, NULL);
first_time = false;
}
struct timeval curtime;
gettimeofday(&curtime, NULL);
time_type delta = 0;
if (curtime.tv_usec < base.tv_usec)
{
delta = (1000000 + curtime.tv_usec - base.tv_usec) / 1000;
--curtime.tv_sec;
}
else
{
delta = (curtime.tv_usec - base.tv_usec) / 1000;
}
delta += (curtime.tv_sec - base.tv_sec) * 1000;
return(delta);
}
void big2little(void * object, int size)
{
static union
{
uint16_t us;
unsigned char uc[sizeof(uint16_t)];
} un;
un.us = 0x0001;
if (0x00 == un.uc[0])
{
char * ptr = (char *)object;
for (int i = 0; i < size / 2; ++i)
{
char temp = ptr[i];
ptr[i] = ptr[size - 1 - i];
ptr[size - 1 - i] = temp;
}
}
}
nodes.hpp:
#ifndef __NODES_H__
#define __NODES_H__
#include <cassert>
#include <iostream>
using std::min;
using std::max;
#include "types.h"
#include "lock.h"
template <typename NodeType>
class NodePool
{
public:
NodePool(NodePool<typename NodeType::InnerNode> * p) : first_node(NULL), inner_pool(p)
{
}
~NodePool()
{
locker.lock();
NodeType * ptr = first_node;
while (NULL != ptr)
{
first_node = first_node->next;
delete ptr;
ptr = first_node;
}
locker.unlock();
}
NodeType * get_node()
{
NodeType * ptr = NULL;
locker.lock();
if (NULL != first_node)
{
ptr = first_node;
first_node = first_node->next;
if (NULL != first_node)
{
first_node->prev = NULL;
}
ptr->prev = NULL;
ptr->next = NULL;
}
else
{
ptr = new NodeType(inner_pool);
}
locker.unlock();
return(ptr);
}
void put_node(NodeType * node)
{
put_node(node, node);
}
void put_node(NodeType * head, NodeType * tail)
{
assert(NULL != head && NULL != tail);
locker.lock();
tail->next = first_node;
if (NULL != first_node)
{
first_node->prev = tail;
}
first_node = head;
first_node->prev = NULL;
locker.unlock();
}
private:
NodeType * first_node;
NodePool<typename NodeType::InnerNode> * inner_pool;
MutexLocker locker;
};
template <typename NodeType>
struct NodeLink
{
typedef NodePool<NodeType> PoolType;
NodeType * head;
NodeType * tail;
PoolType * pool;
uint16_t size;
NodeLink(PoolType * p)
: head(NULL), tail(NULL), pool(p), size(0)
{
assert(NULL != pool);
}
~NodeLink()
{
clear();
}
bool push_after(NodeType * loc, NodeType * node)
{
if (NULL == loc)
{
assert(false);
return(false);
}
if (NULL == node)
{
assert(false);
return(false);
}
node->prev = loc;
node->next = loc->next;
if (NULL != loc->next)
{
loc->next->prev = node;
}
else
{
tail = node;
}
loc->next = node;
++size;
return(true);
}
bool push_front(NodeType * node)
{
if (NULL == node)
{
assert(false);
return(false);
}
node->prev = NULL;
node->next = head;
if (NULL != head)
{
head->prev = node;
}
else
{
tail = node;
}
head = node;
++size;
return(true);
}
bool push_back(NodeType * node)
{
if (NULL == node)
{
assert(false);
return(false);
}
node->prev = tail;
node->next = NULL;
if (NULL == tail)
{
head = node;
}
else
{
tail->next = node;
}
tail = node;
++size;
return(true);
}
bool push_back(NodeLink<NodeType> & node_list)
{
if (NULL == node_list.head)
{
assert(false);
return(false);
}
node_list.head->prev = tail;
if (NULL == tail)
{
head = node_list.head;
}
else
{
tail->next = node_list.head;
}
tail = node_list.tail;
size += node_list.size;
node_list.head = node_list.tail = NULL;
node_list.size = 0;
return(true);
}
bool erase(NodeType * node)
{
assert(NULL != pool);
if (NULL == node)
{
assert(false);
return(false);
}
if (NULL != node->prev)
{
node->prev->next = node->next;
}
else
{
head = node->next;
}
if (NULL != node->next)
{
node->next->prev = node->prev;
}
else
{
tail = node->prev;
}
node->clear();
pool->put_node(node);
--size;
return(true);
}
void clear()
{
assert(NULL != pool);
NodeType * node = head;
while (NULL != node)
{
node->clear();
node = node->next;
}
if (NULL != head)
{
pool->put_node(head, tail);
}
head = tail = NULL;
size = 0;
}
};
typedef struct TimeInfo
{
uint8_t index;
time_type time;
struct TimeInfo * prev;
struct TimeInfo * next;
typedef void InnerNode;
TimeInfo(NodePool<void> * p) : index(0), time(0), prev(NULL), next(NULL)
{
}
~TimeInfo()
{
clear();
}
void clear()
{
}
} TimeNode;
typedef struct SeqInfo
{
seq_type front_sequence;
seq_type behind_sequence;
NodeLink<TimeNode> time_list;
struct SeqInfo * prev;
struct SeqInfo * next;
typedef TimeNode InnerNode;
SeqInfo(NodePool<TimeNode> * p)
: front_sequence(0), behind_sequence(0),
time_list(p), prev(NULL), next(NULL)
{
}
~SeqInfo()
{
clear();
}
int compare(const struct SeqInfo * other) const
{
assert(NULL != other);
if (front_sequence < other->front_sequence)
{
assert(behind_sequence <= other->front_sequence);
return(-1);
}
else if (front_sequence > other->front_sequence)
{
assert(front_sequence >= other->behind_sequence);
return(1);
}
else /* if (front_sequence == other->front_sequence) */
{
assert(behind_sequence == other->behind_sequence);
return(0);
}
}
TimeNode * find_time_node(uint8_t index)
{
assert(0 != index);
TimeNode * node = time_list.head;
while (NULL != node)
{
if (index < node->index)
{
assert(false);
return(NULL);
}
else if (index > node->index)
{
node = node->next;
}
else
{
return(node);
}
}
return(NULL);
}
void clear()
{
time_list.clear();
}
} SeqNode;
typedef struct SendDataInfo
{
enum { send_node_block_size = 16384 };
seq_type first_sequence;
uint16_t using_size;
uint16_t blank_size;
NodeLink<SeqNode> seq_list;
struct SendDataInfo * prev;
struct SendDataInfo * next;
unsigned char data[send_node_block_size];
typedef SeqNode InnerNode;
SendDataInfo(NodePool<SeqNode> * p)
: first_sequence(0), using_size(0),
blank_size(send_node_block_size),
seq_list(p), prev(NULL), next(NULL)
{
}
~SendDataInfo()
{
clear();
}
int get_relation(seq_type front_sequence, uint16_t offset)
{
assert(0 != offset);
assert(front_sequence + offset > front_sequence);
if (first_sequence > front_sequence)
{
return(1);
}
else if (first_sequence + using_size <= front_sequence)
{
return(-1);
}
else
{
assert(front_sequence + offset <= first_sequence + using_size);
return(0);
}
}
SeqNode * find_seq_node(const SeqNode * node)
{
assert(NULL != node);
SeqNode * ret = seq_list.head;
while (NULL != ret)
{
int comp = node->compare(ret);
if (comp < 0)
{
return(NULL);
}
else if (comp > 0)
{
ret = ret->next;
}
else
{
return(ret);
}
}
return(NULL);
}
void clear()
{
seq_list.clear();
}
} SendDataNode;
typedef struct RttInfo
{
enum { g = 8, h = 4 };
enum { min_rto = 200, max_rto = 1000 };
time_type srtt;
time_type rttvar;
time_type rto;
RttInfo() : srtt(0), rttvar(250), rto(srtt + 4 * rttvar)
{
}
void update(time_type rtt)
{
int delta = rtt - srtt;
srtt += delta / g;
if (delta < 0)
{
delta = -delta;
}
rttvar += (delta - rttvar) / h;
rto = srtt + 4 * rttvar;
if (rto < min_rto)
{
rto = min_rto;
}
else if (rto > max_rto)
{
rto = max_rto;
}
}
} RttType;
typedef struct AckInfo
{
seq_type front_sequence;
uint16_t region_size;
uint8_t count;
AckInfo() : front_sequence(0), region_size(0), count(4)
{
}
AckInfo & operator = (const struct AckInfo & other)
{
if (this != &other)
{
front_sequence = other.front_sequence;
region_size = other.region_size;
count = other.count;
}
return(*this);
}
} AckRegion;
typedef struct RegionInfo
{
seq_type front_sequence;
seq_type behind_sequence;
struct RegionInfo * prev;
struct RegionInfo * next;
typedef void InnerNode;
RegionInfo(NodePool<void> * p)
: front_sequence(0), behind_sequence(0), prev(NULL), next(NULL)
{
}
~RegionInfo()
{
clear();
}
void clear()
{
}
} RegionNode;
typedef struct RecvDataInfo
{
enum { recv_node_block_size = 16384 };
seq_type min_sequence;
seq_type max_sequence;
struct RecvDataInfo * prev;
struct RecvDataInfo * next;
unsigned char data[recv_node_block_size];
typedef void InnerNode;
RecvDataInfo(NodePool<void> * p)
: min_sequence(0), max_sequence(0), prev(NULL), next(NULL)
{
}
~RecvDataInfo()
{
clear();
}
void clear()
{
}
} RecvDataNode;
#endif
rudp.h:
#ifndef __RUDP_H__
#define __RUDP_H__
#include "nodes.hpp"
#include "lock.h"
class RudpMgr;
class Rudp
{
public: /* both end */
Rudp(RudpMgr * mgr, int sockfd, uint32_t unique_id);
~Rudp();
public: /* send end, for user */
bool send_data(unsigned char * data, uint16_t len, bool reliable);
bool send_heart_beat_package();
public: /* both end, for RudpMgr */
bool recv_data(unsigned char * data, uint16_t len);
bool is_alive();
uint32_t get_unique_id();
void kill();
private: /* both end */
enum { unreliable_udp, reliable_udp, ack_message, heart_beat };
RudpMgr * m_rudp_mgr;
int m_sockfd;
uint32_t m_unique_id;
bool m_is_alive;
time_type m_last_recv_heart_beat_time;
public: /* send end, for RudpMgr */
bool has_data_to_send();
bool send_data();
private: /* send end */
bool store_send_data(unsigned char * data, uint16_t len);
bool recv_ack(unsigned char * data, uint16_t len);
void send_new_data(uint8_t & send_count);
void send_old_data(uint8_t & send_count);
bool send_rudp_package(seq_type front_index, uint8_t send_index, unsigned char * data, uint16_t len);
void lock_sender();
void unlock_sender();
private: /* send end */
MutexLocker m_send_mutex_locker;
RttType m_rtt;
seq_type m_next_data_node_first_sequence;
uint8_t m_max_send_count;
uint16_t m_pending_count;
uint16_t m_max_pending_count;
SendDataNode * m_last_send_old_data_node;
SeqNode * m_next_send_old_seq_node;
SendDataNode * m_next_send_new_data_node;
uint16_t m_data_offset;
NodePool<TimeNode> m_send_time_pool;
NodePool<SeqNode> m_send_seq_pool;
NodePool<SendDataNode> m_send_data_pool;
NodeLink<SendDataNode> m_send_data_list;
public: /* recv end, for RudpMgr */
bool analytic_data();
private: /* recv end */
bool store_recv_data(unsigned char * data, uint16_t len);
bool send_ack(uint8_t send_index);
bool do_analytic_data();
void update_ack_nodes(seq_type front_sequence, uint16_t region_size);
int update_recv_region(seq_type front_sequence, uint16_t region_size);
void lock_recver();
void unlock_recver();
private: /* recv end */
MutexLocker m_recv_mutex_locker;
AckRegion m_ack_node[4];
int m_ack_node_count;
int m_new_ack_node_position;
AckRegion m_ack_region;
seq_type m_min_need_sequence;
seq_type m_max_read_sequence;
bool m_turn_to_analytic_len;
uint16_t m_need_analytic_data_len;
NodePool<RegionNode> m_region_pool;
NodeLink<RegionNode> m_region_list;
NodePool<RecvDataNode> m_recv_data_pool;
NodeLink<RecvDataNode> m_recv_data_list;
};
#endif
rudp.cpp:
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include "common.h"
#include "rudp.h"
#include "rudpmgr.h"
#include <cstdio>
Rudp::Rudp(RudpMgr * mgr, int sockfd, uint32_t unique_id)
: m_rudp_mgr(mgr),
m_sockfd(sockfd),
m_unique_id(unique_id),
m_is_alive(true),
m_send_time_pool(NULL),
m_send_seq_pool(&m_send_time_pool),
m_send_data_pool(&m_send_seq_pool),
m_send_data_list(&m_send_data_pool),
m_region_pool(NULL),
m_region_list(&m_region_pool),
m_recv_data_pool(NULL),
m_recv_data_list(&m_recv_data_pool)
{
if (NULL == m_rudp_mgr || m_sockfd < 0)
{
assert(false);
exit(1);
}
m_last_recv_heart_beat_time = getcurtime();
/* send end */
m_next_data_node_first_sequence = 0;
m_max_send_count = 20;
m_pending_count = 0;
m_max_pending_count = 100;
m_last_send_old_data_node = NULL;
m_next_send_old_seq_node = NULL;
m_next_send_new_data_node = NULL;
m_data_offset = 0;
/* recv end */
m_ack_node_count = 0;
m_new_ack_node_position = -1;
m_min_need_sequence = 0;
m_max_read_sequence = 0;
m_turn_to_analytic_len = true;
m_need_analytic_data_len = sizeof(uint16_t);
}
Rudp::~Rudp()
{
}
uint32_t Rudp::get_unique_id()
{
return(m_unique_id);
}
void Rudp::kill()
{
m_is_alive = false;
}
void Rudp::lock_sender()
{
m_send_mutex_locker.lock();
}
void Rudp::unlock_sender()
{
m_send_mutex_locker.unlock();
}
void Rudp::lock_recver()
{
m_recv_mutex_locker.lock();
}
void Rudp::unlock_recver()
{
m_recv_mutex_locker.unlock();
}
bool Rudp::send_data(unsigned char * data, uint16_t len, bool reliable)
{
if (reliable)
{
lock_sender();
bool ret = store_send_data(data, len);
unlock_sender();
return(ret);
}
else
{
if (len > 4096 - 1)
{
return(false);
}
char buff[4096];
buff[0] = (unsigned char)unreliable_udp;
memcpy(buff + 1, data, len);
len += 1;
return(-1 != write(m_sockfd, buff, len));
}
}
bool Rudp::send_heart_beat_package()
{
char buff[1] = { heart_beat };
return(-1 != write(m_sockfd, buff, 1));
}
bool Rudp::recv_data(unsigned char * data, uint16_t len)
{
if (len < 1)
{
assert(false);
return(false);
}
unsigned char data_type = data[0];
data += 1;
len -= 1;
bool ret = false;
if (unreliable_udp == data_type)
{
ret = m_rudp_mgr->handle_data(m_unique_id, data, len);
}
else if (reliable_udp == data_type)
{
lock_recver();
ret = store_recv_data(data, len); /* recv end */
unlock_recver();
}
else if (ack_message == data_type)
{
lock_sender();
ret = recv_ack(data, len); /* send end */
unlock_sender();
}
else if (heart_beat == data_type)
{
m_last_recv_heart_beat_time = getcurtime();
ret = true;
}
else /* unknown data type */
{
assert(false);
ret = false;
}
return(ret);
}
bool Rudp::is_alive()
{
return(m_is_alive && getcurtime() - m_last_recv_heart_beat_time < 2 * 60 * 1000);
}
bool Rudp::store_send_data(unsigned char * data, uint16_t len)
{
uint16_t nlen = len;
big2little(&nlen, sizeof(uint16_t));
unsigned char * len_data = (unsigned char *)&nlen;
uint16_t len_data_len = sizeof(uint16_t);
assert(0 == len || NULL != data);
SendDataNode * tail = m_send_data_list.tail;
uint16_t tail_using_size = 0;
uint16_t tail_blank_size = 0;
if (NULL != tail && tail->blank_size > 0)
{
tail_using_size = tail->using_size;
tail_blank_size = tail->blank_size;
uint16_t write_len = min(len_data_len, tail->blank_size);
memcpy(tail->data + tail->using_size, len_data, write_len);
tail->using_size += write_len;
tail->blank_size -= write_len;
len_data += write_len;
len_data_len -= write_len;
if (tail->blank_size > 0 && len > 0)
{
write_len = min(len, tail->blank_size);
memcpy(tail->data + tail->using_size, data, write_len);
data += write_len;
len -= write_len;
tail->using_size += write_len;
tail->blank_size -= write_len;
}
if (0 == len_data_len && 0 == len)
{
return(true);
}
}
seq_type next_data_node_first_sequence = m_next_data_node_first_sequence;
NodeLink<SendDataNode> node_list(&m_send_data_pool);
while (true)
{
SendDataNode * node = m_send_data_pool.get_node();
if (NULL == node)
{
if (0 != tail_using_size)
{
tail->using_size = tail_using_size;
tail->blank_size = tail_blank_size;
}
m_next_data_node_first_sequence = next_data_node_first_sequence;
return(false);
}
node->first_sequence = m_next_data_node_first_sequence;
m_next_data_node_first_sequence += node->blank_size;
if (len_data_len > 0)
{
assert(len_data_len < node->blank_size);
memcpy(node->data, len_data, len_data_len);
node->using_size += len_data_len;
node->blank_size -= len_data_len;
len_data_len = 0;
}
if (len > 0)
{
assert(node->blank_size > 0);
uint16_t write_len = min(len, node->blank_size);
memcpy(node->data + node->using_size, data, write_len);
node->using_size += write_len;
node->blank_size -= write_len;
data += write_len;
len -= write_len;
}
node_list.push_back(node);
if (0 == len_data_len && 0 == len)
{
break;
}
}
m_send_data_list.push_back(node_list);
return(true);
}
bool Rudp::has_data_to_send()
{
SendDataNode * sd_node = NULL;
sd_node = m_send_data_list.head;
if (NULL == sd_node)
{
return(false);
}
if (sd_node->seq_list.size > 0)
{
return(true);
}
sd_node = m_next_send_new_data_node;
if (NULL == sd_node)
{
assert(0 == m_data_offset);
sd_node = m_send_data_list.head;
assert(NULL != sd_node);
assert(m_data_offset <= sd_node->using_size);
assert(NULL == sd_node->seq_list.head);
}
return(m_data_offset < sd_node->using_size);
}
bool Rudp::send_data()
{
lock_sender();
uint8_t send_count = 0;
send_old_data(send_count); /* send old data */
send_new_data(send_count); /* send new data */
unlock_sender();
return(true);
}
void Rudp::send_new_data(uint8_t & send_count)
{
if (send_count >= m_max_send_count || m_pending_count >= m_max_pending_count)
{
return;
}
if (NULL == m_next_send_new_data_node)
{
assert(0 == m_data_offset);
m_next_send_new_data_node = m_send_data_list.head;
if (NULL == m_next_send_new_data_node)
{
return;
}
else
{
assert(NULL == m_next_send_new_data_node->seq_list.head);
}
}
while (true)
{
assert(m_data_offset <= m_next_send_new_data_node->using_size);
seq_type max_sequence = m_next_send_new_data_node->first_sequence + m_next_send_new_data_node->using_size;
while (m_data_offset < m_next_send_new_data_node->using_size)
{
SeqNode * s_node = m_send_seq_pool.get_node();
TimeNode * t_node = m_send_time_pool.get_node();
if (NULL == s_node || NULL == t_node)
{
m_send_seq_pool.put_node(s_node);
m_send_time_pool.put_node(t_node);
return;
}
t_node->index = 1;
s_node->front_sequence = m_next_send_new_data_node->first_sequence + m_data_offset;
s_node->behind_sequence = min(max_sequence, s_node->front_sequence + 512);
assert(s_node->front_sequence < s_node->behind_sequence);
uint16_t region_size = (uint16_t)(s_node->behind_sequence - s_node->front_sequence);
send_rudp_package(s_node->front_sequence, t_node->index, m_next_send_new_data_node->data + m_data_offset, region_size);
t_node->time = getcurtime();
s_node->time_list.push_back(t_node);
m_next_send_new_data_node->seq_list.push_back(s_node);
++send_count;
++m_pending_count;
m_data_offset += region_size;
if (send_count >= m_max_send_count || m_pending_count >= m_max_pending_count)
{
return;
}
}
assert(m_data_offset == m_next_send_new_data_node->using_size);
if (0 == m_next_send_new_data_node->blank_size &&
NULL != m_next_send_new_data_node->next)
{
m_next_send_new_data_node = m_next_send_new_data_node->next;
m_data_offset = 0;
}
else
{
break;
}
}
assert(m_pending_count <= m_max_pending_count);
}
void Rudp::send_old_data(uint8_t & send_count)
{
if (send_count >= m_max_send_count)
{
return;
}
SendDataNode * last_data_node = m_last_send_old_data_node;
SeqNode * next_seq_node = m_next_send_old_seq_node;
if (NULL == last_data_node)
{
assert(NULL == next_seq_node);
last_data_node = m_send_data_list.head;
if (NULL == last_data_node)
{
return;
}
next_seq_node = last_data_node->seq_list.head;
if (NULL == next_seq_node)
{
return;
}
}
while (NULL != next_seq_node && send_count < m_max_send_count)
{
NodeLink<TimeNode> & time_list = next_seq_node->time_list;
assert(NULL != time_list.tail);
if (getcurtime() - time_list.tail->time > m_rtt.rto)
{
TimeNode * node = m_send_time_pool.get_node();
if (NULL == node)
{
return;
}
node->index = time_list.tail->index + 1;
if (0 == node->index)
{
time_list.clear();
node->index = 1;
}
assert(next_seq_node->front_sequence >= last_data_node->first_sequence);
assert(next_seq_node->front_sequence < next_seq_node->behind_sequence);
assert(next_seq_node->behind_sequence <= last_data_node->first_sequence + last_data_node->using_size);
uint16_t offset = next_seq_node->front_sequence - last_data_node->first_sequence;
uint16_t region_size = next_seq_node->behind_sequence - next_seq_node->front_sequence;
send_rudp_package(next_seq_node->front_sequence, node->index, last_data_node->data + offset, region_size);
node->time = getcurtime();
time_list.push_back(node);
++send_count;
}
next_seq_node = next_seq_node->next;
if (NULL == next_seq_node)
{
last_data_node = last_data_node->next;
if (NULL == last_data_node)
{
m_last_send_old_data_node = NULL;
m_next_send_old_seq_node = NULL;
break;
}
else
{
next_seq_node = last_data_node->seq_list.head;
}
}
}
m_next_send_old_seq_node = next_seq_node;
if (NULL == m_next_send_old_seq_node)
{
m_last_send_old_data_node = NULL;
}
else
{
m_last_send_old_data_node = last_data_node;
}
}
bool Rudp::send_rudp_package(seq_type front_sequence, uint8_t send_index, unsigned char * data, uint16_t len)
{
unsigned char buff[1024];
seq_type net_front_sequence = front_sequence;
uint8_t net_index = send_index;
big2little(&net_front_sequence, sizeof(seq_type));
big2little(&net_index, sizeof(uint8_t));
assert(len + 1 + sizeof(seq_type) + sizeof(uint8_t) <= 1024);
uint16_t send_len = 0;
buff[0] = (unsigned char)reliable_udp;
send_len += 1;
memcpy(buff + send_len, &net_front_sequence, sizeof(seq_type));
send_len += sizeof(seq_type);
memcpy(buff + send_len, &net_index, sizeof(uint8_t));
send_len += sizeof(uint8_t);
memcpy(buff + send_len, data, len);
send_len += len;
assert(send_len <= 576 - 20 - 8);
return(-1 != write(m_sockfd, buff, send_len));
}
bool Rudp::recv_ack(unsigned char * data, uint16_t len)
{
assert(m_pending_count <= m_max_pending_count);
if (0 != (len - sizeof(uint8_t) - sizeof(seq_type)) %
(sizeof(seq_type) + sizeof(uint16_t)))
{
assert(false);
return(false);
}
if (len - sizeof(uint8_t) - sizeof(seq_type) <
sizeof(seq_type) + sizeof(uint16_t))
{
assert(false);
return(false);
}
time_type ack_time = getcurtime();
uint8_t send_index = 0;
memcpy(&send_index, data, sizeof(uint8_t));
data += sizeof(uint8_t);
len -= sizeof(uint8_t);
big2little(&send_index, sizeof(uint8_t));
if (0 == send_index)
{
assert(false);
return(false);
}
SendDataNode * sd_node = m_send_data_list.head;
if (NULL == sd_node)
{
return(true);
}
bool first_loop = true;
while (NULL != sd_node)
{
seq_type front_sequence = 0;
uint16_t region_size = 0;
memcpy(&front_sequence, data, sizeof(seq_type));
data += sizeof(seq_type);
len -= sizeof(seq_type);
memcpy(®ion_size, data, sizeof(uint16_t));
data += sizeof(uint16_t);
len -= sizeof(uint16_t);
big2little(&front_sequence, sizeof(seq_type));
big2little(®ion_size, sizeof(uint16_t));
if (front_sequence + region_size <= front_sequence)
{
assert(false);
return(false);
}
int relation = 0;
while (NULL != sd_node)
{
relation = sd_node->get_relation(front_sequence, region_size);
if (relation < 0)
{
sd_node = sd_node->next;
}
else
{
break;
}
}
if (0 == relation)
{
SeqNode node(&m_send_time_pool);
node.front_sequence = front_sequence;
node.behind_sequence = front_sequence + region_size;
SeqNode * s_node = sd_node->find_seq_node(&node);
if (NULL != s_node)
{
TimeNode * t_node = s_node->find_time_node(send_index);
if (NULL != t_node)
{
if (first_loop)
{
m_rtt.update(ack_time - t_node->time);
}
if (s_node == m_next_send_old_seq_node)
{
m_next_send_old_seq_node = m_next_send_old_seq_node->next;
if (NULL == m_next_send_old_seq_node)
{
m_last_send_old_data_node = m_last_send_old_data_node->next;
if (NULL != m_last_send_old_data_node)
{
m_next_send_old_seq_node = m_last_send_old_data_node->seq_list.head;
if (NULL == m_next_send_old_seq_node)
{
m_last_send_old_data_node = NULL;
}
}
}
}
sd_node->seq_list.erase(s_node);
--m_pending_count;
}
}
}
if (len < sizeof(seq_type) + sizeof(uint16_t))
{
break;
}
if (first_loop)
{
sd_node = m_send_data_list.head;
first_loop = false;
}
}
if (sizeof(seq_type) != len)
{
assert(false);
return(false);
}
seq_type min_recved_sequence = 0;
memcpy(&min_recved_sequence, data, sizeof(seq_type));
big2little(&min_recved_sequence, sizeof(seq_type));
sd_node = m_send_data_list.head;
while (NULL != sd_node && 0 == sd_node->blank_size &&
sd_node->first_sequence + sd_node->using_size <= min_recved_sequence)
{
if (sd_node == m_last_send_old_data_node)
{
m_last_send_old_data_node = m_last_send_old_data_node->next;
if (NULL == m_last_send_old_data_node)
{
m_next_send_old_seq_node = NULL;
}
else
{
m_next_send_old_seq_node = m_last_send_old_data_node->seq_list.head;
if (NULL == m_next_send_old_seq_node)
{
m_last_send_old_data_node = NULL;
}
}
}
if (sd_node == m_next_send_new_data_node)
{
assert(m_data_offset == m_next_send_new_data_node->using_size);
m_next_send_new_data_node = m_next_send_new_data_node->next;
m_data_offset = 0;
}
m_pending_count -= sd_node->seq_list.size;
m_send_data_list.erase(sd_node);
sd_node = m_send_data_list.head;
}
if (NULL == sd_node || sd_node->first_sequence >= min_recved_sequence)
{
return(true);
}
SeqNode * s_node = sd_node->seq_list.head;
while (NULL != s_node && s_node->behind_sequence <= min_recved_sequence)
{
if (s_node == m_next_send_old_seq_node)
{
m_next_send_old_seq_node = m_next_send_old_seq_node->next;
if (NULL == m_next_send_old_seq_node)
{
m_last_send_old_data_node = m_last_send_old_data_node->next;
if (NULL != m_last_send_old_data_node)
{
m_next_send_old_seq_node = m_last_send_old_data_node->seq_list.head;
if (NULL == m_next_send_old_seq_node)
{
m_last_send_old_data_node = NULL;
}
}
}
}
sd_node->seq_list.erase(s_node);
s_node = sd_node->seq_list.head;
--m_pending_count;
}
assert(m_pending_count <= m_max_pending_count);
return(true);
}
bool Rudp::store_recv_data(unsigned char * data, uint16_t len)
{
assert(len > sizeof(seq_type) + sizeof(uint8_t));
RecvDataNode * node = m_recv_data_pool.get_node();
if (NULL == node)
{
return(false);
}
seq_type front_sequence = 0;
uint8_t send_index = 0;
memcpy(&front_sequence, data, sizeof(seq_type));
data += sizeof(seq_type);
len -= sizeof(seq_type);
memcpy(&send_index, data, sizeof(uint8_t));
data += sizeof(uint8_t);
len -= sizeof(uint8_t);
big2little(&front_sequence, sizeof(seq_type));
big2little(&send_index, sizeof(uint8_t));
assert(len > 0);
seq_type min_sequence = front_sequence / node->recv_node_block_size * node->recv_node_block_size;
seq_type max_sequence = min_sequence + node->recv_node_block_size;
assert(min_sequence < max_sequence);
if (front_sequence + len <= min_sequence ||
front_sequence + len > max_sequence)
{
assert(false);
m_recv_data_pool.put_node(node);
return(false);
}
int ret = update_recv_region(front_sequence, len);
if (-1 == ret)
{
m_recv_data_pool.put_node(node);
return(false);
}
update_ack_nodes(front_sequence, len);
if (0 == ret)
{
m_recv_data_pool.put_node(node);
send_ack(send_index);
return(true);
}
RecvDataNode * p_node = NULL;
RecvDataNode * rd_node = m_recv_data_list.head;
while (NULL != rd_node && min_sequence >= rd_node->max_sequence)
{
p_node = rd_node;
rd_node = rd_node->next;
}
if (NULL == rd_node)
{
rd_node = node;
m_recv_data_list.push_back(node);
rd_node->min_sequence = min_sequence;
rd_node->max_sequence = max_sequence;
}
else
{
if (max_sequence <= rd_node->min_sequence)
{
rd_node = node;
if (NULL == p_node)
{
m_recv_data_list.push_front(node);
}
else
{
m_recv_data_list.push_after(p_node, node);
}
rd_node->min_sequence = min_sequence;
rd_node->max_sequence = max_sequence;
}
else
{
assert(min_sequence == rd_node->min_sequence &&
max_sequence == rd_node->max_sequence);
m_recv_data_pool.put_node(node);
}
}
uint16_t offset = front_sequence - rd_node->min_sequence;
memcpy(rd_node->data + offset, data, len);
send_ack(send_index);
return(true);
}
void Rudp::update_ack_nodes(seq_type front_sequence, uint16_t region_size)
{
assert(front_sequence + region_size > front_sequence);
int del_count = 0;
for (int index = 0; index < m_ack_node_count; ++index)
{
AckRegion & check_region = m_ack_node[index];
if (4 == check_region.count)
{
++del_count;
continue;
}
if (m_min_need_sequence >= check_region.front_sequence + check_region.region_size)
{
check_region.count = 4;
++del_count;
continue;
}
if (del_count > 0)
{
AckRegion & modify_region = m_ack_node[index - del_count];
modify_region = check_region;
check_region.count = 4;
}
}
m_ack_node_count -= del_count;
assert(m_ack_node_count >= 0 && m_ack_node_count < 4);
bool need_move = true;
m_new_ack_node_position = 0;
while (m_new_ack_node_position < m_ack_node_count)
{
AckRegion & check_region = m_ack_node[m_new_ack_node_position];
if (check_region.front_sequence < front_sequence)
{
++m_new_ack_node_position;
++check_region.count;
continue;
}
if (check_region.front_sequence == front_sequence)
{
check_region.count = 1;
need_move = false;
}
break;
}
for (int index = m_ack_node_count - 1; index >= m_new_ack_node_position; --index)
{
AckRegion & move_region = m_ack_node[index];
++move_region.count;
if (need_move)
{
m_ack_node[index + 1] = move_region;
}
}
if (need_move)
{
AckRegion & modify_region = m_ack_node[m_new_ack_node_position];
modify_region.front_sequence = front_sequence;
modify_region.region_size = region_size;
modify_region.count = 1;
++m_ack_node_count;
}
}
int Rudp::update_recv_region(seq_type front_sequence, uint16_t region_size)
{
seq_type behind_sequence = front_sequence + region_size;
if (front_sequence >= behind_sequence)
{
assert(false);
return(-1);
}
if (behind_sequence <= m_min_need_sequence)
{
return(0);
}
RegionNode * p_node = NULL;
RegionNode * r_node = m_region_list.head;
while (NULL != r_node && front_sequence > r_node->behind_sequence)
{
p_node = r_node;
r_node = r_node->next;
}
if (NULL == r_node || behind_sequence < r_node->front_sequence)
{
if (front_sequence <= m_min_need_sequence)
{
m_min_need_sequence = behind_sequence;
return(1);
}
RegionNode * node = m_region_pool.get_node();
if (NULL == node)
{
return(-1);
}
node->front_sequence = front_sequence;
node->behind_sequence = behind_sequence;
if (NULL == r_node)
{
m_region_list.push_back(node);
}
else
{
if (NULL == p_node)
{
m_region_list.push_front(node);
}
else
{
m_region_list.push_after(p_node, node);
}
}
return(1);
}
if (r_node->front_sequence > front_sequence)
{
r_node->front_sequence = front_sequence;
}
if (r_node->behind_sequence < behind_sequence)
{
r_node->behind_sequence = behind_sequence;
}
RegionNode * n_node = r_node->next;
while (NULL != n_node && r_node->behind_sequence >= n_node->front_sequence)
{
if (r_node->behind_sequence < n_node->behind_sequence)
{
r_node->behind_sequence = n_node->behind_sequence;
}
m_region_list.erase(n_node);
n_node = r_node->next;
}
RegionNode * h_node = m_region_list.head;
if (m_min_need_sequence >= h_node->front_sequence)
{
assert(h_node == r_node);
assert(m_min_need_sequence < h_node->behind_sequence);
m_min_need_sequence = h_node->behind_sequence;
m_region_list.erase(h_node);
}
return(1);
}
bool Rudp::send_ack(uint8_t send_index)
{
unsigned char buff[1024];
big2little(&send_index, sizeof(uint8_t));
uint16_t send_len = 0;
buff[0] = (unsigned char)ack_message;
send_len += 1;
memcpy(buff + send_len, &send_index, sizeof(uint8_t));
send_len += sizeof(uint8_t);
assert(m_new_ack_node_position >= 0 && m_new_ack_node_position < m_ack_node_count);
AckRegion * a_node = &m_ack_node[m_new_ack_node_position];
seq_type front_sequence = a_node->front_sequence;
uint16_t region_size = a_node->region_size;
big2little(&front_sequence, sizeof(seq_type));
big2little(®ion_size, sizeof(uint16_t));
memcpy(buff + send_len, &front_sequence, sizeof(seq_type));
send_len += sizeof(seq_type);
memcpy(buff + send_len, ®ion_size, sizeof(uint16_t));
send_len += sizeof(uint16_t);
for (int index = 0; index < m_ack_node_count; ++index)
{
if (index != m_new_ack_node_position)
{
a_node = &m_ack_node[index];
front_sequence = a_node->front_sequence;
region_size = a_node->region_size;
big2little(&front_sequence, sizeof(seq_type));
big2little(®ion_size, sizeof(uint16_t));
memcpy(buff + send_len, &front_sequence, sizeof(seq_type));
send_len += sizeof(seq_type);
memcpy(buff + send_len, ®ion_size, sizeof(uint16_t));
send_len += sizeof(uint16_t);
}
}
seq_type min_need_sequence = m_min_need_sequence;
big2little(&min_need_sequence, sizeof(seq_type));
memcpy(buff + send_len, &min_need_sequence, sizeof(seq_type));
send_len += sizeof(seq_type);
assert(send_len <= 576 - 20 - 8);
return(-1 != write(m_sockfd, buff, send_len));
}
bool Rudp::analytic_data()
{
lock_recver();
bool ret = do_analytic_data();
unlock_recver();
return(ret);
}
bool Rudp::do_analytic_data()
{
if (m_min_need_sequence - m_max_read_sequence < m_need_analytic_data_len)
{
return(true);
}
unsigned char buff[65535];
uint16_t offset = 0;
uint16_t len = 0;
RecvDataNode * rd_node = NULL;
while (m_min_need_sequence - m_max_read_sequence >= m_need_analytic_data_len)
{
if (0 == len)
{
rd_node = m_recv_data_list.head;
if (NULL == rd_node ||
m_max_read_sequence < rd_node->min_sequence ||
m_max_read_sequence >= rd_node->max_sequence)
{
assert(false);
exit(1);
return(false);
}
offset = m_max_read_sequence - rd_node->min_sequence;
len = min(rd_node->max_sequence, m_min_need_sequence) - m_max_read_sequence;
}
if (len < m_need_analytic_data_len)
{
memcpy(buff, rd_node->data + offset, len);
m_max_read_sequence += len;
uint16_t left_len = m_need_analytic_data_len - len;
while (left_len > 0)
{
m_recv_data_list.erase(rd_node);
rd_node = m_recv_data_list.head;
if (NULL == rd_node ||
m_max_read_sequence != rd_node->min_sequence)
{
assert(false);
exit(1);
return(false);
}
len = min(rd_node->max_sequence, m_min_need_sequence) - m_max_read_sequence;
uint16_t write_len = min(len, left_len);
memcpy(buff + m_need_analytic_data_len - left_len, rd_node->data, write_len);
offset = write_len;
len -= write_len;
m_max_read_sequence += write_len;
left_len -= write_len;
}
}
else
{
memcpy(buff, rd_node->data + offset, m_need_analytic_data_len);
offset += m_need_analytic_data_len;
len -= m_need_analytic_data_len;
m_max_read_sequence += m_need_analytic_data_len;
}
if (m_turn_to_analytic_len)
{
assert(sizeof(uint16_t) == m_need_analytic_data_len);
uint16_t data_len = 0;
memcpy(&data_len, buff, m_need_analytic_data_len);
big2little(&data_len, m_need_analytic_data_len);
m_need_analytic_data_len = data_len;
}
else
{
m_rudp_mgr->handle_data(m_unique_id, buff, m_need_analytic_data_len);
m_need_analytic_data_len = sizeof(uint16_t);
}
m_turn_to_analytic_len = !m_turn_to_analytic_len;
if (m_max_read_sequence == rd_node->max_sequence)
{
assert(0 == len);
m_recv_data_list.erase(rd_node);
}
}
return(true);
}
rudpmgr.h:
#ifndef __RUDP_MANAGER_H__
#define __RUDP_MANAGER_H__
#include <map>
#include <vector>
#include <string>
using std::map;
using std::vector;
using std::string;
#include <cassert>
#include <cstdlib>
#include <pthread.h>
#include <sys/select.h>
#include "types.h"
#include "lock.h"
class Rudp;
class RudpMgrSink;
class RudpMgr
{
public:
RudpMgr(uint16_t port = 0);
~RudpMgr();
void set_sink(RudpMgrSink * sink);
void run();
bool send_data(uint32_t conn, unsigned char * data, uint16_t len, bool reliable);
bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);
void create_rudp(const char * host, uint16_t port);
void destroy_rudp(uint32_t unique_id);
int recv_data_thread();
int send_data_thread();
int handle_data_thread();
private:
void destroy_rudp(uint32_t unique_id, bool is_locked);
private:
struct sock_rudp
{
int connfd;
Rudp * prudp;
};
RudpMgrSink * m_rudp_mgr_sink;
int m_listenfd;
int m_maxrfdp1;
fd_set m_rset;
bool m_is_running;
pthread_t m_recv_thread;
pthread_t m_send_thread;
pthread_t m_handle_thread;
MutexLocker m_mutex_locker;
RWLocker m_rw_locker;
uint32_t m_unique_id_creator;
vector<uint32_t> m_unique_id_vector;
map<string, int> m_address_socket_map;
vector<sock_rudp> m_sock_rudp_vector;
};
#endif
rudpmgr.cpp:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include "common.h"
#include "rudp.h"
#include "rudpmgrsink.h"
#include "rudpmgr.h"
static void * recv_data_func(void * arg)
{
RudpMgr * mgr = (RudpMgr *)arg;
int ret = mgr->recv_data_thread();
return((void *)ret);
}
static void * send_data_func(void * arg)
{
RudpMgr * mgr = (RudpMgr *)arg;
int ret = mgr->send_data_thread();
return((void *)ret);
}
static void * handle_data_func(void * arg)
{
RudpMgr * mgr = (RudpMgr *)arg;
int ret = mgr->handle_data_thread();
return((void *)ret);
}
static bool readable_timeout(int sockfd, int sec)
{
fd_set rset;
struct timeval tv;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
tv.tv_sec = sec;
tv.tv_usec = 0;
return(select(sockfd + 1, &rset, NULL, NULL, &tv) > 0);
}
RudpMgr::RudpMgr(uint16_t port)
: m_rudp_mgr_sink(NULL), m_listenfd(-1), m_maxrfdp1(-1), m_is_running(false), m_unique_id_creator(0)
{
m_unique_id_creator = (uint32_t)rand();
FD_ZERO(&m_rset);
/* client */
if (0 == port)
{
return;
}
/* server */
if (-1 == (m_listenfd = socket(AF_INET, SOCK_DGRAM, 0)))
{
perror("socket error");
exit(1);
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
if (-1 == bind(m_listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
{
perror("bind error");
exit(1);
}
FD_SET(m_listenfd, &m_rset);
m_maxrfdp1 = m_listenfd + 1;
}
RudpMgr::~RudpMgr()
{
if (m_is_running)
{
int error_no = 0;
if (0 != (error_no = pthread_cancel(m_recv_thread)))
{
printf("pthread_cancel recv_thread error: %s\n", strerror(error_no));
}
if (0 != (error_no = pthread_cancel(m_send_thread)))
{
printf("pthread_cancel send_thread error: %s\n", strerror(error_no));
}
if (0 != (error_no = pthread_cancel(m_handle_thread)))
{
printf("pthread_cancel handle_thread error: %s\n", strerror(error_no));
}
sleep(1);
}
if (-1 != m_listenfd)
{
close(m_listenfd);
}
m_rw_locker.wrlock();
vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
while (m_sock_rudp_vector.end() != vsr_iter)
{
close(vsr_iter->connfd);
delete vsr_iter->prudp;
++vsr_iter;
}
m_sock_rudp_vector.clear();
m_rw_locker.unlock();
}
void RudpMgr::set_sink(RudpMgrSink * sink)
{
if (NULL == (m_rudp_mgr_sink = sink))
{
printf("rudp manager sink must been set\n");
exit(1);
}
}
void RudpMgr::run()
{
int error_no = 0;
if (0 != (error_no = pthread_create(&m_recv_thread, NULL, recv_data_func, this)))
{
printf("pthread_create recv_data_thread error: %s\n", strerror(error_no));
exit(1);
}
if (0 != (error_no = pthread_create(&m_send_thread, NULL, send_data_func, this)))
{
printf("pthread_create recv_data_thread error: %s\n", strerror(error_no));
exit(1);
}
if (0 != (error_no = pthread_create(&m_handle_thread, NULL, handle_data_func, this)))
{
printf("pthread_create recv_data_thread error: %s\n", strerror(error_no));
exit(1);
}
m_is_running = true;
}
bool RudpMgr::send_data(uint32_t unique_id, unsigned char * data, uint16_t len, bool reliable)
{
m_rw_locker.rdlock();
Rudp * prudp = NULL;
vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
while (m_sock_rudp_vector.end() != vsr_iter)
{
if (NULL != vsr_iter->prudp && vsr_iter->prudp->get_unique_id() == unique_id)
{
prudp = vsr_iter->prudp;
break;
}
}
bool ret = (NULL != prudp && prudp->send_data(data, len, reliable));
m_rw_locker.unlock();
return(ret);
}
bool RudpMgr::handle_data(uint32_t unique_id, unsigned char * data, uint16_t len)
{
assert(NULL != m_rudp_mgr_sink);
return(NULL != m_rudp_mgr_sink && m_rudp_mgr_sink->handle_data(unique_id, data, len));
}
void RudpMgr::create_rudp(const char * host, uint16_t port)
{
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
if (inet_pton(AF_INET, host, &servaddr.sin_addr) <= 0)
{
perror("inet_pton error");
exit(1);
}
int connfd = -1;
if (-1 == (connfd = socket(AF_INET, SOCK_DGRAM, 0)))
{
perror("socket error");
exit(1);
}
if (-1 == connect(connfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
{
perror("connect error");
exit(1);
}
int send_times = 30;
while (--send_times >= 0)
{
if (-1 == write(connfd, NULL, 0))
{
perror("write error");
exit(1);
}
if (readable_timeout(connfd, 1))
{
break;
}
}
if (send_times < 0)
{
printf("can not connect to server, maybe it is too busy)\n");
exit(1);
}
const int buff_size = 576;
char buff[buff_size];
int pkg_size = 0;
if (-1 == (pkg_size = read(connfd, buff, buff_size - 1)))
{
perror("read error");
if (ECONNREFUSED == errno)
{
printf("server maybe terminated\n");
}
exit(1);
}
buff[pkg_size] = '\0';
char * ptr = strrchr(buff, ':');
if (NULL == ptr)
{
printf("recv exception address message: %s\n", buff);
exit(1);
}
*ptr = '\0';
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(ptr + 1));
if (inet_pton(AF_INET, buff, &servaddr.sin_addr) <= 0)
{
perror("inet_pton error");
exit(1);
}
if (-1 == connect(connfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
{
perror("connect error");
exit(1);
}
m_mutex_locker.lock();
uint32_t unique_id = 0;
if (m_unique_id_vector.size() >= m_unique_id_vector.max_size() - 1)
{
printf("can not support more rudp\n");
exit(1);
}
do
{
unique_id = m_unique_id_creator++;
} while (0 == unique_id ||
m_unique_id_vector.end() !=
find(m_unique_id_vector.begin(), m_unique_id_vector.end(), unique_id));
Rudp * prudp = new Rudp(this, connfd, unique_id);
if (NULL == prudp)
{
printf("new rudp failed\n");
exit(1);
}
m_unique_id_vector.push_back(unique_id);
m_mutex_locker.unlock();
sock_rudp sr = { connfd, prudp };
m_rw_locker.wrlock();
m_sock_rudp_vector.push_back(sr);
m_rw_locker.unlock();
FD_SET(connfd, &m_rset);
if (m_maxrfdp1 < connfd + 1)
{
m_maxrfdp1 = connfd + 1;
}
assert(NULL != m_rudp_mgr_sink);
if (NULL != m_rudp_mgr_sink)
{
m_rudp_mgr_sink->onconnect(unique_id);
}
}
void RudpMgr::destroy_rudp(uint32_t unique_id)
{
destroy_rudp(unique_id, false);
}
void RudpMgr::destroy_rudp(uint32_t unique_id, bool is_locked)
{
int connfd = -1;
if (!is_locked)
{
m_rw_locker.wrlock();
}
vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
while (m_sock_rudp_vector.end() != vsr_iter)
{
if (NULL != vsr_iter->prudp && vsr_iter->prudp->get_unique_id() == unique_id)
{
connfd = vsr_iter->connfd;
FD_CLR(connfd, &m_rset);
close(connfd);
delete vsr_iter->prudp;
m_sock_rudp_vector.erase(vsr_iter);
break;
}
else
{
++vsr_iter;
}
}
if (!is_locked)
{
m_rw_locker.unlock();
}
if (-1 == connfd)
{
return;
}
m_mutex_locker.lock();
map<string, int>::iterator msi_iter = m_address_socket_map.begin();
while (m_address_socket_map.end() != msi_iter)
{
if (msi_iter->second == connfd)
{
m_address_socket_map.erase(msi_iter);
break;
}
else
{
++msi_iter;
}
}
vector<uint32_t>::iterator vu_iter = find(m_unique_id_vector.begin(), m_unique_id_vector.end(), unique_id);
if (m_unique_id_vector.end() != vu_iter)
{
m_unique_id_vector.erase(vu_iter);
}
m_mutex_locker.unlock();
assert(NULL != m_rudp_mgr_sink);
if (NULL != m_rudp_mgr_sink)
{
m_rudp_mgr_sink->ondisconnect(unique_id);
}
}
int RudpMgr::recv_data_thread()
{
const int buff_size = 65535;
char buff[buff_size];
int pkg_size = 0;
while (true)
{
if (m_maxrfdp1 <= 0)
{
sleep(1);
continue;
}
int nready = 0;
fd_set rset = m_rset;
if (-1 == (nready = select(m_maxrfdp1, &rset, NULL, NULL, NULL)))
{
if (EINTR == errno)
{
continue;
}
else
{
perror("select error");
exit(1);
}
}
if (-1 != m_listenfd && FD_ISSET(m_listenfd, &rset))
{
struct sockaddr_in peer_addr;
socklen_t peer_len = sizeof(peer_addr);
if (-1 == (pkg_size = recvfrom(m_listenfd, buff, buff_size, 0,
(struct sockaddr *)&peer_addr, &peer_len)))
{
perror("recvfrom error");
exit(1);
}
const char * paddr = NULL;
if (NULL == (paddr = inet_ntoa(peer_addr.sin_addr)))
{
perror("inet_ntoa error");
exit(1);
}
snprintf(buff, buff_size, "%s:%d", paddr, ntohs(peer_addr.sin_port));
string peer_address(buff);
int connfd = -1;
m_mutex_locker.lock();
map<string, int>::iterator msi_iter = m_address_socket_map.find(peer_address);
if (m_address_socket_map.end() == msi_iter)
{
if (-1 == (connfd = socket(AF_INET, SOCK_DGRAM, 0)))
{
perror("socket error");
exit(1);
}
if (-1 == connect(connfd, (struct sockaddr *)&peer_addr, peer_len))
{
perror("connect error");
exit(1);
}
uint32_t unique_id = 0;
if (m_unique_id_vector.size() >= m_unique_id_vector.max_size() - 1)
{
printf("can not create more Rudp\n");
exit(1);
}
do
{
unique_id = m_unique_id_creator++;
} while (0 == unique_id ||
m_unique_id_vector.end() !=
find(m_unique_id_vector.begin(), m_unique_id_vector.end(), unique_id));
Rudp * prudp = new Rudp(this, connfd, unique_id);
if (NULL == prudp)
{
printf("new rudp failed\n");
exit(1);
}
m_unique_id_vector.push_back(unique_id);
m_address_socket_map[peer_address] = connfd;
m_mutex_locker.unlock();
sock_rudp sr = { connfd, prudp };
m_rw_locker.wrlock();
m_sock_rudp_vector.push_back(sr);
m_rw_locker.unlock();
FD_SET(connfd, &m_rset);
if (m_maxrfdp1 < connfd + 1)
{
m_maxrfdp1 = connfd + 1;
}
assert(NULL != m_rudp_mgr_sink);
if (NULL != m_rudp_mgr_sink)
{
m_rudp_mgr_sink->onconnect(unique_id);
}
}
else
{
connfd = msi_iter->second;
m_mutex_locker.unlock();
assert(-1 != connfd);
}
struct sockaddr_in local_addr;
socklen_t local_len = sizeof(local_addr);
if (-1 == getsockname(connfd, (struct sockaddr *)&local_addr, &local_len))
{
perror("getsockname error");
exit(1);
}
if (NULL == (paddr = inet_ntoa(local_addr.sin_addr)))
{
perror("inet_ntoa error");
exit(1);
}
snprintf(buff, buff_size, "%s:%d", paddr, ntohs(local_addr.sin_port));
pkg_size = strlen(buff);
if (-1 == sendto(m_listenfd, buff, pkg_size, 0, (struct sockaddr *)&peer_addr, peer_len))
{
perror("sendto error");
exit(1);
}
if (--nready <= 0)
{
continue;
}
}
m_rw_locker.rdlock();
vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
while (m_sock_rudp_vector.end() != vsr_iter)
{
int connfd = vsr_iter->connfd;
Rudp * prudp = vsr_iter->prudp;
if (connfd < 0 || NULL == prudp)
{
assert(false);
exit(1);
}
if (FD_ISSET(connfd, &rset))
{
if (-1 == (pkg_size = read(connfd, buff, buff_size)))
{
prudp->kill();
}
else
{
prudp->recv_data((unsigned char *)buff, pkg_size);
}
if (--nready <= 0)
{
break;
}
}
++vsr_iter;
}
m_rw_locker.unlock();
}
return(0);
}
int RudpMgr::send_data_thread()
{
time_type last_send_heart_beat_time = getcurtime();
while (true)
{
bool need_send_heart_beat_package = false;
if (getcurtime() - last_send_heart_beat_time >= 1000)
{
need_send_heart_beat_package = true;
last_send_heart_beat_time = getcurtime();
}
fd_set wset;
FD_ZERO(&wset);
int maxwfdp1 = -1;
m_rw_locker.wrlock();
for (int index = m_sock_rudp_vector.size() - 1; index >= 0; --index)
{
sock_rudp & sr = m_sock_rudp_vector[index];
int connfd = sr.connfd;
Rudp * prudp = sr.prudp;
if (connfd < 0 || NULL == prudp)
{
assert(false);
exit(1);
}
if (!prudp->is_alive())
{
destroy_rudp(prudp->get_unique_id(), true);
continue;
}
if (need_send_heart_beat_package)
{
prudp->send_heart_beat_package();
}
if (prudp->has_data_to_send())
{
FD_SET(connfd, &wset);
if (maxwfdp1 < connfd + 1)
{
maxwfdp1 = connfd + 1;
}
}
}
m_rw_locker.unlock();
if (maxwfdp1 <= 0)
{
sleep(1);
continue;
}
int nready = 0;
if (-1 == (nready = select(maxwfdp1, NULL, &wset, NULL, NULL)))
{
if (EINTR == errno)
{
continue;
}
else
{
perror("select error");
exit(1);
}
}
m_rw_locker.rdlock();
vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
while (m_sock_rudp_vector.end() != vsr_iter)
{
int connfd = vsr_iter->connfd;
Rudp * prudp = vsr_iter->prudp;
if (connfd < 0 || NULL == prudp)
{
assert(false);
exit(1);
}
if (FD_ISSET(connfd, &wset))
{
prudp->send_data();
if (--nready <= 0)
{
break;
}
}
++vsr_iter;
}
m_rw_locker.unlock();
}
return(0);
}
int RudpMgr::handle_data_thread()
{
while (true)
{
m_rw_locker.rdlock();
vector<sock_rudp>::iterator vsr_iter = m_sock_rudp_vector.begin();
while (m_sock_rudp_vector.end() != vsr_iter)
{
int connfd = vsr_iter->connfd;
Rudp * prudp = vsr_iter->prudp;
if (connfd < 0 || NULL == prudp)
{
assert(false);
exit(1);
}
prudp->analytic_data();
++vsr_iter;
}
m_rw_locker.unlock();
}
return(0);
}
rudpmgrsink.h:
#ifndef __RUDP_MANAGER_SINK_H__
#define __RUDP_MANAGER_SINK_H__
#include "types.h"
class RudpMgr;
class RudpMgrSink
{
public:
RudpMgrSink(RudpMgr * mgr);
virtual ~RudpMgrSink();
public:
void create_rudp(const char * host, uint16_t port);
void destroy_rudp(uint32_t unique_id);
bool send_data(uint32_t unique_id, unsigned char * data, uint16_t len, bool reliable);
public:
virtual void onconnect(uint32_t unique_id);
virtual void ondisconnect(uint32_t unique_id);
virtual bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);
private:
RudpMgr * m_rudp_mgr;
};
#endif
rudpmgrsink.cpp:
#include <cstdio>
#include <cstdlib>
#include "types.h"
#include "rudpmgr.h"
#include "rudpmgrsink.h"
RudpMgrSink::RudpMgrSink(RudpMgr * mgr) : m_rudp_mgr(mgr)
{
if (NULL == m_rudp_mgr)
{
printf("rudp manager must been set\n");
exit(1);
}
m_rudp_mgr->set_sink(this);
}
RudpMgrSink::~RudpMgrSink()
{
}
void RudpMgrSink::create_rudp(const char * host, uint16_t port)
{
if (NULL != m_rudp_mgr)
{
m_rudp_mgr->create_rudp(host, port);
}
}
void RudpMgrSink::destroy_rudp(uint32_t unique_id)
{
if (NULL != m_rudp_mgr)
{
m_rudp_mgr->destroy_rudp(unique_id);
}
}
bool RudpMgrSink::send_data(uint32_t unique_id, unsigned char * data, uint16_t len, bool reliable)
{
return(NULL != m_rudp_mgr && m_rudp_mgr->send_data(unique_id, data, len, reliable));
}
void RudpMgrSink::onconnect(uint32_t unique_id)
{
}
void RudpMgrSink::ondisconnect(uint32_t unique_id)
{
}
bool RudpMgrSink::handle_data(uint32_t conn, unsigned char * data, uint16_t len)
{
return(true);
}
test.cpp:
#include <cstdio>
#include <unistd.h>
#include "rudpmgr.h"
#include "rudpmgrsink.h"
class Sink : public RudpMgrSink
{
public:
Sink(RudpMgr * mgr) : RudpMgrSink(mgr)
{
}
};
int main()
{
RudpMgr * p = new RudpMgr;
Sink s(p);
p->run();
sleep(1);
delete p;
printf("fine\n");
return(0);
}
makefile_test:
objects=test.o rudpmgr.o rudp.o rudpmgrsink.o common.o lock.o
test:$(objects)
g++ -o test $(objects) -lpthread
test.o:test.cpp rudpmgr.h rudpmgrsink.h
g++ -c test.cpp
rudpmgr.o:rudpmgr.cpp rudpmgr.h rudp.h rudpmgrsink.h types.h common.h lock.h
g++ -c rudpmgr.cpp
rudp.o:rudp.cpp rudp.h rudpmgr.h nodes.hpp lock.h
g++ -c rudp.cpp
rudpmgrsink.o:rudpmgrsink.cpp rudpmgrsink.h rudpmgr.h types.h
g++ -c rudpmgrsink.cpp
common.o:common.cpp common.h types.h
g++ -c common.cpp
lock.o:lock.cpp lock.h
g++ -c lock.cpp
rebuild:clean test
clean:
-rm test $(objects)
command.h:
#ifndef __COMMAND_H__
#define __COMMAND_H__
enum
{
cmd_reverse
};
#endif
testclient.h:
#ifndef __TEST_CLIENT_H__
#define __TEST_CLIENT_H__
#include <string>
using std::string;
#include "command.h"
#include "rudpmgrsink.h"
class TestClient : public RudpMgrSink
{
public:
TestClient(RudpMgr * mgr, const char * host, uint16_t port);
virtual ~TestClient();
public:
virtual void onconnect(uint32_t unique_id);
virtual void ondisconnect(uint32_t unique_id);
virtual bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);
public:
bool handle_reverse_string_response(unsigned char * data, uint16_t len);
public:
bool send_reverse_string_request(const char * str);
private:
string m_host;
uint16_t m_port;
uint32_t m_unique_id;
};
#endif
testclient.cpp:
#include <cstdio>
#include <cassert>
#include <cstring>
#include "testclient.h"
TestClient::TestClient(RudpMgr * mgr, const char * host, uint16_t port)
: RudpMgrSink(mgr), m_host(host), m_port(port), m_unique_id(0)
{
create_rudp(m_host.c_str(), m_port); /* connect to host:port */
}
TestClient::~TestClient()
{
if (0 != m_unique_id)
{
destroy_rudp(m_unique_id); /* disconnect with host:port */
}
}
void TestClient::onconnect(uint32_t unique_id)
{
if (0 == m_unique_id)
{
m_unique_id = unique_id; /* get connection handle */
}
else
{
assert(false);
destroy_rudp(unique_id); /* disconnect with unknown peer */
}
}
void TestClient::ondisconnect(uint32_t unique_id)
{
if (m_unique_id == unique_id)
{
m_unique_id = 0;
create_rudp(m_host.c_str(), m_port); /* reconnect to host:port */
}
}
bool TestClient::handle_data(uint32_t unique_id, unsigned char * data, uint16_t len)
{
unsigned char cmd = data[0];
data += 1;
len -= 1;
switch (cmd)
{
case cmd_reverse:
{
return(handle_reverse_string_response(data, len));
}
default:
{
return(false);
}
}
}
bool TestClient::handle_reverse_string_response(unsigned char * data, uint16_t len)
{
fprintf(stderr, "reverse string: %s\n", (char *)data);
return(true);
}
bool TestClient::send_reverse_string_request(const char * str)
{
if (0 == m_unique_id)
{
create_rudp(m_host.c_str(), m_port); /* connect to host:port */
return(false);
}
uint16_t len = strlen(str);
if (len > 65535 - sizeof(unsigned char) + sizeof(uint16_t))
{
return(false);
}
unsigned char buff[65535];
buff[0] = (unsigned char)cmd_reverse;
memcpy(buff + 1, str, len + 1);
len += 2;
return(send_data(m_unique_id, buff, len, true));
}
client.cpp:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <errno.h>
#include <unistd.h>
#include "rudpmgr.h"
#include "testclient.h"
int main()
{
RudpMgr * prudpmgr = new RudpMgr();
TestClient client(prudpmgr, "127.0.0.1", 10000);
prudpmgr->run();
char buff[4096] = { 0 };
while (fgets(buff, 4095, stdin) != NULL)
{
int len = strlen(buff);
if (len > 0 && ('\r' == buff[len - 1] || '\n' == buff[len - 1]))
{
buff[len - 1] = '\0';
}
client.send_reverse_string_request(buff);
}
if (ferror(stdin)) {
perror("fget error");
exit(1);
}
sleep(5);
delete prudpmgr;
printf("test over\n");
return(0);
}
makefile_client:
objects=client.o testclient.o rudpmgr.o rudp.o rudpmgrsink.o common.o lock.o
client:$(objects)
g++ -o client $(objects) -lpthread
client.o:client.cpp rudpmgr.h testclient.h
g++ -c client.cpp
testclient.o:testclient.cpp testclient.h
g++ -c testclient.cpp
rudpmgr.o:rudpmgr.cpp rudpmgr.h rudp.h rudpmgrsink.h types.h common.h lock.h
g++ -c rudpmgr.cpp
rudp.o:rudp.cpp rudp.h rudpmgr.h nodes.hpp lock.h
g++ -c rudp.cpp
rudpmgrsink.o:rudpmgrsink.cpp rudpmgrsink.h rudpmgr.h types.h
g++ -c rudpmgrsink.cpp
common.o:common.cpp common.h types.h
g++ -c common.cpp
lock.o:lock.cpp lock.h
g++ -c lock.cpp
rebuild:clean client
clean:
-rm client $(objects)
testserver.h:
#ifndef __TEST_SERVER_H__
#define __TEST_SERVER_H__
#include "command.h"
#include "rudpmgrsink.h"
class TestServer : public RudpMgrSink
{
public:
TestServer(RudpMgr * mgr);
virtual ~TestServer();
public:
virtual void onconnect(uint32_t unique_id);
virtual void ondisconnect(uint32_t unique_id);
virtual bool handle_data(uint32_t conn, unsigned char * data, uint16_t len);
public:
bool handle_reverse_string_request(uint32_t unique_id, unsigned char * data, uint16_t len);
public:
bool send_reverse_string_response(uint32_t unique_id, unsigned char * data, uint16_t len);
};
#endif
testserver.cpp:
#include <cstring>
#include "testserver.h"
TestServer::TestServer(RudpMgr * mgr) : RudpMgrSink(mgr)
{
}
TestServer::~TestServer()
{
}
void TestServer::onconnect(uint32_t unique_id)
{
}
void TestServer::ondisconnect(uint32_t unique_id)
{
}
bool TestServer::handle_data(uint32_t unique_id, unsigned char * data, uint16_t len)
{
unsigned char cmd = data[0];
data += 1;
len -= 1;
switch (cmd)
{
case cmd_reverse:
{
return(handle_reverse_string_request(unique_id, data, len));
}
default:
{
return(false);
}
}
}
bool TestServer::handle_reverse_string_request(uint32_t unique_id, unsigned char * data, uint16_t len)
{
for (int index = 0; index < len / 2; ++index)
{
unsigned char temp = data[index];
data[index] = data[len - 2 - index];
data[len - 2 - index] = temp;
}
return(send_reverse_string_response(unique_id, data, len));
}
bool TestServer::send_reverse_string_response(uint32_t unique_id, unsigned char * data, uint16_t len)
{
if (0 == unique_id)
{
return(false);
}
if (len > 65535 - sizeof(unsigned char) + sizeof(uint16_t))
{
return(false);
}
unsigned char buff[65535];
buff[0] = (unsigned char)cmd_reverse;
len += sizeof(unsigned char);
memcpy(buff + 1, data, len);
len += 1;
return(send_data(unique_id, buff, len, true));
}
server.cpp:
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include "rudpmgr.h"
#include "testserver.h"
int main()
{
RudpMgr * prudpmgr = new RudpMgr(10000);
TestServer server(prudpmgr);
prudpmgr->run();
while (true)
{
pause();
}
delete prudpmgr;
printf("test over\n");
return(0);
}
makefile_server:
objects=server.o testserver.o rudpmgr.o rudp.o rudpmgrsink.o common.o lock.o
server:$(objects)
g++ -o server $(objects) -lpthread
server.o:server.cpp rudpmgr.h testserver.h
g++ -c server.cpp
testserver.o:testserver.cpp testserver.h
g++ -c testserver.cpp
rudpmgr.o:rudpmgr.cpp rudpmgr.h rudp.h rudpmgrsink.h types.h common.h lock.h
g++ -c rudpmgr.cpp
rudp.o:rudp.cpp rudp.h rudpmgr.h nodes.hpp lock.h
g++ -c rudp.cpp
rudpmgrsink.o:rudpmgrsink.cpp rudpmgrsink.h rudpmgr.h types.h
g++ -c rudpmgrsink.cpp
common.o:common.cpp common.h types.h
g++ -c common.cpp
lock.o:lock.cpp lock.h
g++ -c lock.cpp
rebuild:clean server
clean:
-rm server $(objects)