0

I've got a complete Winsock client and server below. I'm not able to get the whole file though.

The client is not filling up its buffer with the data.

Stepping through debug it looks like the server process is sending back, but I only get three loops and the recv() is done.

I assume I'm missing something apparent, but not being fluent in Winsock or memcpy, can someone help me?

Single winsockserver.cpp code:

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <strsafe.h>
#include <process.h>
#include <mswsock.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")

WCHAR REGPATH[260];

BOOL SetPrivilege() 
{
    HANDLE hToken;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) != 0)
        {
        LUID luid;
        BOOL bLookupPrivilegeValue = LookupPrivilegeValueW(NULL, L"SeBackupPrivilege", &luid);
        if (bLookupPrivilegeValue == TRUE)
            {
            TOKEN_PRIVILEGES tp;
            tp.PrivilegeCount = 1;
            tp.Privileges[0].Luid = luid;
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            BOOL bAdjustTokenPrivileges = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD)NULL);
            return ((bAdjustTokenPrivileges == TRUE) && (GetLastError() == ERROR_SUCCESS));
            }
        }
    return TRUE;
}

SOCKET SetUpListener(CONST CHAR *pcAddress, INT nPort)
{
    DWORD dwWSA = 0;
    INT iBind = 0;
    ULONG nInterfaceAddr = 0;
    inet_pton(AF_INET, pcAddress, &nInterfaceAddr);
    if (nInterfaceAddr != INADDR_NONE) 
        {
        SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);
        if (sd != INVALID_SOCKET) 
            {
            sockaddr_in sinInterface;
            sinInterface.sin_family = AF_INET;
            sinInterface.sin_addr.s_addr = nInterfaceAddr;
            sinInterface.sin_port = nPort;            
            iBind = bind(sd, (sockaddr*) &sinInterface, sizeof(sockaddr_in));
            if (iBind != SOCKET_ERROR)
                {
                listen(sd, SOMAXCONN);
                return sd;
                }
            dwWSA = WSAGetLastError();
            }
        }
    return INVALID_SOCKET;
}

BOOL ReceiveDoWorkThenReturnDataToClient(SOCKET sd)
{    
    CHAR acReadBuffer[1024];
    INT nReadBytes;
    do 
        {
        nReadBytes = recv(sd, acReadBuffer, 1024, 0);
        if (nReadBytes > 0) 
            {
            //INT nSentBytes = 0;
            //while (nSentBytes < nReadBytes) 
                {
                WCHAR* sTempFileOut = new WCHAR[MAX_PATH]();
                StringCchCopyW(sTempFileOut, MAX_PATH, L"c:\\temp\\~test.txt");

                HKEY key;
                LRESULT dresult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REGPATH, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);  // If the function succeeds, the return value is ERROR_SUCCESS.
                if (dresult == ERROR_SUCCESS)
                    {
                    DWORD dwErrorBackupPriv = 0;
                    if (SetPrivilege() == TRUE)
                        {
                        LSTATUS dStatus = RegSaveKeyW(key, sTempFileOut, NULL);  // If the function succeeds, the return value is ERROR_SUCCESS.
                        if ((dStatus == ERROR_SUCCESS) || (dStatus == ERROR_ALREADY_EXISTS))
                            {
                            HANDLE hFile = CreateFileW(sTempFileOut, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
                            if (hFile != INVALID_HANDLE_VALUE)
                                {
                                ULARGE_INTEGER ul;
                                ul.LowPart = GetFileSize(hFile, &ul.HighPart);

                                if ((ul.LowPart == INVALID_FILE_SIZE) && (GetLastError() != 0)) return 7;

                                OVERLAPPED ov = {};
                                ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
                                if (!ov.hEvent) return 8;

                                unsigned __int64 uiPos = 0;
                                unsigned __int64 uiRemaining = ul.QuadPart;

                                while (uiRemaining > 0)
                                    {
                                    ul.QuadPart = uiPos;
                                    ov.Offset = ul.LowPart;
                                    ov.OffsetHigh = ul.HighPart;
                                    DWORD dwNumToSend = (uiRemaining >= 3) ? 3 : (DWORD)uiRemaining;
                                    if (!TransmitFile(sd, hFile, dwNumToSend, 0, &ov, NULL, 0))
                                        {
                                        if ((GetLastError() != ERROR_IO_PENDING) && (WSAGetLastError() != WSA_IO_PENDING))
                                            break;
                                        WaitForSingleObject(ov.hEvent, INFINITE);
                                        }

                                    uiPos += dwNumToSend;
                                    uiRemaining -= dwNumToSend;

                                    Sleep(100);
                                    }

                                CloseHandle(ov.hEvent);
                                CloseHandle(hFile);
                                }
                            }
                        }
                    }
                delete[] sTempFileOut;
                }
            }
        else if (nReadBytes == SOCKET_ERROR) 
            return FALSE;
        }
    while (nReadBytes != 0);
    return TRUE;
}

