0

I'm currently doing an assignment in which we are defined to use send()/recv() with two parts:

first send an int that indicates the length of the string (4 bytes) and then send the string itself.

When I try to run the client/server on my PC, only the first recv() returns success, while the next one fails.

When I run the same code on my partner's PC, it works well.

The error I'm receiving for recv() is 10054.

I am totally clueless, and have no idea how to approach this.

The receiving code is:

TransferResult_t ReceiveString(char** OutputStrPtr, SOCKET sd){

    /* Recv the the request to the server on socket sd */
    int TotalStringSizeInBytes;
    TransferResult_t RecvRes;
    char* StrBuffer = NULL;

    if ((OutputStrPtr == NULL) || (*OutputStrPtr != NULL))
    {
        printf("The first input to ReceiveString() must be "
            "a pointer to a char pointer that is initialized to NULL. For example:\n"
            "\tchar* Buffer = NULL;\n"
            "\tReceiveString( &Buffer, ___ )\n");
        return TRNS_FAILED;
    }

    /* The request is received in two parts. First the Length of the string (stored in
    an int variable ), then the string itself. */

    RecvRes = ReceiveBuffer(
        (char *)(&TotalStringSizeInBytes),
        (int)(sizeof(TotalStringSizeInBytes)), // 4 bytes
        sd);

    if (RecvRes != TRNS_SUCCEEDED) return RecvRes;

    StrBuffer = (char*)malloc(TotalStringSizeInBytes * sizeof(char));

    if (StrBuffer == NULL)
        return TRNS_FAILED;

    RecvRes = ReceiveBuffer(
        (char *)(StrBuffer),
        (int)(TotalStringSizeInBytes),
        sd);

    if (RecvRes == TRNS_SUCCEEDED)
    {
        *OutputStrPtr = StrBuffer;
    }
    else
    {
        free(StrBuffer);
    }

    return RecvRes;
}

The ReceiveBuffer function is:

TransferResult_t ReceiveBuffer(char* OutputBuffer, int BytesToReceive, SOCKET sd){

    char* CurPlacePtr = OutputBuffer;
    int BytesJustTransferred;
    int RemainingBytesToReceive = BytesToReceive;

    while (RemainingBytesToReceive > 0)
    {
        /* send does not guarantee that the entire message is sent */
        BytesJustTransferred = recv(sd, CurPlacePtr, RemainingBytesToReceive, 0);
        if (BytesJustTransferred == SOCKET_ERROR)
        {
            printf("recv() failed, error %d\n", WSAGetLastError());
            return TRNS_FAILED;
        }
        else if (BytesJustTransferred == 0)
            return TRNS_DISCONNECTED; // recv() returns zero if connection was gracefully disconnected.

        RemainingBytesToReceive -= BytesJustTransferred;
        CurPlacePtr += BytesJustTransferred; // <ISP> pointer arithmetic
    }

    return TRNS_SUCCEEDED;
}

ADDED: the sending function:

TransferResult_t SendString( const char *Str, SOCKET sd ){
    /* Send the the request to the server on socket sd */
    int TotalStringSizeInBytes;
    TransferResult_t SendRes;

    /* The request is sent in two parts. First the Length of the string (stored in 
    an int variable ), then the string itself. */

    TotalStringSizeInBytes = (int)( strlen(Str) + 1 ); // terminating zero also sent    

    SendRes = SendBuffer( 
        (const char *)( &TotalStringSizeInBytes ),
        (int)( sizeof(TotalStringSizeInBytes) ), // sizeof(int) 
        sd );

    if ( SendRes != TRNS_SUCCEEDED ) return SendRes ;

    SendRes = SendBuffer( 
        (const char *)( Str ),
        (int)( TotalStringSizeInBytes ), 
        sd );

    return SendRes;
}

And:

