Добавил:
korayakov
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Лабы / 2 / lab.01.by mice / fexchange / fx_net
.cpp/*******************************************************************************
* file: fx_net.cpp *
* version: 0.0.1 *
* author: inba (mailto:inba@mail.ru) *
* description: not available *
*******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
// program specific headers
#include "fx_net.h"
namespace fx_ns {
/*******************************************************************************
* definitions *
*******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
// constants
static BYTE winsock_ver_hi = 2;
static BYTE winsock_ver_low = 0;
////////////////////////////////////////////////////////////////////////////////
// functions (definitions)
WORD version_required() {
return MAKEWORD(winsock_ver_hi, winsock_ver_low);
}
////////////////////////////////////////////////////////////////////////////////
// cfx_socket (public definitions)
cfx_socket::cfx_socket() {
_kill_mtx = CreateMutex(NULL, FALSE, NULL);
_socket = INVALID_SOCKET;
_last_error = 0;
_on_event = NULL;
_owner = NULL;
_ext_id = NULL;
}
cfx_socket::cfx_socket(void *const owner, const tfx_socket_event ev_handler, void *const ext_id) {
_kill_mtx = CreateMutex(NULL, FALSE, NULL);
_socket = INVALID_SOCKET;
_last_error = 0;
_on_event = ev_handler;
_owner = owner;
_ext_id = ext_id;
}
cfx_socket::~cfx_socket() {
if (INVALID_SOCKET != _socket) closesocket(_socket);
CloseHandle(_kill_mtx);
}
void cfx_socket::set_linger(unsigned short on_off, unsigned short t) {
linger sling;
sling.l_linger = on_off;
sling.l_onoff = t;
setsockopt(_socket, SOL_SOCKET, SO_LINGER, (char *)&sling, sizeof(sling));
}
void cfx_socket::get_linger(unsigned short *on_off, unsigned short *t) const {
linger slinger;
int opt_len = sizeof(slinger);
getsockopt(_socket, SOL_SOCKET, SO_LINGER, (char *)&slinger, &opt_len);
if (NULL != on_off) *on_off = slinger.l_onoff;
if (NULL != t) *t = slinger.l_linger;
}
int cfx_socket::resolve_addr(const char *const addr, in_addr *const raddr) {
raddr->s_addr = inet_addr(addr);
// 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 == raddr->s_addr) {
hostent *host;
host = gethostbyname(addr);
if (NULL == host) return ERC_SOCK_RESOLVE;
memcpy(raddr, host->h_addr_list[0], host->h_length);
}
return OK_OK;
}
int cfx_socket::create() {
_saddr_in.sin_family = AF_INET;
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == _socket) return _wsa_error(ERC_SOCK_SOCKET);
return OK_OK;
}
int cfx_socket::create(const SOCKET sock, const sockaddr_in *const saddr_in) {
_socket = sock;
_saddr_in = *saddr_in;
return OK_OK;
}
int cfx_socket::kill() {
if (INVALID_SOCKET != _socket) {
if (SOCKET_ERROR == closesocket(_socket))
return _wsa_error(ERC_SOCK_CLOSE);
}
return OK_OK;
}
////////////////////////////////////////////////////////////////////////////////
// cfx_server (protected definitions)
void cfx_server::_init() {
_stoped = true;
_fs_sock = INVALID_SOCKET;
_accept_thread_id = NULL;
_accept_thread_h = NULL;
_mx_pc = _def_mx_pc;
_buf_sz = _def_buf_sz;
}
DWORD __stdcall cfx_server::_accept_proc(cfx_server *const server) {
WaitForSingleObject(server->kill_mtx(), INFINITE);
for (;;) {
server->_stoped = false;
server->_call_event(EV_LISTENING, NULL);
sfx_accept_struct acst;
acst.addr_len = sizeof(acst);
acst.asock = accept(server->sock(), (sockaddr *)&acst.addr, &acst.addr_len);
if (server->_stoped) {
// if (0 != ioctlsocket(server->sock(), FIONBIO, 0)) {
// server->_wsa_error();
// server->_call_event(EV_ERROR, TO_PVOID(ERC_SOCK_IOSTL));
// }
if (INVALID_SOCKET != server->_fs_sock) {
closesocket(server->_fs_sock);
server->_fs_sock = INVALID_SOCKET;
}
int res = server->_call_event(EV_STOPPING, TO_PVOID(EV_STR_USER));
if (OK_CANCEL != res) {
server->_call_event(EV_STOPED, TO_PVOID(EV_STR_USER));
if (INVALID_SOCKET != acst.asock) closesocket(acst.asock);
ReleaseMutex(server->kill_mtx());
return OK_OK;
}
continue;
}
if (INVALID_SOCKET == acst.asock) {
server->_wsa_error();
server->_call_event(EV_ERROR, TO_PVOID(ERC_SERV_INVSOCKAC));
int res = server->_call_event(EV_STOPPING, TO_PVOID(ERC_SERV_INVSOCKAC));
if (OK_CANCEL != res) {
server->_call_event(EV_STOPED, TO_PVOID(ERC_SERV_INVSOCKAC));
ReleaseMutex(server->kill_mtx());
return ERC_SERV_INVSOCKAC;
}
continue;
}
// tell about new connection and if not accepted, continue listening
int res = server->_call_event(EV_ACCEPTING, &acst);
if (OK_CANCEL == res) {
closesocket(acst.asock);
continue;
}
if (OK_OK != res) {
//TODO: handle some errors
}
// run client socket for downloading
cfx_client *client = server->new_client();
client->create(acst.asock, &acst.addr);
client->set_parent(server);
if (OK_OK != server->_call_event(EV_ACCEPTED, client)) server->del_client(client);
}
ReleaseMutex(server->kill_mtx());
return (DWORD)OK_OK;
}
////////////////////////////////////////////////////////////////////////////////
// cfx_server (public definitions)
cfx_server::~cfx_server() {
if (INVALID_SOCKET != _fs_sock) closesocket(_fs_sock);
}
int cfx_server::bind(const char *const addr, const unsigned short port) {
saddr_in()->sin_port = htons(port);
int res = resolve_addr(addr, &saddr_in()->sin_addr);
if (OK_OK != res) return _wsa_error(res);
res = ::bind(sock(), (sockaddr *)saddr_in(), saddr_in_sz());
if (0 != res) return _wsa_error(ERC_SOCK_BIND);
res = listen(sock(), _mx_pc);
if (0 != res) return _wsa_error(ERC_SOCK_LISTEN);
return OK_OK;
}
int cfx_server::run() {
_accept_thread_h = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(_accept_proc), (void *)this,
0, &_accept_thread_id);
if (NULL == _accept_thread_h) return _not_wsa_error(ERC_CRTHREAD);
return OK_OK;
}
int cfx_server::stop() {
_stoped = true;
// int nb_mode = 1;
// if (0 != ioctlsocket(sock(), FIONBIO, (u_long *)&nb_mode))
// return _wsa_error(ERC_SOCK_STOP);
// try to create fake socket to stop server
_fs_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == _fs_sock) return _wsa_error(ERC_SERV_CANTSTOPC);
int res = ::connect(_fs_sock, (sockaddr *)saddr_in(), sizeof(sockaddr_in));
if (0 != res) {
closesocket(_fs_sock);
_fs_sock = INVALID_SOCKET;
return _wsa_error(ERC_SERV_CANTSTOPC);
}
return OK_OK;
}
int cfx_server::kill(const bool wait) {
if (wait) {
stop();
WaitForSingleObject(kill_mtx(), INFINITE);
ReleaseMutex(kill_mtx());
return cfx_socket::kill();
} else {
//FIXME:
int res = cfx_socket::kill();
stop();
TerminateThread(_accept_thread_h, 0);
return res;
}
return OK_OK;
}
cfx_client *cfx_server::new_client() const {
return new cfx_client;
}
void cfx_server::del_client(cfx_client *clnt) {
delete clnt;
}
////////////////////////////////////////////////////////////////////////////////
// cfx_client (public definitions)
int cfx_client::connect(const char *const addr, const unsigned short port) {
saddr_in()->sin_port = htons(port);
int res = resolve_addr(addr, &saddr_in()->sin_addr);
if (OK_OK != res) return _wsa_error(res);
res = ::connect(sock(), (sockaddr *)saddr_in(), saddr_in_sz());
if (0 != res) return _wsa_error(ERC_SOCK_CONNECT);
return OK_OK;
}
int cfx_client::recv_file() {
_thread_h = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(_recv_proc), (void *)this,
0, &_thread_id);
if (NULL == _thread_h) return _not_wsa_error(ERC_CRTHREAD);
return OK_OK;
}
int cfx_client::send_file(char *const filename) {
_filename = filename;
_thread_h = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(_send_proc), (void *)this,
0, &_thread_id);
if (NULL == _thread_h) return _not_wsa_error(ERC_CRTHREAD);
return OK_OK;
}
////////////////////////////////////////////////////////////////////////////////
// cfx_client (protected definitions)
void cfx_client::_init() {
_filename = NULL;
_buf_sz = _def_buf_sz;
}
DWORD __stdcall cfx_client::_recv_proc(cfx_client *const client) {
client->_call_event(EV_WAITING4DATA, NULL);
unsigned int file_sz = -1;
int res = recv(client->sock(), (char *)&file_sz, sizeof(file_sz), 0);
client->_call_event(EV_RECVING_INFO, NULL);
sfx_file_info finfo;
finfo.total_sz = file_sz;
finfo.filename = NULL;
finfo.done_sz = 0;
finfo.file = NULL;
finfo.buf = NULL;
finfo.buf_sz = 0;
client->_call_event(EV_RECVED_INFO, &finfo);
client->_call_event(EV_NEED_FILE2W, &finfo);
client->_filename = finfo.filename;
finfo.buf = new char[client->_buf_sz];
finfo.buf_sz = client->_buf_sz;
if (0 < strlen(finfo.filename)) {
cfx_fblk fblk;
if (0 != fblk.block(finfo.filename)) finfo.file = NULL;
else finfo.file = fopen(finfo.filename, "wb");
} else {
finfo.file = NULL;
}
if (NULL == finfo.file) {
client->_not_wsa_error();
client->_call_event(EV_KILLING, TO_PVOID(ERC_CLNT_CANTCRFL));
closesocket(client->sock());
client->_call_event(EV_KILLED, NULL);
return ERC_ERROR;
}
client->_call_event(EV_RECVING_DATA, &finfo);
for(;;) {
res = recv(client->sock(), finfo.buf, finfo.buf_sz, 0);
if (res == SOCKET_ERROR) {
client->_wsa_error();
client->_call_event(EV_KILLING, TO_PVOID(ERC_CLNT_ERRECV));
break;
}
if (res == 0) break;
fwrite(finfo.buf, sizeof(char), res, finfo.file);
finfo.done_sz += res;
client->_call_event(EV_RECVED_DATA, &finfo);
}
if (SOCKET_ERROR != res && 0 != res)
client->_call_event(EV_RECV_END, TO_PVOID(OK_OK));
if (finfo.done_sz != finfo.total_sz)
client->_call_event(EV_ERROR, TO_PVOID(ERC_CLNT_SZ_DM));
cfx_fblk fblk;
fblk.ublock(finfo.filename);
fclose(finfo.file);
delete[] finfo.buf;
client->_call_event(EV_KILLED, NULL);
return OK_OK;
}
DWORD __stdcall cfx_client::_send_proc(cfx_client *const client) {
client->_call_event(EV_SENDING_INFO, NULL);
sfx_file_info finfo;
finfo.filename = client->_filename;
if (0 < strlen(finfo.filename)) {
cfx_fblk fblk;
if (0 != fblk.block(finfo.filename)) finfo.file = NULL;
else finfo.file = fopen(finfo.filename, "rb");
} else {
finfo.file = NULL;
}
if (NULL == finfo.file) {
client->_not_wsa_error();
client->_call_event(EV_KILLING, TO_PVOID(ERC_CLNT_CANTOPNFL));
closesocket(client->sock());
client->_call_event(EV_KILLED, NULL);
return ERC_ERROR;
}
fseek(finfo.file, 0, SEEK_END);
// finfo.total_sz = ftell(finfo.file);
fpos_t filesize64;
fgetpos(finfo.file, &filesize64);
finfo.total_sz = filesize64;
fseek(finfo.file, 0, SEEK_SET);
finfo.done_sz = 0;
finfo.buf = new char[client->_buf_sz];
finfo.buf_sz = client->_buf_sz;
unsigned int file_sz;
// file_sz[0] = 0;
// file_sz[1] = finfo.totalsz_hi;
file_sz = finfo.total_sz;
int res = send(client->sock(), (char *)&file_sz, sizeof(file_sz), 0);
client->_call_event(EV_SENT_INFO, &finfo);
client->_call_event(EV_SENDING_DATA, &finfo);
while(!feof(finfo.file)) {
res = (int)fread(finfo.buf, sizeof(char), finfo.buf_sz, finfo.file);
finfo.done_sz += res;
res = send(client->sock(), finfo.buf, res, 0);
if (SOCKET_ERROR == res) {
client->_wsa_error();
client->_call_event(EV_KILLING, TO_PVOID(ERC_CLNT_ERSEND));
break;
}
client->_call_event(EV_SENT_DATA, &finfo);
}
if (SOCKET_ERROR != res) {
client->_call_event(EV_SEND_END, &finfo);
}
cfx_fblk fblk;
fblk.ublock(finfo.filename);
fclose(finfo.file);
closesocket(client->sock());
delete finfo.buf;
client->_call_event(EV_KILLED, NULL);
return OK_OK;
}
}; // end of namespace "fx_ns"
Соседние файлы в папке fexchange