BOOL ShutdownConnection(SOCKET sd)
{
    if (shutdown(sd, SD_SEND) == SOCKET_ERROR) return FALSE;
    CHAR acReadBuffer[1024];
    while (1) 
        {
        INT nNewBytes = recv(sd, acReadBuffer, 1024, 0);
        if (nNewBytes == SOCKET_ERROR) return FALSE;
        else if (nNewBytes == 0) break;
        }
    return (closesocket(sd) != SOCKET_ERROR);
}

DWORD WINAPI ThreadHandler(void* sd_)
{
    INT nRetval = 0;
    SOCKET sd = (SOCKET) sd_;
    if (!ReceiveDoWorkThenReturnDataToClient(sd)) nRetval = 3;
    if (!ShutdownConnection(sd)) nRetval = 4;
    return nRetval;
}

unsigned WINAPI ListenAndAccept(void *)
{
    WSAData wsaData;
    INT nCode;    
    sockaddr_in sinRemote;
    INT nAddrSize = sizeof(sinRemote);
    DWORD nThreadID;

    if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != ERROR_SUCCESS) return nCode;
    SOCKET ListeningSocket = SetUpListener("localhost", htons(43210));
    if (ListeningSocket == INVALID_SOCKET)
        return 3;
    while (1)
        {
        SOCKET sd = accept(ListeningSocket, (sockaddr*)&sinRemote, &nAddrSize);
        if (sd != INVALID_SOCKET)
            CreateThread(0, 0, &ThreadHandler, (void*)sd, 0, &nThreadID);
        else
            break;
        }
    WSACleanup();
    return 0;
}

int main()
{
    UINT threadID = 0;
    StringCchCopy(REGPATH, 260, L"Software\\Microsoft\\Direct3D");
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ListenAndAccept, NULL, 0, &threadID);
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);

    while (1)
        ;
}

Single Winsockclient.cpp file:

#include <winsock2.h>
#include <windows.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <strsafe.h>
#include <windns.h>
#include <process.h>
#include <windns.h>

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "dnsapi.lib")

DWORD SendWinsockCommandToRemoteServer(CONST DWORD dwCharsAllocatedReturnString, WCHAR **sStringReturned)
{
    SOCKET ConnectSocket = INVALID_SOCKET;
    INT recvbuflen = 65536;
    DWORD dwIPv4 = 0;
    DWORD dwErr = 0;

    SecureZeroMemory(*sStringReturned, dwCharsAllocatedReturnString * sizeof(CHAR));
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket == INVALID_SOCKET) 
        return WSAGetLastError();

    sockaddr_in clientService{};
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = dwIPv4;
    clientService.sin_port = htons(43210);

    INT iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
    if ((iResult != 0) || (iResult == SOCKET_ERROR))
        {
        closesocket(ConnectSocket);
        return WSAGetLastError();
        }

    iResult = send(ConnectSocket, "test", 5, 0);
    if ((iResult == INVALID_SOCKET) || (iResult == SOCKET_ERROR))
        {
        closesocket(ConnectSocket);
        return 5;
        }

    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) 
        {
        closesocket(ConnectSocket);
        return 6;
        }

    DWORD dwLen = 0;    
    BYTE * cRecvbuf = (BYTE*) calloc(65536, sizeof(BYTE));
    BYTE * cRecvbuf2 = (BYTE*) calloc(65536, sizeof(BYTE));
    do 
        {
        iResult = recv(ConnectSocket, (CHAR *) cRecvbuf, recvbuflen, MSG_WAITALL);
        memcpy(cRecvbuf2, cRecvbuf, sizeof(cRecvbuf)*2);
        }
    while (iResult > 0);

    DWORD dwLenOfRecvbuf = strlen((CHAR *) cRecvbuf);
    if (dwLenOfRecvbuf > 0)
        dwLen = dwLenOfRecvbuf + 1;

    if (dwLen > 0)
        {
        WCHAR *sRecvbuf = new WCHAR[dwLen]();
        DWORD dwCharWrittenToBuffer = MultiByteToWideChar(CP_UTF8, 0, (CHAR*)cRecvbuf, (INT)dwLen, sRecvbuf, dwLen);
        if (dwCharWrittenToBuffer != 0)
            StringCchCopyW(*sStringReturned, dwLen, sRecvbuf);
        delete[] sRecvbuf;
        free(cRecvbuf);
        if (dwCharWrittenToBuffer == 0)
            return 7;
        }
    else
        {
        free(cRecvbuf);
        return 8;
        }

    closesocket(ConnectSocket);
    return 0;
}


