AK-33
AK-33

Reputation: 157

connect() function fails when passing sockaddr_in as argument

I have the following main function:

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv) {
    char *serv_IP;
    in_port_t serv_port;
    int sock;
    struct sockaddr_in serv_addr;
    
    serv_IP = argv[1];
    serv_port = atoi(argv[2]);
    
    if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        fprintf(stderr, "Failed to create TCP socket\r\n");
        exit(1);
    }
    
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    
    if (inet_pton(AF_INET, serv_IP, &serv_addr.sin_addr.s_addr) == 0) {
        fprintf(stderr, "Invalid IP address\r\n");
        exit(1);
    }
    
    serv_addr.sin_port = htons(serv_port);
    
    if (connect(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        fprintf(stderr, "Failed to connect to serv\r\n");
        exit(1);
    }
    else {
        printf("You're connected!\n);
    }
    close(sock)
    return 0;
}

Now, this code works just fine. However, what I want to do is to replace the call to connect() with a helper function call to something like this:

void function(int sock, struct sockaddr_in *serv_addr) {
    if (connect(sock, (struct sockaddr *) serv_addr, sizeof(serv_addr)) < 0) {
        printf("Server IP = %s\n", inet_ntoa(serv_addr->sin_addr));
        printf("Server port = %d\n", ntohs(serv_addr->sin_port));
        fprintf(stderr, "Failed to connect to server\r\n");
        exit(1);
    }
    else {
        // Do other stuff
    }
}

I remove the call to connect() from main(), and replace it with the function call:

function(sock, &serv_addr);

As soon as the function is called, the correct IP and port numbers are printed out, but I still fail to connect to my server.

The only difference is, in my main function(), I preface serv_addr in the connect call with the & — i.e., connect(sock, (struct sockaddr *), &serv_addr, sizeof(serv_addr) — to reference its address, and I don't do that in the helper function because the address of serv_addr is already being passed as an argument — i.e., connect(sock, (struct sockaddr *), serv_addr, sizeof(serv_addr). It makes no difference if I add the &, just in case you were wondering.

So, with the &serv_addr being passed to function() seemingly correctly, as verified by me being able to print out the correct IP and port numbers, why is it that I can connect in main(), but not when I pass the serv_addr struct as an argument to another function and call connect() from there?

Upvotes: 1

Views: 7943

Answers (2)

AK-33
AK-33

Reputation: 157

I never would have thought about the return of sizeof() as a potential problem with returning different sizes for actual values vs. pointers to values.

The exact line that fixed it was:

if (connect(sock, (struct sockaddr *) serv_addr, sizeof(struct sockaddr_in)) < 0)

I was right about not needing the '&' in front of serv_add. You also need the "struct" in sizeof() or else it returns sockaddr_in as an undeclared variable.

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 595981

sizeof(serv_addr) returns 16 when serv_addr is declared as sockaddr_in, but returns 4 (in 32bit) or 8 (in 64bit) when declared as sockaddr_in*. It is too small either way, AF_INET needs 16. Had you looked at errno when connect() failed, it would have told you that you were passing an invalid parameter value.

You need to use sizeof(sockaddr_in), either directly:

void function(int sock, struct sockaddr_in *serv_addr)
{
    if (connect(sock, (struct sockaddr *) serv_addr, sizeof(struct sockaddr_in)) < 0)

Or indirectly via sizeof(*serv_addr):

void function(int sock, struct sockaddr_in *serv_addr)
{
    if (connect(sock, (struct sockaddr *) serv_addr, sizeof(*serv_addr)) < 0)

Upvotes: 2

Related Questions