Hawk
Hawk

Reputation: 327

recv() on socket by dynamically allocating space

I'm trying to get the source code of my website using c, I'm able to connect and everything but when I implement the recv() code, it only receives the last few bytes of the source code. I'd like to dynamically allocate space for the buffer to receive more using the C functions malloc and realloc.

This is the code I have so far:

char *buffer = NULL;
unsigned int i = 0;
unsigned long LEN = 200;
unsigned long cur_size = 0;

buffer = (char*)malloc(sizeof(char)*LEN);
do
{
    if( status >= LEN )
    {
        cur_size += status;
        buffer = (char*)realloc(buffer, cur_size);
    }
    status = recv(cSocket, buffer, LEN, 0);
    if( status == 0 )
    {
        printf("Bye\n");
    }
    else if( status > 0 )
    {
        printf("%d\n", status);
    }
    else
    {
        printf("socket error=%d\n", WSAGetLastError());
        break;
    }
}while( status > 0 );
printf("%s\n", buffer);

It still doesn't print the whole source code. How should I go about this?

Pseudocode:

buffer = 'len chars';
loop:
if( status >= buffer ) buffer = 'resize to status chars';
status = recv(sock, buffer, len, 0);
end loop

Upvotes: 0

Views: 5157

Answers (2)

alk
alk

Reputation: 70971

As you resize the buffer in advance this needs to be reflected by its size. Which currently is not the case.

To fix this you could, for example, initialise cur_size with LEN by changing

unsigned long cur_size = 0;

to

unsigned long cur_size = LEN;

Assuming the fix above, you want to append to the buffer and not overwrite it with every call to recv().

To do so change this line

status = recv(cSocket, buffer, LEN, 0);

to be

status = recv(cSocket, buffer + cur_size - LEN, LEN, 0);

A more straight forward approach would be to not track the size of the buffer, but the number of bytes received and just always increase the buffer by a constant size.

Also the two calls to allocate memory can be replaced by one:

char *buffer = NULL;
unsigned long LEN = 200;
unsigned long bytes_received = 0;
unsigned long cur_size = 0;
int status = 0;

do
{
    if (bytes_received >= cur_size)
    {
        char * tmp;
        cur_size += LEN;
        tmp = realloc(buffer, cur_size);
        if (NULL == tmp)
        {
          fprintf(stderr, "realloc error=%d\n", WSAGetLastError());
          break;
        }

        buffer = tmp;
    }

    status = recv(cSocket, buffer + bytes_received, LEN, 0);
    if (status == 0)
    {
        printf("Bye\n");
    }
    else if (status > 0)
    {
      bytes_received += status;
      printf("%d\n", status);           
    }
    else /* < 0 */
    {
        fprintf(stderr, "socket error=%d\n", WSAGetLastError());
    }
} while (status > 0);

printf("%s\n", buffer);

Upvotes: 2

Hawk
Hawk

Reputation: 327

Well, after a bit of research, I came across this website and finally found what I was looking for.

Binary tides

Although it uses linux's fcntl, the windows equivalent is ioctlsocket which is used to set the socket's non-blocking mode.

To see the exact function, visit the website. I modified the version and set my socket to blocking mode.

int total_recv(SOCKET s)
{
    int size_recv = 0, total_size = 0, block = 00;
    char chunk[BUFLEN];

    ioctlsocket(s, FIONBIO, (unsigned long*)&block); // set mode to block
    // not necessary but clarification of function, mode is block by
    // default

    while( 1 )
    {
        memset(chunk, 0, BUFLEN);
        if( ( size_recv = recv(s, chunk, BUFLEN, 0) ) == SOCKET_ERROR )
        {
            printf("Error receiving\n");
        }
        else if( size_recv == 0 )
        {
            break;
        }
        else
        {
            total_size += size_recv;

            // i used file since console wouldn't show full source code
            FILE *fp = NULL;
            fp = fopen("source.txt", "a");
            fprintf(fp, chunk);
            fclose(fp);
        }
    }

    return total_size;
}

Upvotes: 0

Related Questions