void QueryWinsockServer(CONST DWORD dwDataAllocatedSize, WCHAR** sDataBack, DWORD* dwErrorFromSendWinsockCommandToRemoteServer)
{
    SecureZeroMemory(*sDataBack, dwDataAllocatedSize * sizeof (WCHAR));
    WCHAR *sRV = new WCHAR[dwDataAllocatedSize]();
    *dwErrorFromSendWinsockCommandToRemoteServer = SendWinsockCommandToRemoteServer(dwDataAllocatedSize, &sRV);
    if (*dwErrorFromSendWinsockCommandToRemoteServer == ERROR_SUCCESS)
        {
        DWORD dwLenToCopy = wcslen(sRV) + 1;
        StringCchCopyW(*sDataBack, dwLenToCopy, sRV);
        }
    delete[] sRV;
}




int main(int argc, char **argv) 
{
    DWORD dwDataAllocatedSize = 1024;
    DWORD dwErr = 0;
    WCHAR* sData = new WCHAR[dwDataAllocatedSize]();
    WSADATA wsaData{};

    INT iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

    QueryWinsockServer(dwDataAllocatedSize, &sData, &dwErr);

    wprintf(L"Press any key to end.");
    getchar();

    return 0;
}
JeffR
  • 765
  • 2
  • 8
  • 23
  • 2
    This might not be the only problem, but why are you calling `TransmitFile` repeatedly to send 3-byte chunks? Just pass `dwNumBytes` as zero and let it do its thing, see [documentation](https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile). – Paul Sanders Jul 07 '22 at 15:30
  • I"m trying to send a binary file from server to client. Good suggestion, I'll try that. The client receiving the BYTE string, `recv()` only accepts `CHAR *`, so that might be an issue why `recv()` is only being run 3 times? – JeffR Jul 07 '22 at 15:41
  • Not using Transmit...solution found in: https://stackoverflow.com/questions/25634483/send-binary-file-over-tcp-ip-connection, post by @RemyLebeau – JeffR Jul 07 '22 at 16:03
  • Oh, OK, but it should be possible to get `TransmitFile` to work - it is purpose designed for the job. Then again, if you want portable code... – Paul Sanders Jul 07 '22 at 16:13
  • It's just for Windows, so if `TransmitFile` would work better, then yeah, I just don't have the right code on the server or client side, and finding working example code for `TransmitFile` is a wee bit difficult! – JeffR Jul 07 '22 at 17:00
  • 2
    @JeffR Possible duplicate of [TransmitFile sending the same bytes again and again](https://stackoverflow.com/questions/50706315/). Oh, nevermind, I see you are the one who commented on my answer to that question, so you are now trying to adopt that code into your project and failing. I agree with PaulSanders, the best way to use `TransmitFile` is to let it transmit the entire file in one go, not break it up into 3-byte chunks (you may as well just use `send()` for that). You should send the file size, then transmit the file. Receive the file size, then read until the full size is received. – Remy Lebeau Jul 07 '22 at 17:06
  • Why memcpy and ignore the destination buffer? Why strlen on file data that might be binary? – Anders Jul 08 '22 at 00:38

0 Answers0