Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы / 2 / lab.03.by mice / claw / client

.cpp
Скачиваний:
12
Добавлен:
17.04.2013
Размер:
17.38 Кб
Скачать
/*******************************************************************************
* file:         client.cpp                                                     *
* version:      0.0.1                                                          *
* author:       d-evil [tmd] (mailto:d-evil.tmd@mail.ru)                       *
* description:  not available                                                  *
*******************************************************************************/

#include "client.h"


////////////////////////////////////////////////////////////////////////////////
// ccw_server public definition
ccw_client::ccw_client() {
	_is_sender = true;
	_parent = NULL;
	_hicon = NULL;
	_run_mtx = CreateMutex(NULL, 0, NULL);
	_pause_mtx = CreateMutex(NULL, 0, NULL);
	_thread_h = NULL;
	_thread_id = 0;
	_stoped = false;
	_paused = false;
	_run_btn_state = -1;
	_pause_btn_state = -1;
	_claw_id = 0;

	_total_sz = -1;
	_done_sz = -1;
}


ccw_client::~ccw_client() {
	ReleaseMutex(_run_mtx);
	ReleaseMutex(_pause_mtx);
}


int ccw_client::change_mode(const bool is_sender) {
	if (NULL != GetSafeHwnd()) return -1;

	_is_sender = is_sender;

	return 0;
}


int ccw_client::set_caption() {
	CString cap;
	if (NULL != _parent) {
		_parent->GetWindowText(cap);
	} else cap = "Claw /root";

	CString name;
	if (_is_sender) name = "senders";
	else name = "receivers";

	if (_sock.is_connected()) {
		name.AppendFormat("/%s:%s", _sock.iaddr()->host(), _sock.iaddr()->port_str());
	}

	cap.AppendFormat("/%s", name);
	SetWindowText(cap);
	return 0;
}


int ccw_client::update_recver() {
	if (NULL == GetSafeHwnd() || _is_sender) return -1;

	_edit_host->SetWindowText(_sock.iaddr()->host());
	_edit_ip->SetWindowText(_sock.iaddr()->ip_str());
	_edit_port->SetWindowText(_sock.iaddr()->port_str());

	set_caption();

	return 0;
}


int ccw_client::give_life() {
	Create(IDD_DLG_CLIENT, _parent);
	ShowWindow(SW_SHOW);

	return 0;
}


int ccw_client::take_life() {
	return 0;
}


BOOL ccw_client::OnInitDialog() {
	if (NULL !=_hicon) SetIcon(_hicon, FALSE);

	_edit_host = (CEdit *)GetDlgItem(IDC_EDIT_HOST);
	_edit_ip = (CEdit *)GetDlgItem(IDC_EDIT_IP);
	_edit_port = (CEdit *)GetDlgItem(IDC_EDIT_PORT);
	_edit_file = (CEdit *)GetDlgItem(IDC_EDIT_FILE);
	_edit_size = (CEdit *)GetDlgItem(IDC_EDIT_SIZE);
	_edit_status = (CEdit *)GetDlgItem(IDC_EDIT_STATUS);
	_edit_time = (CEdit *)GetDlgItem(IDC_EDIT_TIME);
	_progress_bar = (CProgressCtrl *)GetDlgItem(IDC_BAR);
	_btn_browse = (CButton *)GetDlgItem(IDC_BTN_BROWSE);
	_btn_run = (CButton *)GetDlgItem(IDC_BTN_RUN);
	_btn_pause = (CButton *)GetDlgItem(IDC_BTN_PAUSE);
	_btn_exit = (CButton *)GetDlgItem(IDC_BTN_EXIT);

	_init_controls();

	return TRUE;
}


void ccw_client::OnClose() {
	if (!_stoped) stop();

	if (WAIT_TIMEOUT == WaitForSingleObject(_run_mtx, 100)) {
		PostMessage(WM_CLOSE, 0, 0);
		return;
	}

	if (NULL != _parent) {
		_parent->PostMessage(MSG_DEL_CLIENT, _claw_id, 0);
	} else {
		EndDialog(0);
		delete this;	// guess it will not work :)
	}
}


