7

I'm writing a small C client/server application, but I cannot make the connection work when using the external IP address. The code for both client and server is taken from here, in particular the clients do:

    char *default_server_name = "localhost";
    char *server_name = NULL;
    int nport = DEFAULT_DAMA_PORT;
    char port[15];

    // Parse the command line options
    if (parse_options(argc, argv, &server_name, &nport) < 0) {
        return -1;
    }

    if (server_name == NULL) {
        server_name = default_server_name;
    }

    snprintf(port, 15, "%d", nport);

    // Connect to the server
    int client_socket;
    struct addrinfo hints, *servinfo, *p;
    int rv;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    if ((rv = getaddrinfo(server_name, port, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        exit(1);
    }

    for (p=servinfo; p != NULL; p = p->ai_next) {
        if ((client_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
#ifdef DEBUG
            perror("socket");
#endif
            continue;
        }

        if (connect(client_socket, p->ai_addr, p->ai_addrlen) == -1) {
            close(client_socket);
#ifdef DEBUG
            perror("connect");
#endif
            continue;
        }

        // Connected succesfully!
        break;
    }

    if (p == NULL) {
        // The loop wasn't able to connect to the server
        fprintf(stderr, "Couldn't connect to the server\n.");
        exit(1);
    }

While the server:

    int nport;
    char port[15];
    if (parse_options(argc, argv, &nport) < 0) {
        return -1;
    }

    snprintf(port, 15, "%d", nport);

    int server_socket;
    struct addrinfo hints, *servinfo, *p;
    int rv;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        exit(1);
    }

    for (p=servinfo; p != NULL; p = p->ai_next) {
        if ((server_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
#ifdef DEBUG
            perror("socket");
#endif
            continue;
        }

        if (bind(server_socket, p->ai_addr, p->ai_addrlen) == -1) {
            close(server_socket);
#ifdef DEBUG
            perror("bind");
#endif
            continue;
        }

        // We binded successfully!
        break;
    }

    if (p == NULL) {
        fprintf(stderr, "failed to bind socket\n");
        exit(2);
    }

    int pl_one, pl_two;
    socklen_t pl_one_len, pl_two_len;
    struct sockaddr_in pl_one_addr, pl_two_addr;

    if (listen(server_socket, 2) < 0) {
        fatal_error("Error in syscall listen.", 2);
    }

    // Get the two clients connections.
    pl_one_len = sizeof(pl_one_addr);
    pl_one = accept(server_socket,
                    (struct sockaddr *)&pl_one_addr,
                    &pl_one_len);
    if (pl_one < 0) {
        fatal_error("Error in syscall accept.", 3);
    }

    pl_two_len = sizeof(pl_two_addr);
    pl_two = accept(server_socket,
                    (struct sockaddr *)&pl_two_addr,
                    &pl_two_len);
    if (pl_two < 0) {
        fatal_error("Error in syscall accept.", 3);
    }

If I specify the IP of my machine in the command line, and hence the server_name in the clients is set to a string like 151.51.xxx.xxx, then the sockets cannot connect to the server. Also using 127.0.0.1 shows the same behaviour, which makes me think that when the documentation states:

The host name that you're interested in goes in the nodename parameter. The address can be either a host name, like "www.example.com", or an IPv4 or IPv6 address (passed as a string).

it's just joking.

Am I doing something incorrectly? Could there be some problem with firewall etc. that is preventing the clients to connect using the IP addresses?

Note: I've already searched a lot for this problem and some people say to avoid using getaddrinfo at all and directly fill with INADDR_ANY, but the getaddrinfo documentation states that passing NULL as nodename should already fill the address with INADDR_ANY, so I don't see why should I use the old method when the new one does this automatically.

ggorlen
  • 26,337
  • 5
  • 34
  • 50
Bakuriu
  • 85,459
  • 18
  • 168
  • 202
  • For the server part to work as expected (to be able accept connections) you have to add calls to `listen()` and `accept()`. You might like to read on chapter 9.15 and chapter 9.1. – alk May 04 '13 at 10:22
  • @alk I obviously do have calls to `listen` and `accept`(otherwise how come the server works if the client use `localhost` as `server_name`?). I'll add them to the question anyway. – Bakuriu May 04 '13 at 10:34
  • 2
    Is the server behind a router? Are the required ports opened or forwarded? – typ1232 May 04 '13 at 10:45
  • Some older ’share the internet’-boxes cannot do what you seem to be trying to do. That is, if you have setup port-forwarding, it will only work if you try to connect from a machine that is outside of your local network. – Mats May 04 '13 at 10:52
  • @typ1232 I have the router, and I think it is probably blocking connections to most ports... Still I don't get why passing `127.0.0.1` is different than passing `localhost`. Anyway it seems like the problem is not the code but the router configuration. @Sudhee No, if I use `localhost` it works, if I use *anything* else it doesn't work. – Bakuriu May 04 '13 at 11:09
  • To what ip-address does `localhost` resolve? – alk May 04 '13 at 11:13
  • Sry, but you did not mention it worked for `localhost` in you OP. – alk May 04 '13 at 11:14
  • @Bakuriu 127.0.0.1/"localhost" is the local loopback, it is a redirection of the OS! this will not go over the router, whereas an external ip will. You need to open the ports in your router configuration – typ1232 May 04 '13 at 11:14
  • @Bakuriu: tyring to localize the issue, so you are saying if you use "localhost" it works fine, and if you use "127.0.0.1" it fails? If so, it wont be router config (may be that too later, but this is different). Are you sure your parse_options is not messing up the IP Address? – Sudhee May 04 '13 at 11:19

1 Answers1

1

As written in comments you are trying to connect to a server that is located in a network behind a router.

127.0.0.1 or localhost are redirections of the operating system and will not go over the router. That's why it worked for you.

If you specify an external ip address, the connection is made via the router and the ports that you use need to be forwarded in the router configuration. Any normal home internet end user router blocks incoming connections from any port by default.

typ1232
  • 5,304
  • 6
  • 32
  • 49