Потокобезопасность функций WinAPI

Пишу функцию, реализующую функционал утилиты ping. Функция вызывается внутри цикла для каждого значения IP-адреса, который она проверяет, каждый вызов происходит в отдельном потоке. Пишу на Qt с использованием классов: QTreadPool, QMutex и QMutexLocker. Являются ли функции gethostbyname, getprotobyname, memcpy, sendto, socket, setsockopt, recvfrom и WSAStartup потокобезопасными? Первый раз работаю с многопоточностью. При запуске в разных потоках получаю неопределённое поведение. При запуске в одном потоке всё работает верно.

#include "ips_socket.h"
#include "include/log.h"
#include "classes/binary_defines.h"
#include "include/error_defines.h"
#include "include/error_messages.h"
#include "include/network/unix_socket.h"
#include "include/network/win_socket.h"
#include <QMutexLocker>

#ifdef Q_OS_UNIX
    #include <fcntl.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <sys/socket.h>    
    #include <netinet/ip_icmp.h>
#endif

IPSSocket::IPSSocket(QTcpSocket* parent)
    : inherited(parent)
{   
}
void IPSSocket::createConnectionToHost(QTcpSocket* socket, QString const& host, std::uint16_t port) noexcept
{    
    QMutexLocker locker(&m_mutex);
    return socket->connectToHost(host, port);
}
#ifdef Q_OS_WIN
bool IPSSocket::preparingData(const char* host) noexcept
{
    QMutexLocker locker(&m_mutex);
    if ((m_sock.lpHostEntry = gethostbyname(host)) == nullptr)
        return false;

    m_sock.sockAddrLocal.sin_family = AF_INET;
    m_sock.sockAddrLocal.sin_addr = *(reinterpret_cast<LPIN_ADDR>(*m_sock.lpHostEntry->h_addr_list));

    if ((m_sock.lpProtocolEntry = getprotobyname("icmp")) == nullptr)
        m_sock.nProtocol = IPPROTO_ICMP;
    else
        m_sock.nProtocol = m_sock.lpProtocolEntry->p_proto;
    return true;
}
void IPSSocket::sendData(win_socket::icmp icmp) noexcept
{    
    QMutexLocker locker(&m_mutex);
    memcpy(&m_sock.IcmpSendPacket, &icmp, sizeof(win_socket::icmp));
    m_sock.iSentBytes = sendto(m_sock.hsocket, reinterpret_cast<LPSTR>(m_sock.IcmpSendPacket), m_sock.iPacketSize,
        NO_FLAGS, reinterpret_cast<LPSOCKADDR>(&m_sock.sockAddrLocal), sizeof(m_sock.sockAddrLocal));
}
bool IPSSocket::createSocket() noexcept
{
    QMutexLocker locker(&m_mutex);
    if ((m_sock.hsocket = socket(PF_INET, SOCK_RAW, m_sock.nProtocol)) == INVALID_SOCKET) {
        return false;
    }
    return true;
}
unsigned short IPSSocket::checksum(void *b, int len)
{
    QMutexLocker locker(&m_mutex);
    unsigned short *buf = static_cast<unsigned short *>(b);
    unsigned int sum=0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(reinterpret_cast<unsigned char*>(buf));
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = static_cast<unsigned short>(~sum);
    return result;
}
bool IPSSocket::setOptionsSocket() noexcept
{
    QMutexLocker locker(&m_mutex);
    DWORD timeOut = static_cast<unsigned long>(SOCKET_TIMEOUT);    
    return !setsockopt(m_sock.hsocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeOut), sizeof(timeOut));
}
win_socket::icmp IPSSocket::setICMPHeader() noexcept
{
    QMutexLocker locker(&m_mutex);
    win_socket::icmp pkg;
    pkg.icmp_type = ICMP_ECHO;
    pkg.icmp_cksum = 0;
    pkg.icmp_code = 0;
    pkg.icmp_seq  = 0;
    pkg.icmp_id = HINSTANCE(1);
    pkg.icmp_cksum = checksum(reinterpret_cast<unsigned short *>(&pkg), sizeof(pkg));
    m_sock.iPacketSize = sizeof(pkg);
    return  pkg;
}
void IPSSocket::reciveData() noexcept
{
    QMutexLocker locker(&m_mutex);
    m_sock.iHostAddrLength = sizeof(m_sock.sockAddrHost);
    m_sock.iReceivedBytes = recvfrom(m_sock.hsocket, reinterpret_cast<LPSTR>(m_sock.IcmpRecvPacket),
    sizeof(m_sock.IcmpRecvPacket), NO_FLAGS, reinterpret_cast<LPSOCKADDR>(&m_sock.sockAddrHost), &m_sock.iHostAddrLength);
}
bool IPSSocket::controlData() noexcept
{
    QMutexLocker locker(&m_mutex);
    m_pIpHeader = reinterpret_cast<struct win_socket::ip*>(m_sock.IcmpRecvPacket);
    m_sock.iIPHeadLength = (m_pIpHeader->ip_verlen >> 4) << 2;    

    if (m_sock.iReceivedBytes < m_sock.iIPHeadLength + ICMP_HEADERSIZE)
       return false;       

    return true;
}
bool IPSSocket::pingICMPWin(const char* host)
{    
    QMutexLocker locker(&m_mutex);

    WSADATA wsaData;
    WSAStartup(WINSOCK_VERSION, &wsaData);

    if(!preparingData(host))
        return false;

    if(!createSocket())
        return false;    

    if(!setOptionsSocket())
        return false;

    sendData(setICMPHeader());

    reciveData();
    closesocket(m_sock.hsocket);

    if(!controlData())
        return false;

    WSACleanup();
    return true;
}
#endif

Ответы (0 шт):