int ccw_client::run() {
	_thread_h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_client_proc_helper, this, 0, &_thread_id);
	if (NULL == _thread_h) return -1;

	return 0;
}


int ccw_client::stop() {
	_stoped = true;
	if (_paused) upause();

	return 0;
}


int ccw_client::pause() {
	_set_pbtn_state(0);
	if (WAIT_TIMEOUT == WaitForSingleObject(_pause_mtx, 5000)) return -1;
	_paused = true;

	return 0;
}


int ccw_client::upause() {
	_set_pbtn_state(0);
	_paused = false;
	ReleaseMutex(_pause_mtx);

	return 0;
}


int ccw_client::wait(const int timeout) {
	if (WAIT_TIMEOUT == WaitForSingleObject(_run_mtx, timeout))
		return -1;

	return 0;
}


int ccw_client::recv_header() {
	if (_is_sender || !_sock.is_connected()) return -1;

	clock_t t1 = clock();
	clock_t t2;

	do {
		t2 = clock();
		if (0 > _sock.CanRead()) continue;

		int rev = _sock.Receive((char *)&_total_sz, sizeof(_total_sz));
		if (sizeof(_total_sz) != rev) return -1;

		CString str;
		size_to_str(_total_sz, str);
		_edit_size->SetWindowText(str);

		return 0;

	} while (t2 - t1 < READ_SZ_TIMEOUT*CLOCKS_PER_SEC);

	return -1;
}


ccw_client *ccw_client::mk_client(const int claw_id, const bool is_sender) {
	ccw_client *clnt = new ccw_client;
	clnt->set_claw_id(claw_id);
	clnt->_is_sender = is_sender;

	return clnt;
}


int ccw_client::rm_client(ccw_client *const clnt) {
	if (NULL == clnt) return -1;
	delete clnt;

	return 0;
}



////////////////////////////////////////////////////////////////////////////////
// ccw_server protected definition
BEGIN_MESSAGE_MAP(ccw_client, CDialog)
	ON_WM_CLOSE()
	ON_COMMAND(IDC_BTN_BROWSE, _on_btn_browse)
	ON_COMMAND(IDC_BTN_RUN, _on_btn_run)
	ON_COMMAND(IDC_BTN_PAUSE, _on_btn_pause)
	ON_COMMAND(IDC_BTN_EXIT, _on_btn_exit)
END_MESSAGE_MAP()


void ccw_client::_on_btn_browse() {
	if (_is_sender) _sender_browse();
	else _recver_browse();
}


void ccw_client::_on_btn_run() {
	switch (_run_btn_state) {
		case 1: run(); break;
		case 2: stop(); break;
		default: break;
	}
}


void ccw_client::_on_btn_pause() {
	switch (_pause_btn_state) {
		case 1: pause(); break;
		case 2: upause(); break;
		default: break;
	}
}


void ccw_client::_on_btn_exit() {
	PostMessage(WM_CLOSE, 0, 0);
}


void ccw_client::_init_controls() {
	if (0 != _sock.iaddr()->set_to_local()) {
		show_error_msg("Can't set local address", 0, this);
	}

	_edit_host->SetWindowText(_sock.iaddr()->host());
	_edit_ip->SetWindowText(_sock.iaddr()->ip_str());
	_edit_port->SetWindowText(_sock.iaddr()->port_str());

	_edit_size->SetWindowText("none");
	_edit_status->SetWindowText("none");
	_edit_time->SetWindowText("--:--:--");

	if (_is_sender) _ulock_edits();
	else _lock_edits();

	_set_rbtn_state(1);
	_set_pbtn_state(0);

	set_caption();
}


void ccw_client::_lock_edits() {
	_edit_host->PostMessage(EM_SETREADONLY, TRUE, 0);
	_edit_port->PostMessage(EM_SETREADONLY, TRUE, 0);
}


void ccw_client::_ulock_edits() {
	_edit_host->PostMessage(EM_SETREADONLY, FALSE, 0);
	_edit_port->PostMessage(EM_SETREADONLY, FALSE, 0);
}


