Добавил:
korayakov
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:
/*******************************************************************************
* file: dm_core.cpp *
* version: 0.9.2 *
* author: d-evil [tmd] (mailto:d-evil.tmd@mail.ru) *
* description: not available *
*******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
// headers
#include "dm_core.h"
namespace dm_core {
////////////////////////////////////////////////////////////////////////////////
// cdm_dl_list public definition
cdm_dls_list::cdm_dls_list(): _first(NULL), _inum(0) {
_mutex = CreateMutex(NULL, FALSE, NULL);
}
cdm_dls_list::~cdm_dls_list() {
WaitForSingleObject(_mutex, INFINITE);
CloseHandle(_mutex);
}
int cdm_dls_list::add(cdm_dl_item *const item, const int timeout) {
if (WAIT_TIMEOUT == WaitForSingleObject(_mutex, timeout)) return -1;
item->set(_first);
if (NULL != _first) _first->set_prev(item);
_first = item;
++_inum;
ReleaseMutex(_mutex);
return _inum;
}
int cdm_dls_list::del(cdm_dl_item *const item, const int timeout) {
if (WAIT_TIMEOUT == WaitForSingleObject(_mutex, timeout)) return -1;
if (NULL != item->prev())
item->prev()->set_next(item->next());
else
_first = item->next();
if (NULL != item->next())
item->next()->set_prev(item->prev());
ReleaseMutex(_mutex);
return --_inum;
}
int cdm_dls_list::lock(const int timeout) {
int rev = WaitForSingleObject(_mutex, (timeout == -1)? INFINITE: timeout);
if (WAIT_TIMEOUT == rev) return -1;
return 0;
}
int cdm_dls_list::ulock() {
if (0 == ReleaseMutex(_mutex)) return -1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_addr_info public definition
cdm_addr_info::cdm_addr_info() {
_saddr_in.sin_addr.s_addr = 0;
_saddr_in.sin_port = 0;
_saddr_in.sin_family = AF_INET;
_ip_str = NULL;
_port_str = (char *)malloc(MX_PORTLEN * sizeof(char));
_host = NULL;
}
cdm_addr_info::cdm_addr_info(const char *const host, const unsigned short port) {
_ip_str = NULL;
set(host, port);
}
cdm_addr_info::~cdm_addr_info() {
free(_ip_str);
free(_port_str);
free(_host);
}
int cdm_addr_info::set(const sockaddr_in *const saddrin) {
int rev = set_port(saddrin->sin_port);
if (0 != rev) return rev;
rev = _set_ip(saddrin->sin_addr);
if (0 != rev) {
if (NULL != _host) _host[0] = '\0';
return rev;
}
return _updt_host();
}
int cdm_addr_info::set(const char *const host, const unsigned short port) {
int rev = set_port(port);
if (0 != rev) return rev;
return set_host(host);
}
int cdm_addr_info::set_port(const unsigned short port) {
_saddr_in.sin_port = port;
if (NULL == _port_str) {
// try to alloc some memory
_port_str = (char *)malloc(MX_PORTLEN * sizeof(char));
if (NULL == _port_str) return ERC_NOMEM;
}
_port_str = itoa(port, _port_str, 10);
return 0;
}
int cdm_addr_info::set_host(const char *const host) {
int rev = resolve_host(host, &_saddr_in.sin_addr);
if (0 != rev) return rev;
rev = _set_ip(_saddr_in.sin_addr);
if (0 != rev) {
if (NULL != _host) _host[0] = '\0';
return rev;
}
return _updt_host();
}
int cdm_addr_info::resolve_host(const char *const host, in_addr *const addr) {
addr->s_addr = inet_addr(host);
// If the supplied server address wasn’t in the form "aaa.bbb.ccc.ddd"
// it’s a host name, so try to resolve it
if (INADDR_NONE == addr->s_addr) {
hostent *ht;
ht = gethostbyname(host);
if (NULL == ht) return ERC_CANTRESOLVE;
memcpy(addr, ht->h_addr_list[0], ht->h_length);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_addr_info protected definition
int cdm_addr_info::_set_ip(const in_addr ip) {
_saddr_in.sin_addr = ip;
char *ip_str = inet_ntoa(_saddr_in.sin_addr);
if (NULL == ip_str) {
if (NULL != _ip_str) _ip_str[0] = '\0';
return ERC_WSA;
}
size_t len = strlen(ip_str) + 1;
char *tmp = (char *)realloc(_ip_str, len * sizeof(char));
if (NULL == tmp) {
_ip_str = '\0';
return ERC_NOMEM;
}
_ip_str = tmp;
memcpy(_ip_str, ip_str, len * sizeof(char));
return 0;
}
int cdm_addr_info::_updt_host() {
hostent *ht = gethostbyaddr((char *)&_saddr_in.sin_addr,
sizeof(_saddr_in.sin_addr), _saddr_in.sin_family);
if (NULL == ht || NULL == ht->h_name) {
if (NULL != _host) _host[0] = '\0';
return 0; // ERC_CANTRESOLVE; // can't resolve
}
size_t len = strlen(ht->h_name) + 1;
char *tmp = (char *)realloc(_host, len * sizeof(char));
if (NULL == tmp) {
if (NULL != _host) _host[0] = '\0';
return ERC_NOMEM;
}
_host = tmp;
memcpy(_host, ht->h_name, len * sizeof(char));
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_file_info public definition
cdm_file_info::cdm_file_info() {
_init();
}
cdm_file_info::cdm_file_info(const cdm_file_info &ifile) {
_init();
set_path(ifile.path(), false);
set_name(ifile.name());
set_sz(ifile.sz());
}
cdm_file_info::cdm_file_info(const char *const path, const bool ch_name) {
_init();
set_path(path, ch_name);
}
cdm_file_info::cdm_file_info(const char *const name) {
_init();
set_name(name);
}
cdm_file_info::~cdm_file_info() {
free(_name);
free(_path);
}
int cdm_file_info::set_name(const char *const name) {
if (NULL == name) {
free(_name);
_name = NULL;
return 0;
}
int tmp_len = (int)strlen(name) + 1;
char *tmp = (char *)realloc(_name, tmp_len * sizeof(char));
if (NULL == tmp) return -1;
memcpy(_name = tmp, name, tmp_len);
_name_len = tmp_len - 1;
return 0;
}
int cdm_file_info::set_path(const char *const path, const bool ch_name) {
if (NULL == path) {
free(_path);
_path = NULL;
if (ch_name) {
free(_name);
_name = NULL;
}
return 0;
}
int tmp_len = (int)strlen(path) + 1;
char *tmp = (char *)realloc(_path, tmp_len * sizeof(char));
if (NULL == tmp) return -1;
memcpy(_path = tmp, path, tmp_len);
_path_len = tmp_len - 1;
if (ch_name) {
set_name(_path + extract_filename(_path, _path_len));
}
return 0;
}
int cdm_file_info::extract_filename(const char *const path, const int len) {
int i = (0 == len)? (int)strlen(path): len;
for (--i; 0 <= i; --i) {
if ('\\' == path[i] || '/' == path[i]) return i+1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_file_info protected definition
void cdm_file_info::_init() {
_name = NULL;
_path = NULL;
_name_len = 0;
_path_len = 0;
_sz = 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_fwriter public definition
cdm_fwriter::cdm_fwriter() {
_id = 0;
_next_num = 0;
_file = NULL;
}
cdm_fwriter::~cdm_fwriter() {
if (NULL != _file) close();
}
int cdm_fwriter::open(const char *const mode) {
_file = fopen(_file_info.path(), mode);
if (NULL == _file) return -1;
return 0;
}
int cdm_fwriter::close() {
fclose(_file);
return 0;
}
int cdm_fwriter::write(const char *const buf, const int len) {
if (NULL == _file) return -1;
if (len != fwrite(buf, sizeof(char), len, _file)) return -1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_socket public definition
cdm_socket::cdm_socket() {
_state = STATE_NONE;
_ext_state = EXTSTATE_NONE;
_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
_pckt_sz = _DEF_PCKT_SZ;
_buf = (char *)malloc(_pckt_sz * sizeof(char));
_ui_data = NULL;
}
cdm_socket::~cdm_socket() {
free(_buf);
if (INVALID_SOCKET != _sock)
closesocket(_sock);
}
int cdm_socket::set_pckt_sz(const int pckt_sz) {
if (pckt_sz <= _PCKT_MNSZ) return _pckt_sz;
char *tmp = (char *)realloc(_buf, sizeof(char));
if (NULL == tmp) return _pckt_sz;
_buf = tmp;
return (_pckt_sz = pckt_sz);
}
int cdm_socket::bind() {
int rev = ::bind(_sock, _addr_info.saddr(), _addr_info.saddr_sz());
if (0 != rev) return -1;
return 0;
}
int cdm_socket::can_read() {
fd_set set;
set.fd_count = 1;
set.fd_array[0] = _sock;
timeval tv = {0, 0};
int rev = select(0, &set, NULL, NULL, &tv);
if (1 == rev) return 1;
if (SOCKET_ERROR == rev) return -1;
return 0;
}
int cdm_socket::can_write() {
fd_set set;
set.fd_count = 1;
set.fd_array[0] = _sock;
timeval tv = {0, 0};
int rev = select(0, NULL, &set, NULL, &tv);
if (1 == rev) return 1;
if (SOCKET_ERROR == rev) return -1;
return 0;
}
int cdm_socket::can_read_size() {
unsigned long arg;
if (0 != ioctlsocket(_sock, FIONREAD, &arg)) return -1;
return (int)arg;
}
int cdm_socket::recv_dtgm() {
if (NULL == _buf) return -1;
_saddrin_sz = sizeof(_saddrin);
if (cdm_core::use_bugs() && rand() > RAND_MAX/16) return 0;
int rev = ::recvfrom(_sock, _buf, _pckt_sz, 0, (sockaddr *)&_saddrin, &_saddrin_sz);
if (rev != _pckt_sz) return -1;
return 0;
}
int cdm_socket::send_dtgm() {
if (cdm_core::use_bugs() && rand() < RAND_MAX/16) return 0;
int rev = ::sendto(_sock, _buf, _pckt_sz, 0, _addr_info.saddr(), _addr_info.saddr_sz());
if (rev != _pckt_sz) return -1;
return 0;
}
int cdm_socket::send_dtgm(char *const dtgm) {
if (cdm_core::use_bugs() && rand() < RAND_MAX/16) return 0;
int rev = ::sendto(_sock, dtgm, _pckt_sz, 0, _addr_info.saddr(), _addr_info.saddr_sz());
if (rev != _pckt_sz) return -1;
return 0;
}
int cdm_socket::send_dtgm(const char *const dtgm, const int dtgm_size,
sockaddr_in *const saddrin, const int saddrin_sz)
{
if (cdm_core::use_bugs() && rand() < RAND_MAX/16) return 0;
int rev = ::sendto(_sock, dtgm, dtgm_size, 0, (sockaddr *)saddrin, saddrin_sz);
if (rev != dtgm_size) return -1;
return 0;
}
int cdm_socket::send_dtgm(sockaddr_in *const saddrin, const int saddrin_sz) {
if (cdm_core::use_bugs() && rand() < RAND_MAX/16) return 0;
int rev = ::sendto(_sock, _buf, _pckt_sz, 0, (sockaddr *)saddrin, saddrin_sz);
if (rev != _pckt_sz) return -1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_frecv_subs public definition
cdm_frecv_subs::cdm_frecv_subs() {
_init();
}
cdm_frecv_subs::~cdm_frecv_subs() {
_free_dtgms();
_free_appeal();
free(_dtgms);
free(_free_tbl);
if (NULL != _hfile && INVALID_HANDLE_VALUE != _hfile)
CloseHandle(_hfile);
}
int cdm_frecv_subs::init() {
_last_appeal_time = 0;
_set_state(STATE_STOPED);
_set_ext_state(EXTSTATE_NONE);
_realloc_bufs();
_realloc_appeal();
return 0;
}
int cdm_frecv_subs::start(const bool delayed) {
if (delayed) {
_set_state(STATE_LAUNCHED);
_set_ext_state(EXTSTATE_NONE);
return 0;
}
stop();
_run_time = 0;
_last_time = clock();
_hfile = CreateFile(_ifile.path(), GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == _hfile) return -1;
_appeal_max = _ifile.sz() / _data_size;
if (0 != _ifile.sz() % _data_size) ++_appeal_max;
_done_parts = 0;
_total_parts = _appeal_max;
int doto;
if (_appeal_max < _appeals_count) {
for (int i = _appeals_count - 1; i >= _appeal_max; --i)
_appeal->nums[i] = -1;
doto = _appeal_max;
_appeal_next = -1;
} else {
doto = _appeals_count;
_appeal_next = _appeals_count;
}
for (int i = doto-1; 0 <= i; --i) {
_appeal->nums[i] = i;
}
_appeal->type = DTGM_TYPE_APPEAL;
_appeal->ss_id = _id;
_appeal->pckt_sz = _dtgm_size;
_appeal->count = _appeals_count;
_appeals_changed = 0;
_appeal->session_id = _session_id;
_set_state(STATE_RUNNING);
_set_ext_state(EXTSTATE_RECVING);
return 0;
}
int cdm_frecv_subs::stop(const int ext_state) {
_set_state(STATE_STOPED);
_set_ext_state(ext_state);
if (NULL != _hfile && INVALID_HANDLE_VALUE != _hfile) {
CloseHandle(_hfile);
_hfile = NULL;
}
return 0;
}
int cdm_frecv_subs::add_dtgm(sdm_dtgm_data *const dtgm) {
for (int i = 0; _appeals_count > i; ++i) {
if (dtgm->num != _appeal->nums[i]) continue;
if (dtgm->data_sz > _data_size) dtgm->data_sz = _data_size;
unsigned int fgoto = (unsigned int)(dtgm->num) * (unsigned int)_data_size;
LARGE_INTEGER pos_64;
pos_64.QuadPart = fgoto;
SetFilePointer(_hfile, pos_64.LowPart, &pos_64.HighPart, FILE_BEGIN);
DWORD w;
BOOL br = WriteFile(_hfile, dtgm->data, dtgm->data_sz, &w, NULL);
if (TRUE != br || w != dtgm->data_sz) return -1;
if (_appeal_next < _appeal_max) {
_appeal->nums[i] = _appeal_next++;
++_appeals_changed;
} else {
_appeal->nums[i] = -1;
}
++_done_parts;
return 0;
}
return -1;
}
int cdm_frecv_subs::terminate(const int ext_state) {
_set_state(STATE_RUNNING);
_set_ext_state(ext_state);
return 0;
}
bool cdm_frecv_subs::can_appeal() {
for (int i = 0; i < _appeals_count; ++i) {
if (-1 != _appeal->nums[i]) return true;
}
return false;
}
bool cdm_frecv_subs::need_appeal() {
// if (!can_appeal()) return false;
//[debug] CString str;
//[debug] str.AppendFormat("_appeals_count: %i\n", _appeals_count);
//[debug] str.AppendFormat("_appeals_need_ahead: %i\n", _appeals_need_ahead);
int max_apch = _appeals_count - _appeals_need_ahead;
//[debug] str.AppendFormat("max_apch: %i\n", max_apch);
//[debug] str.AppendFormat("_appeals_changed: %i\n", _appeals_changed);
//[debug]MessageBox(NULL, str+" 1", "dormouse core", MB_OK|MB_APPLMODAL|MB_ICONINFORMATION);
if (_appeals_changed >= max_apch) return true;
clock_t max_apt = _reappeal_timeout * CLOCKS_PER_SEC/1000;
//[debug] str.AppendFormat("_reappeal_timeout: %i\n", _reappeal_timeout);
//[debug] str.AppendFormat("max_apt 1: %i\n", max_apt);
//[debug] str.AppendFormat("_last_appeal_time: %i\n", _last_appeal_time);
max_apt += _last_appeal_time;
//[debug] str.AppendFormat("max_apt 2: %i\n", max_apt);
//[debug] str.AppendFormat("clock(): %i\n", clock());
//[debug] MessageBox(NULL, str+" 2", "dormouse core", MB_OK|MB_APPLMODAL|MB_ICONINFORMATION);
if (max_apt < clock()) return true;
//[debug] MessageBox(NULL, str+" 3", "dormouse core", MB_OK|MB_APPLMODAL|MB_ICONINFORMATION);
return false;
}
sdm_dtgm_appeal *cdm_frecv_subs::get_appeal(const bool will_send) {
if (will_send) {
_appeals_changed = 0;
_last_appeal_time = clock();
}
_appeal->done_parts = _done_parts;
return _appeal;
}
int cdm_frecv_subs::send_discard(const int dtype, const int data, const int param) {
if (1 != _parent->can_write()) return 0;
sdm_dtgm_discard *discard = (sdm_dtgm_discard *)malloc(_dtgm_size * sizeof(char));
if (NULL == discard) return -1;
discard->type = DTGM_TYPE_DISCARD;
discard->session_id = _session_id;
discard->ss_id = _id;
discard->dtype = dtype;
discard->data = data;
discard->param = param;
_parent->send_dtgm((char *)discard, _dtgm_size, _iaddr.saddrin(), _iaddr.saddr_sz());
free(discard);
return 0;
}
int cdm_frecv_subs::set_dtgm_size(const int dtgm_size) {
_dtgm_size = dtgm_size;
_data_size = _dtgm_size - sizeof(sdm_dtgm_data) + sizeof(char);
_realloc_bufs();
return 0;
}
int cdm_frecv_subs::set_dtgms_count(const int dtgms_count) {
_dtgms_count = dtgms_count;
_realloc_bufs();
return 0;
}
int cdm_frecv_subs::set_appeals_count(const int appeals_count) {
_appeals_count = appeals_count;
_realloc_appeal();
return 0;
}
int cdm_frecv_subs::die(const bool delayed) {
if (delayed) {
_dying = true;
return 0;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_frecv_subs protected definition
void cdm_frecv_subs::_init() {
_set_state(STATE_NONE);
_set_ext_state(EXTSTATE_NONE);
_dtgms_count = _DEF_DTGMS_COUNT;
_dtgm_size = _DEF_DTGM_SIZE;
_appeals_count = _DEF_APEALS_COUNT;
_reappeal_timeout = _DEF_REAPPEAL_TIMEOUT;
_appeals_need_ahead = _DEF_APPEALS_NEEDAHEAD;
_data_size = _dtgm_size - sizeof(sdm_dtgm_data) + sizeof(char);
_dtgms = NULL;
_free_tbl = NULL;
_free_i = 0;
_hfile = NULL;
_appeal = NULL;
_done_parts = 0;
_total_parts = 0;
_id = -1;
_session_id = -1;
_dying = false;
_last_time = clock();
_run_time = 0;
}
void cdm_frecv_subs::_alloc_dtgms() {
for (int i = _dtgms_count - 1; 0 <= i; --i) {
_dtgms[i] = (char *)malloc(_dtgm_size * sizeof(char));
}
}
void cdm_frecv_subs::_free_dtgms() {
if (NULL == _dtgms) return;
for (int i = _dtgms_count - 1; 0 <= i; --i) {
free(_dtgms[i]);
_dtgms[i] = NULL;
}
}
void cdm_frecv_subs::_realloc_free_tbl() {
_free_tbl = (int *)realloc(_free_tbl, _dtgms_count * sizeof(int));
for (int i = _dtgms_count - 1; 0 <= i; --i) {
_free_tbl[i] = i;
}
}
void cdm_frecv_subs::_realloc_bufs() {
_free_dtgms();
_dtgms = (char **)realloc(_dtgms, _dtgms_count * sizeof(char *));
_alloc_dtgms();
_realloc_free_tbl();
}
void cdm_frecv_subs::_realloc_appeal() {
_appeal = (sdm_dtgm_appeal *)realloc(_appeal, _dtgm_size * sizeof(char));
for (int i = _appeals_count - 1; 0 <= i; --i) {
_appeal->nums[i] = -1;
}
}
void cdm_frecv_subs::_free_appeal() {
free(_appeal);
_appeal = NULL;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_frecver public definition
cdm_frecver::cdm_frecver() {
_binded = false;
_dying = false;
}
cdm_frecver::~cdm_frecver() {
die();
}
void cdm_frecver::add_subs(cdm_frecv_subs *const subs) {
int id = 0;
while (NULL != get_subs(id)) ++id;
subs->set_id(id);
subs->init();
_subs.add((_cdm_frecv_subs *)subs);
}
void cdm_frecver::remove_subs(cdm_frecv_subs *const subs) {
_subs.del((_cdm_frecv_subs *)subs);
}
cdm_frecv_subs *cdm_frecver::get_subs(const int id) {
_cdm_frecv_subs *item = (_cdm_frecv_subs *)_subs.first();
for (; NULL != item; item = (_cdm_frecv_subs *)item->next()) {
if (id == item->id()) return item;
}
return NULL;
}
cdm_frecv_subs *cdm_frecver::get_session(const int session_id) {
_cdm_frecv_subs *item = (_cdm_frecv_subs *)_subs.first();
for (; NULL != item; item = (_cdm_frecv_subs *)item->next()) {
if (session_id == item->session_id()) return item;
}
return NULL;
}
int cdm_frecver::start(const bool delayed) {
if (delayed) {
_set_state(STATE_LAUNCHED);
_set_ext_state(EXTSTATE_NONE);
return 0;
}
if (!_binded && 0 != bind()) {
_set_state(STATE_STOPED);
_set_ext_state(EXTSTATE_NONE);
return -1;
}
_binded = true;
_set_state(STATE_RUNNING);
_set_ext_state(EXTSTATE_LISTENING);
return 0;
}
int cdm_frecver::stop() {
_set_state(STATE_STOPED);
_set_ext_state(EXTSTATE_NONE);
return 0;
}
int cdm_frecver::die(const bool delayed) {
if (delayed) {
_dying = true;
return 0;
}
_cdm_frecv_subs *subs = (_cdm_frecv_subs *)_subs.first();
while (NULL != subs) {
_cdm_frecv_subs *victim = subs;
subs = (_cdm_frecv_subs *)subs->next();
kill_subs(victim);
}
return 0;
}
int cdm_frecver::kill_subs(cdm_frecv_subs *const subs) {
if (NULL == subs) return -1;
subs->stop();
_subs.del((_cdm_frecv_subs *)subs);
delete (_cdm_frecv_subs *)subs;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_fsender public definition
cdm_fsender::cdm_fsender() {
_set_state(STATE_STOPED);
_rerequest_timeout = _DEF_REREQUEST_TIMEOUT;
_send_dtgm = NULL;
_hfile = NULL;
_total_parts = 0;
_done_parts = 0;
_session_id = 0;
_dying = false;
_run_time = 0;
_last_time = clock();
}
cdm_fsender::~cdm_fsender() {
free(_send_dtgm);
if (NULL != _hfile && INVALID_HANDLE_VALUE != _hfile) {
CloseHandle(_hfile);
_hfile = NULL;
}
}
int cdm_fsender::start(const bool delayed) {
if (delayed) { // if start is delayed
_set_state(STATE_LAUNCHED);
_set_ext_state(EXTSTATE_NONE);
return 0;
}
stop();
_run_time = 0;
_last_time = clock();
// _data_sz is a number of bytes can be sent in one datagram
_data_sz = pckt_sz() - sizeof(sdm_dtgm_data) + sizeof(char);
if (NULL != _hfile && INVALID_HANDLE_VALUE != _hfile) CloseHandle(_hfile);
_hfile = CreateFile(_ifile.path(), GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == _hfile) {
_set_state(STATE_STOPED);
_set_ext_state(EXTSTATE_NONE);
return -1;
}
_ifile.set_sz(GetFileSize(_hfile, NULL));
_total_parts = _ifile.sz() / _data_sz;
if (0 != _ifile.sz() % _data_sz) ++_total_parts;
_done_parts = 0;
// try to alloc buffer for "send out" datagrams.
// internal buffer (from cdm_socket) will be used to recv datagrams
char *tmp = (char *)realloc(_send_dtgm, pckt_sz() * sizeof(char));
if (NULL == tmp) {
CloseHandle(_hfile);
_hfile = NULL;
_set_state(STATE_STOPED);
_set_ext_state(EXTSTATE_NONE);
return -1;
}
_send_dtgm = (sdm_dtgm_data *)tmp;
//TODO: use other way to init session id
_session_id = rand() + RAND_MAX*rand();
_last_request_time = clock() - _rerequest_timeout;
_set_state(STATE_RUNNING);
_set_ext_state(EXTSTATE_REQUESTING);
return 0;
}
int cdm_fsender::stop(const int ext_state) {
if (NULL != _hfile && INVALID_HANDLE_VALUE != _hfile) {
CloseHandle(_hfile);
_hfile = NULL;
}
_set_state(STATE_STOPED);
_set_ext_state(ext_state);
return 0;
}
bool cdm_fsender::need_request() {
int dtime = (clock() - _last_request_time)*1000/CLOCKS_PER_SEC;
if (_rerequest_timeout > dtime) return false;
return true;
}
int cdm_fsender::send_request() {
if (STATE_RUNNING != state()) return 0;
_set_ext_state(EXTSTATE_REQUESTING);
int rev = can_write();
if (1 != rev) return rev;
sdm_dtgm_request *request = (sdm_dtgm_request *)_send_dtgm;
request->type = DTGM_TYPE_REQUEST;
request->session_id = _session_id;
request->pckt_sz = pckt_sz();
request->file_sz = _ifile.sz();
request->fn_len = _ifile.name_len();
int mx_fn_len = pckt_sz() - sizeof(sdm_dtgm_request);
int cp_len = (mx_fn_len > _ifile.name_len())? _ifile.name_len(): mx_fn_len;
memcpy(request->fname, _ifile.name(), cp_len);
request->fname[cp_len] = '\0';
rev = send_dtgm((char *)request);
if (0 != rev) return rev;
_last_request_time = clock();
return 0;
}
int cdm_fsender::send_data(const int id, int *const appeals, const int count) {
if (STATE_RUNNING != state()) return 0;
_set_ext_state(EXTSTATE_SENDING);
_send_dtgm->type = DTGM_TYPE_DATA;
_send_dtgm->session_id = _session_id;
_send_dtgm->ss_id = id;
for (int i = 0; i < count; ++i) {
if (-1 == appeals[i]) continue;
unsigned int fgoto = (unsigned int)appeals[i] * (unsigned int)_data_sz;
if (_ifile.sz() <= fgoto) continue;
if (1 != can_write()) continue;
LARGE_INTEGER pos_64;
pos_64.QuadPart = fgoto;
if (INVALID_SET_FILE_POINTER == SetFilePointer(_hfile, pos_64.LowPart, &pos_64.HighPart, FILE_BEGIN))
continue;
DWORD rsz;
if (FALSE == ReadFile(_hfile, (void *)_send_dtgm->data, _data_sz, &rsz, NULL))
continue;
if (0 >= (int)rsz) continue;
_send_dtgm->num = appeals[i];
_send_dtgm->data_sz = (int)rsz;
send_dtgm((char *)_send_dtgm);
}
return 0;
}
int cdm_fsender::send_discard(const int ss_id, const int dtype, const int data, const int param) {
if (1 != can_write()) return 0;
sdm_dtgm_discard *discard = (sdm_dtgm_discard *)malloc(pckt_sz() * sizeof(char));
if (NULL == discard) return -1;
discard->type = DTGM_TYPE_DISCARD;
discard->session_id = _session_id;
discard->ss_id = ss_id;
discard->dtype = dtype;
discard->data = data;
discard->param = param;
send_dtgm((char *)discard);
free(discard);
return 0;
}
int cdm_fsender::add_parts(const int num) {
_done_parts += num; //XXX: the string was "++_done_parts;"
if (_total_parts < _done_parts) {
_done_parts = _total_parts;
return -1;
}
return _done_parts;
}
int cdm_fsender::die(const bool delayed) {
if (delayed) {
_dying = true;
return 0;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_core public definition
cdm_core::cdm_core() {
_thread_h = NULL;
_hostname = NULL;
_running_mtx = NULL;
_ui = NULL;
_nulljob_delay = _DEF_NULLJOB_DELAY;
_last_dm_error = 0;
_last_error = 0;
_def_dir = NULL;
_running_mtx = CreateMutex(NULL, FALSE, NULL);
}
cdm_core::~cdm_core() {
if (NULL != _running_mtx) {
_must_stop = true;
WaitForSingleObject(_running_mtx, INFINITE);
CloseHandle(_running_mtx);
}
WSACleanup();
free(_def_dir);
}
int cdm_core::attach_ui(cdm_uiproto *const ui) {
_ui = ui;
return 0;
}
int cdm_core::init() {
if (0 != WSAStartup(MAKEWORD(2,0), &_wsa_data)) return _error(ERC_SOCKSINIT);
_def_dir = (char *)malloc(MAX_PATH*2);
GetCurrentDirectory(MAX_PATH*2, _def_dir);
_hostname = (char *)malloc(_HOSTNAME_MXLEN * sizeof(char));
if (NULL != _hostname) {
int rev = gethostname(_hostname, _HOSTNAME_MXLEN);
if (SOCKET_ERROR == rev) _hostname[0] = '\0';
}
return 0;
}
int cdm_core::run(const bool nt) {
_must_stop = false;
if (!nt) return _run();
_thread_h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_run_helper, this, 0, &_thread_id);
if (NULL == _thread_h) return _error(ERC_CRTHREAD);
return 0;
}
int cdm_core::pause() {
if (NULL != _thread_h) return ERC_PAUSEMAIN;
if ((DWORD)-1 == SuspendThread(_thread_h)) return _error(ERC_THRSUSPEND);
return 0;
}
int cdm_core::upause() {
if (NULL == _thread_h) return ERC_PAUSEMAIN;
if ((DWORD)-1 == ResumeThread(_thread_h)) return _error(ERC_THRRESUME);
return 0;
}
int cdm_core::quit() {
_must_stop = true;
return 0;
}
int cdm_core::swallow(cdm_frecver *const recver, int *const ch_mask) {
int pen_sz = recver->can_read_size();
// parsing incoming datagram
for (; recver->pckt_sz() <= pen_sz; pen_sz -= recver->pckt_sz()) {
if (0 != recver->recv_dtgm()) break;
switch (recver->dtgm_type()) {
case DTGM_TYPE_REQUEST: // request for connect
accept(recver, ch_mask);
break;
case DTGM_TYPE_DATA:
get_data(recver, ch_mask);
break;
case DTGM_TYPE_DISCARD:
discard(recver, ch_mask);
break;
default:
// unknow datagram type. Not use it
break;
}
}
// check all sub systems
cdm_frecv_subs *subs = recver->subs_first();
while (NULL != subs) {
if (subs->is_dying()) {
cdm_frecv_subs *victim = subs;
subs = recver->subs_next(subs);
_ui->on_subs_rm(victim);
recver->kill_subs(victim);
continue;
}
if (cdm_frecv_subs::STATE_LAUNCHED == subs->state()) {
if (0 != subs->start()) {
_error(ERC_STARTFSUBS);
_ui_on_error();
subs->stop();
*ch_mask |= cdm_uiproto::FRECVER_CH_STATE;
}
_ui->on_subs_ch(subs, cdm_uiproto::FSUBS_CH_ALL);
subs = recver->subs_next(subs);
continue;
}
if (cdm_frecv_subs::STATE_RUNNING != subs->state()) {
subs = recver->subs_next(subs);
continue;
}
subs->update_time();
if (cdm_frecv_subs::EXTSTATE_TERMINATING == subs->ext_state()) {
subs->send_discard(DISCARD_TYPE_CANCEL, -1);
subs = recver->subs_next(subs);
continue;
} else if (cdm_frecv_subs::EXTSTATE_FINALIZING == subs->ext_state()) {
subs->send_discard(DISCARD_TYPE_DONE, subs->done_parts());
subs = recver->subs_next(subs);
continue;
}
if (!subs->can_appeal()) {
// all data received
// subs->send_discard(DISCARD_TYPE_DONE, subs->total_parts());
subs->terminate(); // stop(cdm_frecv_subs::EXTSTATE_FINALIZING);
_ui->on_subs_ch(subs, cdm_uiproto::FSUBS_CH_ALL);
subs = recver->subs_next(subs);
continue;
}
if (subs->need_appeal()) {
sdm_dtgm_appeal *appeal = subs->get_appeal();
recver->send_dtgm((char *)appeal, subs->dtgm_size(),
subs->iaddr()->saddrin(), subs->iaddr()->saddr_sz());
}
subs = recver->subs_next(subs);
}
return 0;
}
int cdm_core::spit(cdm_fsender *const sender, int *const ch_mask) {
if (cdm_fsender::EXTSTATE_REQUESTING == sender->ext_state()) {
if (sender->need_request()) {
*ch_mask |= cdm_uiproto::FRECVER_CH_STATE|cdm_uiproto::FSENDER_CH_PROGRESS;
if (0 != sender->send_request()) {
_sock_error(ERC_FSENDER_SPIT);
sender->stop();
return -1;
}
}
}
int pen_sz = sender->can_read_size();
// parsing incoming datagram
for (; sender->pckt_sz() <= pen_sz; pen_sz -= sender->pckt_sz()) {
// MessageBeep(MB_ICONASTERISK);
if (0 != sender->recv_dtgm()) break;
switch(sender->dtgm_type()) {
case DTGM_TYPE_APPEAL:
appeal(sender, ch_mask);
break;
case DTGM_TYPE_DISCARD:
discard(sender, ch_mask);
*ch_mask |= cdm_uiproto::FSENDER_CH_STATE;
break;
default:
break;
}
}
return 0;
}
int cdm_core::accept(cdm_frecver *const recver, int *const ch_mask) {
sdm_dtgm_request *request = (sdm_dtgm_request *)recver->dtgm();
if (NULL != recver->get_session(request->session_id)) return 0;
if (0 > request->file_sz) return 0;
int mx_bdy_sz = recver->pckt_sz() - sizeof(sdm_dtgm_request);
if (0 >= mx_bdy_sz || mx_bdy_sz <= request->fn_len) return 0;
// MessageBox(NULL, recver->addr_info()->ip_str(), "before", MB_OK|MB_APPLMODAL); // [bug fixed 12.04.2005]
request->fname[mx_bdy_sz-1] = '\0'; // bug was: request->fname[recver->pckt_sz()-1] = '\0';
// MessageBox(NULL, recver->addr_info()->ip_str(), "after", MB_OK|MB_APPLMODAL); // [/bug fixed 12.04.2005]
cdm_frecv_subs *subs = recver->new_subs();
subs->set_parent(recver);
subs->iaddr()->set(recver->saddrin());
subs->ifile()->set_name(request->fname);
subs->ifile()->set_sz(request->file_sz);
subs->set_session_id(request->session_id);
recver->add_subs(subs);
if (0 == _ui->on_accept(subs)) {
subs->start(true);
} else {
subs->terminate(cdm_frecv_subs::EXTSTATE_TERMINATING);
}
_ui->on_subs_ch(subs, cdm_uiproto::FSUBS_CH_ALL);
return 0;
}
int cdm_core::get_data(cdm_frecver *const recver, int *const ch_mask) {
sdm_dtgm_data *dtgm = (sdm_dtgm_data *)recver->dtgm();
cdm_frecv_subs *subs = recver->get_subs(dtgm->ss_id);
if (NULL == subs) return 0;
if (cdm_frecv_subs::STATE_RUNNING != subs->state()) return 0;
if (cdm_frecv_subs::EXTSTATE_RECVING != subs->ext_state()) return 0;
_speeed_prev = subs->done_parts();
subs->add_dtgm(dtgm);
_speeed += subs->done_parts() - _speeed_prev;
_ui->on_subs_ch(subs, cdm_uiproto::FSENDER_CH_PROGRESS);
return 0;
}
int cdm_core::discard(cdm_frecver *const recver, int *const ch_mask) {
sdm_dtgm_discard *discard = (sdm_dtgm_discard *)recver->dtgm();
cdm_frecv_subs *subs = recver->get_subs(discard->ss_id);
if (NULL == subs) return -1;
if (cdm_frecv_subs::STATE_RUNNING != subs->state()) return 0;
switch (discard->dtype) {
case DISCARD_TYPE_CANCEL:
if (-1 == discard->data.i) { // discard all (close connection)
subs->send_discard(DISCARD_TYPE_DONE, subs->done_parts());
subs->stop(cdm_frecv_subs::EXTSTATE_ABORTED);
} else if (0 == discard->data.i) {
} else if (0 < discard->data.i) {
}
break;
case DISCARD_TYPE_DONE:
if (0 == subs->total_parts() || !subs->total_done())
subs->stop(cdm_frecv_subs::EXTSTATE_ABORTED);
else
subs->stop(cdm_frecv_subs::EXTSTATE_DONE);
break;
default:
break;
}
_ui->on_subs_ch(subs, cdm_uiproto::FSENDER_CH_ALL);
*ch_mask |= cdm_uiproto::FSENDER_CH_STATE;
return 0;
}
int cdm_core::appeal(cdm_fsender *const sender, int *const ch_mask) {
sdm_dtgm_appeal *appeal = (sdm_dtgm_appeal *)sender->dtgm();
if (appeal->session_id != sender->session_id()) return 0;
int mx_ap_sz = sender->pckt_sz() - sizeof(sdm_dtgm_appeal);
if ((appeal->count * (int)sizeof(int)) > mx_ap_sz) {
appeal->count = mx_ap_sz;
}
sender->send_data(appeal->ss_id, appeal->nums, appeal->count);
*ch_mask |= cdm_uiproto::FSENDER_CH_PROGRESS;
sender->set_done_parts(appeal->done_parts);
return 0;
}
int cdm_core::discard(cdm_fsender *const sender, int *const ch_mask) {
sdm_dtgm_discard *discard = (sdm_dtgm_discard *)sender->dtgm();
if (discard->session_id != sender->session_id()) return 0;
switch (discard->dtype) {
case DISCARD_TYPE_CANCEL:
if (-1 == discard->data.i) {
sender->send_discard(discard->ss_id, DISCARD_TYPE_DONE, sender->done_parts());
sender->stop(cdm_fsender::EXTSTATE_CANCELED);
} else if (0 == discard->data.i) {
sender->accepted();
} else if (0 < discard->data.i) {
if (0 > sender->add_parts(discard->data.i)) {
_pure_dm_error(ERC_FSENDER_FSIZE);
_ui_on_dm_error();
sender->stop();
}
}
break;
case DISCARD_TYPE_DONE:
sender->set_done_parts(discard->data.i);
sender->send_discard(discard->ss_id, DISCARD_TYPE_DONE, sender->done_parts());
sender->stop(cdm_fsender::EXTSTATE_DONE);
break;
default:
break;
}
*ch_mask |= cdm_uiproto::FSENDER_CH_PROGRESS;
*ch_mask |= cdm_uiproto::FSENDER_CH_STATE;
return 0;
}
cdm_frecver *cdm_core::new_frecver(const char *const host, const unsigned short port) {
_cdm_frecver *recver = new _cdm_frecver;
if (0 != recver->addr_info()->set(host, port)) {
delete recver;
_sock_error(ERC_SOCKSRESOLVE);
return NULL;
}
return recver;
}
cdm_fsender *cdm_core::new_fsender(const char *const host, const unsigned short port) {
_cdm_fsender *sender = new _cdm_fsender;
if (0 != sender->addr_info()->set(host, port)) {
delete sender;
_sock_error(ERC_SOCKSRESOLVE);
return NULL;
}
sender->iaddr()->set(host, port);
return sender;
}
int cdm_core::add_frecver(cdm_frecver *const recver) {
if (0 >= _frecvers.add((_cdm_frecver *)recver, 3000)) {
return _pure_dm_error(ERC_ADDFRECVER);
}
return 0;
}
int cdm_core::add_fsender(cdm_fsender *const sender) {
if (0 >= _fsenders.add((_cdm_fsender *)sender, 3000)) {
return _pure_dm_error(ERC_ADDFSENDER);
}
return 0;
}
int cdm_core::start_frecver(cdm_frecver *const recver, const bool delayed) {
if (0 != recver->start(delayed)) return _error(ERC_STARTFRECVER);
return 0;
}
int cdm_core::start_fsender(cdm_fsender *const sender, const bool delayed) {
if (0 != sender->start(delayed)) return _error(ERC_STARTFSENDER);
return 0;
}
int cdm_core::del_frecver(cdm_frecver *const recver) {
cdm_frecv_subs *subs;
while (NULL != (subs = recver->subs_first())) {
_ui->on_subs_rm(subs);
recver->kill_subs(subs);
}
_ui->on_frecver_rm(recver);
if (0 != _frecvers.del((_cdm_frecver *)recver, 3000)) return -1;
return 0;
}
int cdm_core::del_fsender(cdm_fsender *const sender) {
_ui->on_fsender_rm(sender);
if (0 != _fsenders.del((_cdm_fsender *)sender, 3000)) return -1;
return 0;
}
int cdm_core::free_frecver(cdm_frecver *const recver) {
delete (_cdm_frecver *)recver;
return 0;
}
int cdm_core::free_fsender(cdm_fsender *const sender) {
delete (_cdm_fsender *)sender;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// cdm_core protected definition
int cdm_core::_run() {
// if (NULL != _running_mtx) CloseHandle(_running_mtx);
// _running_mtx = CreateMutex(NULL, FALSE, NULL);
WaitForSingleObject(_running_mtx, INFINITE);
// _must_stop = false;
while (!_must_stop) {
//_speeed = 0;
int job_recv;
int job_send;
int rev;
rev = _parse_frecvers(&job_recv);
rev = _parse_fsenders(&job_send);
if (0 == job_recv + job_send) Sleep(_nulljob_delay);
}
_cdm_fsender *sender;
while (NULL != (sender = (_cdm_fsender *)_fsenders.first())) {
del_fsender(sender);
free_fsender(sender);
}
_cdm_frecver *recver;
while (NULL != (recver = (_cdm_frecver *)_frecvers.first())) {
cdm_frecv_subs *subs;
while (NULL != (subs = recver->subs_first())) {
_ui->on_subs_rm(subs);
recver->kill_subs(subs);
}
del_frecver(recver);
free_frecver(recver);
}
_ui->on_quit();
ReleaseMutex(_running_mtx);
// CloseHandle(_running_mtx);
// _running_mtx = NULL;
return 0;
}
int cdm_core::_parse_frecvers(int *const num) {
if (NULL != num) *num = 0;
if (0 != _frecvers.lock()) return -1;
int c = 0;
_cdm_frecver *recver = (_cdm_frecver *)_frecvers.first();
while (NULL != recver) {
int ch_mask = 0;
switch (recver->state()) {
case cdm_frecver::STATE_RUNNING:
if (0 != swallow(recver, &ch_mask)) {
_ui_on_error();
recver->stop();
ch_mask = cdm_uiproto::FRECVER_CH_ALL;
} else ++c;
break;
case cdm_frecver::STATE_LAUNCHED:
if (0 != recver->start()) {
_sock_error(ERC_STARTFSENDER);
_ui_on_error();
recver->stop();
}
ch_mask |= cdm_uiproto::FRECVER_CH_ALL;
break;
default:
break;
}
if (0 != ch_mask) _ui->on_frecver_ch(recver, ch_mask);
if (recver->is_dying()) {
_cdm_frecver *victim = recver;
recver = (_cdm_frecver *)recver->next();
del_frecver(victim);
free_frecver(victim);
} else recver = (_cdm_frecver *)recver->next();
}
while (0 != _frecvers.ulock());
if (NULL != num) *num = c;
return 0;
}
int cdm_core::_parse_fsenders(int *const num) {
if (NULL != num) *num = 0;
if (0 != _fsenders.lock()) return -1;
int c = 0;
_cdm_fsender *sender = (_cdm_fsender *)_fsenders.first();
while (NULL != sender) {
int ch_mask = 0;
switch (sender->state()) {
case cdm_fsender::STATE_RUNNING:
_speeed_prev = sender->done_parts();
if (0 != spit(sender, &ch_mask)) {
_ui_on_error();
} else ++c;
_speeed += sender->done_parts() - _speeed_prev;
sender->update_time();
break;
case cdm_fsender::STATE_LAUNCHED:
if (0 != sender->start()) {
_error(ERC_STARTFSENDER);
_ui_on_error();
sender->stop();
}
ch_mask = cdm_uiproto::FSENDER_CH_ALL;
break;
default:
break;
}
if (0 != ch_mask) _ui->on_fsender_ch(sender, ch_mask);
if (sender->is_dying()) {
_cdm_fsender *victim = sender;
sender = (_cdm_fsender *)sender->next();
del_fsender(victim);
free_fsender(victim);
} else sender = (_cdm_fsender *)sender->next();
}
while (0 != _fsenders.ulock());
if (NULL != num) *num = c;
return 0;
}
// private
bool cdm_core::_use_bugs = false;
} // end of namespace "dm_core"
Соседние файлы в папке main