Сообщение Re[2]: Telnet client issue от 05.04.2019 5:27
Изменено 05.04.2019 6:53 Harvat
Re[2]: Telnet client issue
Здравствуйте, Kernan, Вы писали:
K>Здравствуйте, Harvat, Вы писали:
H>>Все хорошо, за исключением того, что для того чтобы создать новое подключение после завершения текущего нужен sleep на секунду после closesocket.
K>Возможно, надо делать Bind с so_reuseaddr, хотя в случае клиента это не обязательно как бы.
H>>Подскажите, чем обусловленна необходимость этого слипа?
K>Покажи код.
K>Здравствуйте, Harvat, Вы писали:
H>>Все хорошо, за исключением того, что для того чтобы создать новое подключение после завершения текущего нужен sleep на секунду после closesocket.
K>Возможно, надо делать Bind с so_reuseaddr, хотя в случае клиента это не обязательно как бы.
H>>Подскажите, чем обусловленна необходимость этого слипа?
K>Покажи код.
HRESULT CDevice::ws_init()
{
WSADATA ws_info;
if (WSAStartup (0x0202, &ws_info) != 0)
return E_FAIL;
if (ws_info.wVersion != 0x0202)
{
WSACleanup();
return E_FAIL;
}
return S_OK;
}
HRESULT CDevice::ws_socket_init(SOCKET* psocket, ULONG port, ULONG address, ULONG timeout)
{
HRESULT result = S_OK;
SOCKADDR_IN target = {0};
target.sin_family = AF_INET;
target.sin_port = htons((unsigned __int16)port);
target.sin_addr.s_addr = LE_TO_BE_32(address);
TIMEVAL socket_timeout = {timeout/1000, (timeout%1000)*1000};
ULONG mode[2] = {1, 0};
*psocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ((*psocket != INVALID_SOCKET) &&
(ioctlsocket(*psocket, FIONBIO, &(mode[0])) != SOCKET_ERROR) &&
(connect(*psocket, (SOCKADDR*)&target, sizeof(target)) != 0)
{
fd_set fd_write, fd_error;
FD_ZERO(&fd_write);
FD_ZERO(&fd_error);
FD_SET(*psocket, &fd_write);
FD_SET(*psocket, &fd_error);
select(0, NULL, &fd_write, &fd_error, &socket_timeout);
if (FD_ISSET(*psocket, &fd_write))
{
}
else
result = E_WSAERROR | WSAGetLastError();
}
else result = E_WSAERROR | WSAGetLastError();
if (FAILED(result))
closesocket(*psocket);
return result;
}
HRESULT CDevice::ws_done()
{
WSACleanup();
return S_OK;
}
HRESULT CDevice::ws_socket_done(SOCKET socket)
{
shutdown(socket, SD_BOTH);
closesocket(socket);
return S_OK;
}
HRESULT CDevice::ws_socket_wait(SOCKET socket, BOOL read, BOOL write, ULONG timeout)
{
HRESULT result = S_OK;
fd_set fd_read, fd_write, fd_error;
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
FD_ZERO(&fd_error);
FD_SET(socket, &fd_read);
FD_SET(socket, &fd_write);
FD_SET(socket, &fd_error);
TIMEVAL socket_timeout = {timeout/1000, (timeout%1000)*1000};
int wait_result = select(0, read ? &fd_read : NULL, write ? &fd_write : NULL, &fd_error, &socket_timeout);
switch (wait_result)
{
case 0:
result = E_TIMEOUT; break;
case SOCKET_ERROR:
result = E_WSAERROR | WSAGetLastError(); break;
default:
result = FD_ISSET(socket, &fd_error) ? E_WSAERROR | WSAGetLastError() : S_OK;
}
return result;
}
ULONG CDevice::ws_time_left(ULONG base, ULONG timeout)
{
ULONG time = GetTickCount();
return (time < (base + timeout)) ? (base + timeout - time) : 0;
}
HRESULT CDevice::ws_socket_write(SOCKET socket, void* buffer, ULONG length, ULONG timeout)
{
ULONG time = GetTickCount();
if (send(socket, (char*)buffer, length, 0) == SOCKET_ERROR)
return E_WSAERROR | WSAGetLastError();
// Wait for writability of the socket.
return ws_socket_wait(socket, FALSE, TRUE, ws_time_left(time, timeout));
}
HRESULT CDevice::ws_socket_read(SOCKET socket, void* buffer, ULONG minimum, ULONG maximum, ULONG* readed, ULONG timeout)
{
ULONG time = GetTickCount();
HRESULT result = S_OK;
ULONG count = 0;
char* pBuffer = (char*)buffer;
while (result == S_OK)
{
result = ws_socket_wait(socket, TRUE, FALSE, ws_time_left(time, timeout));
if (FAILED(result)) break;
int socket_result = recv(socket, pBuffer + count, maximum - count, 0);
if (socket_result == SOCKET_ERROR) {result = E_WSAERROR | WSAGetLastError(); break;}
count = count + socket_result;
if (count >= minimum) break;
}
if (readed) *readed = count;
return result;
}
HRESULT CDevice::ws_socket_clear(SOCKET socket)
{
char buffer[1024];
HRESULT result = S_OK;
while (SUCCEEDED(ws_socket_wait(socket, TRUE, FALSE, 0)))
{
int socket_result = recv(socket, buffer, sizeof(buffer), 0);
if (socket_result == 0)
{result = S_OK; break;}
if (socket_result == SOCKET_ERROR)
{result = E_WSAERROR | WSAGetLastError(); break;}
}
return result;
}
HRESULT CDevice::ws_telnet_command(SOCKET socket, const char* command, const char* ok, const char* error, char* input, ULONG input_length, ULONG timeout)
{
// Send command if not NULL.
// Then read back data if input buffer is not null.
// Read till ok or error strings are not present in input buffer or input buffer length exceeeded.
// Timeout is used for all operation regardless of number of reads.
if (command)
ws_socket_clear(socket);
HRESULT result = S_OK;
char* allocated_buffer = NULL;
if ((input == NULL) && (ok || error))
{
input_length = command ? (strlen(command) + input_length + 1000) : (input_length + 1);
allocated_buffer = command ? (char*)malloc(input_length) : (char*)malloc(input_length);
input = allocated_buffer;
if (allocated_buffer == NULL)
result = E_NORESOURCES;
}
ULONG time = GetTickCount();
if (command && SUCCEEDED(result))
result = (send(socket, command, strlen(command), 0) == SOCKET_ERROR) ? E_WSAERROR | WSAGetLastError() : result;
if (command && SUCCEEDED(result))
result = ws_socket_wait(socket, FALSE, TRUE, ws_time_left(time, timeout));
ULONG input_count = 0;
ULONG input_bytes = 0;
// Read result till success or fail or timeout.
while (input && SUCCEEDED(result))
{
if (SUCCEEDED(result))
result = ws_socket_wait(socket, TRUE, FALSE, ws_time_left(time, timeout));
if (SUCCEEDED(result))
result = ws_socket_read(socket, input + input_count, 1, input_length - input_count - 1, &input_bytes, ws_time_left(time, timeout));
if (SUCCEEDED(result))
{
input_count = input_count + input_bytes;
input[input_count] = 0;
// Check there is success or error.
if (ok && strstr(input, ok))
{ result = S_OK; break; }
if (error && strstr(input, error))
{ result = S_FALSE; break; }
}
}
if (allocated_buffer) free(allocated_buffer);
return result;
}
HRESULT CDevice::Done()
{
HRESULT result = S_OK;
Lock();
if (m_HostType == ETHERNET)
{
ULONG command[2];
MAKE_COMMAND_HEADER(command, COMMAND_CLOSECOCKET, 0);
Binary(command, sizeof(command), NULL, 0, NULL, 0, command, CALCULATE_COMMAND_TIMEOUT(0));
ws_socket_done(m_socketBinary);
ws_socket_done(m_socketTelnet);
ws_done();
}
if (m_HostType == RS232)
{
::CloseHandle(m_hFile);
m_hFile = NULL;
}
m_HostType = 0;
Unlock();
return result;
}
HRESULT CDevice::Init(ULONG type, ULONG address)
{
HRESULT result = E_FAIL;
Done();
if (type == ETHERNET)
{
Lock();
#ifdef NOHARDWARE
return S_OK;
#endif
result = ws_init();
m_HostType = type;
m_HostAddress = address;
if (SUCCEEDED(result))
result = ws_socket_init(&m_socketTelnet, m_HostPort, m_HostAddress, 5000);
if (FAILED(result))
result = E_NOIPADDRESS;
if (SUCCEEDED(result))
result = Telnet(NULL, "login: ", NULL, NULL, 10000, 2000);
if (SUCCEEDED(result))
result = Telnet("root\r\n", "Password: ", NULL, NULL, 100, 2000);
if (SUCCEEDED(result))
result = Telnet("root\r\n", "]# ", "login: ", NULL, 100, 2000);
if (result == S_FALSE)
result = E_ACCESSDENIED;
char input_buffer[1024];
if (SUCCEEDED(result))
result = Telnet(m_ServerCommand, "]# ", NULL, input_buffer, sizeof(input_buffer), 2000);
if (SUCCEEDED(result) && strstr(input_buffer, "-sh: "))
result = E_TELNETEXECUTE;
if (SUCCEEDED(result) && strstr(input_buffer, "Error : "))
result = E_SERVERFAIL;
if (SUCCEEDED(result) && strstr(input_buffer, "\r\n"))
result = (sscanf_s(strstr(input_buffer, "\r\n"), "\r\n%d", &m_DataPort) != 1) ? E_INVALIDARG : result;
if (SUCCEEDED(result))
result = ws_socket_init(&m_socketBinary, m_DataPort, m_HostAddress, 2000);
Unlock();
}
// If address is 0, look for first COM port available.
#ifdef NOHARDWARE
return S_OK;
#endif
if (address == 0)
{
for (ULONG i=1; i<128; i++)
{
result = Init(RS232, i);
if (SUCCEEDED(result)) break;
}
}
else
{
Lock();
m_HostType = type;
m_HostAddress = address;
m_HostName.Format(_T("\\\\.\\COM%d"), address);
m_hFile = ::CreateFile(m_HostName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if ((m_hFile == NULL) || (m_hFile == INVALID_HANDLE_VALUE)) return E_FAIL;
DCB dcb;
dcb.DCBlength = sizeof(dcb);
::GetCommState(m_hFile, &dcb);
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = 0;
COMMTIMEOUTS timeouts = {MAXDWORD, 0, 0, 0, 1};
char bufferrx[1000] = {0};
result = ::SetCommTimeouts(m_hFile, &timeouts) && ::SetupComm(m_hFile, 4096, 4096) && ::SetCommState(m_hFile, &dcb) && ::PurgeComm(m_hFile, PURGE_RXCLEAR | PURGE_TXCLEAR) ? S_OK : E_FAIL;
if (SUCCEEDED(result))
result = Telnet("\x03root\r\n", "Password: ", NULL, bufferrx, sizeof(bufferrx), 2000);
result = Telnet("root\r\n", "]# ", "login: ", bufferrx, sizeof(bufferrx), 2000);
result = strstr(bufferrx, "]# ") ? S_OK : result;
if (SUCCEEDED(result))
TRACE(_T("Connected to RS-232 COM%d.\n"), address);
Unlock();
}
}
if (FAILED(result))
Done();
return result;
}
HRESULT CDevice::Telnet(const char* command, const char* ok, const char* error, char* output, ULONG length, ULONG timeout)
{
HRESULT result = E_FAIL;
if (m_HostType == ETHERNET) result = TelnetEthernet(command, ok, error, output, length, timeout);
return result;
}
HRESULT CDevice::TelnetEthernet(const char* command, const char* ok, const char* error, char* output, ULONG length, ULONG timeout)
{
return ws_telnet_command(m_socketTelnet, command, ok, error, output, length, timeout);
}
void CDevice::Proc()
{
#define ETHERNET_ADDRESS_ETH0 IPADDRESS_MAKE(192,168,50,250)
#define ETHERNET_ADDRESS_ETH1 IPADDRESS_MAKE(192,168,60,250)
HRESULT result = S_OK;
HRESULT result1 = S_OK;
HRESULT result2 = S_OK;
result1 = Init(CDevice::ETHERNET, ETHERNET_ADDRESS_ETH0);
Done();
if (SUCCEEDED(result1)) Sleep(2000);/////!!!!!!!!!!!!!!!!!!!!!
result2 = Init(CDevice::ETHERNET, ETHERNET_ADDRESS_ETH1);
Done();
/*
Если не выждать паузу в 1-2 секунды,
то второе подключение не проходит
*/
}
Re[2]: Telnet client issue
Вопрос снят.
Проблема оказалось в слишком умном свиче
Проблема оказалось в слишком умном свиче