TransferResult_t SendBuffer( const char* Buffer, int BytesToSend, SOCKET sd ){
    const char* CurPlacePtr = Buffer;
    int BytesTransferred;
    int RemainingBytesToSend = BytesToSend;

    while ( RemainingBytesToSend > 0 )  
    {
        /* send does not guarantee that the entire message is sent */
        BytesTransferred = send (sd, CurPlacePtr, RemainingBytesToSend, 0);
        if ( BytesTransferred == SOCKET_ERROR ) 
        {
            printf("send() failed, error %d\n", WSAGetLastError() );
            return TRNS_FAILED;
        }

        RemainingBytesToSend -= BytesTransferred;
        CurPlacePtr += BytesTransferred; // <ISP> pointer arithmetic
    }

    return TRNS_SUCCEEDED;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
AmitRe
  • 1
  • 2
  • 1
    [don't cast malloc in C](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar Jan 24 '18 at 22:40
  • 1
    [WSAECONNRESET: Connection reset by peer.](https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668.aspx) – jxh Jan 24 '18 at 22:42
  • 1
    That error code suggests that the problem is on the sending side, not the receiver. – Barmar Jan 24 '18 at 22:43
  • 1
    You said that the first byte is the size of the string. But you're reading `int`, not a single byte. Also, your code assumes that `sizeof(int)` is the same on the sender and receiver. – Barmar Jan 24 '18 at 22:44
  • Sorry, I was wrong. it simply sends the string in two parts, 4 bytes for its length and then the string itself. Also, the error code doesn't really tell my anything. – AmitRe Jan 24 '18 at 22:51
  • In addition, forgot to mention, I only run the client-server locally, as in the same pc. – AmitRe Jan 24 '18 at 22:53
  • Perhaps you should post the code from the "sender", where it is sending "the 4 bytes for its length andd then the string itself". – TonyB Jan 24 '18 at 23:13
  • "we are defined to use send/recv with one byte at a time, while the first byte indicated the size of the string (in bytes)" Either do that, or [edit] your post and remove this passage. – n. m. could be an AI Jan 24 '18 at 23:16
  • @AmitRe Yes it does, WSAECONNRESET means the other side closed the connection. – user253751 Jan 24 '18 at 23:25
  • Thanks for the help! I edited my post, due to your comments. the main clue I think is that this code works on other pc. – AmitRe Jan 24 '18 at 23:31
  • Your "SendBuffer" function does not send the "4 byte" length of the string, as you state in your description. If it's sent elsewhere, prior to calling "SendBuffer", then please post that code. Otherwise, correct your description. – TonyB Jan 24 '18 at 23:37
  • SendString recieves a string and calls SendBuffer. The first call is of an int variable, which is 4 bytes long, and the second call is for the string itself. – AmitRe Jan 24 '18 at 23:42
  • why are you casting your variables? – MFisherKDX Jan 24 '18 at 23:46
  • 1
    Perhaps you should run WireShark (or other network sniffer) and see what is being sent "over the wire"... Additionally, I googled "windows 10054 error" and found a couple of Windows Support postings talking about a hotfix for a problem related to a facility used by some anti-virus products... which could explain why your friend's PC doesn't have the problem... i.e. the two PC's use different anti-virus products and/or have different levels up updates applied. [EXAMPLE](https://support.microsoft.com/en-us/help/981344/an-application-may-receive-the-10054-error-when-the-application-receiv) – TonyB Jan 25 '18 at 01:01
  • ECONNRESET, when not intentionally induced, is frequently a symptom of the other side unexpectedly crashing. Either that or a firewall. – Ove Jan 25 '18 at 01:19
  • I don't really see anything in the code that would cause the error, so it has to be external. But, on a side note, consider using `stdint.h` so you can use fixed-sized types like `int32_t`, as `int` is not guaranteed to be 4 bytes on all compilers or platforms. Also, multi-byte integers should be sent in network byte order (big endian). Windows is little endian. `SendString()` should use `htonl()` to convert `TotalStringSizeInBytes` to network byte order before sending it, and `ReceiveString()` should use `ntohl()` to convert `TotalStringSizeInBytes` to host byte order after reading it. – Remy Lebeau Jan 25 '18 at 02:49
  • Also, since you are sending the string length, sending a null terminator is redundant. I suggest dropping that, and have `ReceiveString()` allocate `StrBuffer` as `TotalStringSizeInBytes + 1` for a null terminator. Also, the check for `*OutputStrPtr != NULL` is unnecessary since `OutputStrPtr` is an output parameter. If `OutputStrPtr` is not NULL, initialize `*OutputStrPtr` to NULL before reading the string (or not, it is your choice what to output on error). If the caller passes in a pre-existing buffer on input, it has a logic error in its code, which would represent itself as a memory leak. – Remy Lebeau Jan 25 '18 at 02:56

0 Answers0