void ccw_client::_lock_file_edit() {
	_edit_file->PostMessage(EM_SETREADONLY, TRUE, 0);
	_btn_browse->EnableWindow(FALSE);
	SetFocus();
}


void ccw_client::_ulock_file_edit() {
	_edit_file->PostMessage(EM_SETREADONLY, FALSE, 0);
	_btn_browse->EnableWindow(TRUE);
}


void ccw_client::_set_rbtn_state(const int st) {
	if (st == _run_btn_state) return;
	_run_btn_state = st;

	switch (st) {
		case 1:
			if (_is_sender) _btn_run->SetWindowText("Send");
			else _btn_run->SetWindowText("Accept");
			_btn_run->EnableWindow(TRUE);
			break;

		case 2:
			_btn_run->SetWindowText("Cancel");
			_btn_run->EnableWindow(TRUE);
			break;

		default:
			_btn_run->SetWindowText("N/A");
			_btn_run->EnableWindow(FALSE);
			SetFocus();
			break;
	}
}


void ccw_client::_set_pbtn_state(const int st) {
	if (st == _pause_btn_state) return;
	_pause_btn_state = st;

	switch (st) {
		case 1:
			_btn_pause->SetWindowText("Pause");
			_btn_pause->EnableWindow(TRUE);
			break;

		case 2:
			_btn_pause->SetWindowText("Resume");
			_btn_pause->EnableWindow(TRUE);
			break;

		default:
			_btn_pause->SetWindowText("N/A");
			_btn_pause->EnableWindow(FALSE);
			SetFocus();
			break;
	}
}


void ccw_client::_sender_browse() {
	CString fname;
	_edit_file->GetWindowText(fname);
	CString filter = "All Files (*.*)|*.*|Text files (*.txt;*.doc;*.rtf;*.inf)|*.txt;*.doc;*.rtf;*.inf|Applications (*.exe;*.com;*.bat)|*.exe;*.com;*.bat|Images (*.bmp;*.jpeg;*.jpg;*.gif;*.psd)|*.bmp;*.jpeg;*.jpg;*.gif;*.psd||";
	CFileDialog fdlg(TRUE, NULL, fname,
		OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_NOTESTFILECREATE,
		filter, this, 0
	);
	if (IDOK == fdlg.DoModal()) {
		fname = fdlg.GetPathName();
		_edit_file->SetWindowText(fname);
		HANDLE hf = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
							   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (INVALID_HANDLE_VALUE != hf) {
			DWORD sz = GetFileSize(hf, NULL);
			CloseHandle(hf);
			size_to_str(sz, fname);
			_edit_size->SetWindowText(fname);
		} else _edit_size->SetWindowText("none");
	}
}


void ccw_client::_recver_browse() {
	CString fname;
	_edit_file->GetWindowText(fname);
	CString filter = "All Files (*.*)|*.*|Text files (*.txt;*.doc;*.rtf;*.inf)|*.txt;*.doc;*.rtf;*.inf|Applications (*.exe;*.com;*.bat)|*.exe;*.com;*.bat|Images (*.bmp;*.jpeg;*.jpg;*.gif;*.psd)|*.bmp;*.jpeg;*.jpg;*.gif;*.psd||";
	CFileDialog fdlg(FALSE, NULL, fname,
		OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_NOTESTFILECREATE,
		filter, this, 0
	);

	if (IDOK != fdlg.DoModal()) return;

	fname = fdlg.GetPathName();
	_edit_file->SetWindowText(fname);
}


