Информация об изменениях

Сообщение 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>Покажи код.



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
Вопрос снят.
Проблема оказалось в слишком умном свиче