int ccw_client::_sender_proc() {
	_stoped = false;
	_progress_bar->SetPos(0);
	_edit_time->SetWindowText("00:00:00");

	if (WAIT_TIMEOUT == WaitForSingleObject(_run_mtx, 10000)) {
		show_error_msg("Can't launch sender (скорее всего уже и не получится:)", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		return -1;
	}

	// [entering level 0] (lock controls, gather info and try to open file)
	_edit_status->SetWindowText("gathering information...");
	_lock_edits();
	_lock_file_edit();
	_set_rbtn_state(0);
	_set_pbtn_state(0);

	CString host;
	_edit_host->GetWindowText(host);
	CString port_str;
	_edit_port->GetWindowText(port_str);
	unsigned short port = atoi(port_str);
	CString fname;
	_edit_file->GetWindowText(fname);

	_edit_status->SetWindowText("opening file...");
	HANDLE hf = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ,
						   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hf) {
		show_error_msg("Can't open file for reading", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_0;
	}
	_total_sz = GetFileSize(hf, NULL);
	_done_sz = 0;

	// [entering level 1] (resolve host and create socket)
	_edit_status->SetWindowText("resolving host...");
	if (0 != _sock.iaddr()->set(host, port)) {
		show_error_msg("Can't resolve host", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_1;
	}

	_edit_host->SetWindowText(_sock.iaddr()->host());
	_edit_port->SetWindowText(_sock.iaddr()->port_str());
	_edit_ip->SetWindowText(_sock.iaddr()->ip_str());

	if (0 != _sock.Create()) {
		show_error_msg("Can't create socket", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_1;
	}

	// [entering level 2] (try to connect and allocate buffer)
	_edit_status->SetWindowText("connecting...");
	if (0 != _sock.Connect()) {
		show_error_msg("Can't establish connection", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_2;
	}

	_edit_status->SetWindowText("allocating buffer...");
	char *buf = (char *)malloc(SOCK_IO_BUF_SZ * sizeof(char));
	if (NULL == buf) {
		show_error_msg("Can't allocate buffer (no memory)", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_2;
	}

	// [entering level 3] (sending loop)
	_set_rbtn_state(2);
	_set_pbtn_state(1);
	set_caption();

	_edit_status->SetWindowText("sending...");
	clock_t t_base = clock();
	clock_t up_time = 0;

	// send file size
	_sock.Send((char *)&_total_sz, sizeof(_total_sz));

	while (!_stoped) {
		clock_t tmp_clock = clock() - t_base;
		if (CLOCKS_PER_SEC/3 < tmp_clock - up_time) {
			CString str;
			clock_to_str(tmp_clock, str);
			_edit_time->SetWindowText(str);
			up_time = tmp_clock;
		}

		if (_paused) {
			_edit_status->SetWindowText("paused.");
			_set_pbtn_state(2);
			WaitForSingleObject(_pause_mtx, INFINITE);
			ReleaseMutex(_pause_mtx);
			_set_pbtn_state(1);
			_edit_status->SetWindowText("sending...");
			t_base = clock() - tmp_clock;
		}		

		int rev = _sock.CanWrite();
		if (0 > rev) {
			show_error_msg("Can't select() socket for writing", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_2;
		}
		if (0 >= rev) continue;

		DWORD dwr;
		if (0 == ReadFile(hf, buf, SOCK_IO_BUF_SZ, &dwr, NULL)) {
			show_error_msg("Can't read from opened file", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_3;
		}
		if (0 == dwr) {
			show_error_msg("Error reading file", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_3;
		}
		rev = _sock.Send(buf, dwr);
		if (rev != dwr) {
			show_error_msg("Can't send data", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_3;
		}
		_done_sz += dwr;
		if (_done_sz == _total_sz) {
			_progress_bar->SetPos(100);
			_edit_status->SetWindowText("done.");
			goto exit_level_3;
		}
		if (_done_sz > _total_sz) {
			show_error_msg("Wrong file size - streams not supported in free version", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_3;
		}

		double pos = 100*(double)_done_sz / (double)_total_sz;
		_progress_bar->SetPos((int)ceil(pos));
	}
	if (_stoped) _edit_status->SetWindowText("stoped via user.");

exit_level_3:
	free(buf);

exit_level_2:
	_sock.Close();

exit_level_1:
	CloseHandle(hf);

exit_level_0:
	_ulock_edits();
	_ulock_file_edit();
	_set_rbtn_state(1);
	_set_pbtn_state(0);
	set_caption();
	ReleaseMutex(_run_mtx);
	_stoped = true;

	return 0;
}


int ccw_client::_recver_proc() {
	_stoped = false;
	_progress_bar->SetPos(0);
	_edit_time->SetWindowText("00:00:00");
	bool no_way_back = false;

	if (WAIT_TIMEOUT == WaitForSingleObject(_run_mtx, 10000)) {
		show_error_msg("Can't launch receiver (скорее всего уже и не получится:)", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		return -1;
	}

	// [entering level 0] (lock controls and try to open file for writing)
	// setting buttons and edits
	_edit_status->SetWindowText("opening file...");
	_lock_edits();
	_lock_file_edit();
	_set_rbtn_state(0);
	_set_pbtn_state(0);

	CString fname;
	_edit_file->GetWindowText(fname);
	HANDLE hf = CreateFile(fname, GENERIC_WRITE, FILE_SHARE_READ,
						   NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hf) {
		show_error_msg("Can't open file for writing", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_0;
	}

	// [entering level 1] (allocating buffer)
	_edit_status->SetWindowText("allocating buffer...");
	char *buf = (char *)malloc(SOCK_IO_BUF_SZ * sizeof(char));
	if (NULL == buf) {
		show_error_msg("Can't get memory for read buffer", 0, this);
		_edit_status->SetWindowText("stoped via error.");
		goto exit_level_1;
	}

	// [entering level 2] (startint recving)
	_edit_status->SetWindowText("receiving...");
	_set_rbtn_state(2);
	_set_pbtn_state(1);

	_done_sz = 0;
	while (0 > _total_sz) Sleep(200);

	clock_t t_base = clock();
	clock_t up_time = 0;

	no_way_back = true;
	while (!_stoped) {
		clock_t tmp_clock = clock() - t_base;
		if (CLOCKS_PER_SEC/3 < tmp_clock - up_time) {
			CString str;
			clock_to_str(tmp_clock, str);
			_edit_time->SetWindowText(str);
			up_time = tmp_clock;
		}

		if (_paused) {
			_edit_status->SetWindowText("paused.");
			_set_pbtn_state(2);
			WaitForSingleObject(_pause_mtx, INFINITE);
			ReleaseMutex(_pause_mtx);
			_set_pbtn_state(1);
			_edit_status->SetWindowText("receiving...");
			t_base = clock() - tmp_clock;
		}

		int rev = _sock.CanRead();
		if (0 > rev) {
			show_error_msg("Can't select() socket for reading", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_2;
		}
		if (0 >= rev) continue;

		rev = _sock.Receive(buf, SOCK_IO_BUF_SZ);
		if (0 >= rev) {
			show_error_msg("Can't receive anymore", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_2;
		}
		
		DWORD bwr;
		int wres = WriteFile(hf, buf, rev, &bwr, NULL);
		if (0 == wres || bwr != rev) {
			show_error_msg("Can't write to file", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_2;
		}
		_done_sz += rev;

		if (_done_sz > _total_sz) {
			show_error_msg("Wrong file size - streams not supported in free version", 0, this);
			_edit_status->SetWindowText("stoped via error.");
			goto exit_level_2;
		}
		if (_done_sz == _total_sz) {
			_progress_bar->SetPos(100);
			_edit_status->SetWindowText("done.");
			goto exit_level_2;
		}

		double pos = 100*(double)_done_sz / (double)_total_sz;
		_progress_bar->SetPos((int)ceil(pos));
	}
	if (_stoped) _edit_status->SetWindowText("stoped via user.");


exit_level_2:
	free(buf);
	_done_sz = -1;
	_total_sz = -1;

exit_level_1:
	CloseHandle(hf);

exit_level_0:
	if (no_way_back) {
		_set_rbtn_state(0);
		_set_pbtn_state(0);
		_sock.Close();
	} else {
		_set_rbtn_state(1);
		_set_pbtn_state(0);
		_ulock_file_edit();
	}
	ReleaseMutex(_run_mtx);
	_stoped = true;

	return 0;
}
Соседние файлы в папке claw