0
\$\begingroup\$

I'm trying to write a c++ winsock client/server pair. Everything I've read online has the client supply the IP to connect to via command line argument. Nothing says how to get THE (singular) IP address of the server. I know how to get a list of them, but cant find anything about finding the right one. THE IMPORTANT PART I need the IP address the client needs to connect to the server from a different computer on a different network.

Also, nothing seems too keen on explaining how to supply one to getaddrinfo ie. what data type do I use?

Any help/links to resources are welcome, Thanks, Peter

EDIT (in response to comments about clarity): I have a datagram/UDP server class. Its all set up to recv from a socket. I know which socket. The problem is that I dont know what the IP is to provide the client so it can connect to the server. (Once the client is connected I know how to obtain the IP of the host but not before then which is a real problem as it precludes the client from connecting at all.)

Problem 2: Once I have this IP address, how do I supply it to getaddrinfo? I dont want to use command line arguments. Do I have the user std::cin the IP to a char array? How long do I need that array to be and are there any special termination characters I need to add to the end?

Hope this is more clear.

And just for kicks here's my code. Its all in one file so everything I have is here:

#include <stdio.h>
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <cstring>

#pragma comment(lib, "ws2_32.lib")

#define PORT "4590"
#define MAXBUFLEN 100

void startup(){
    WSADATA wsaData;
    int iResult;

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0){
        fprintf(stderr, "WSAStartup failed\n");
        exit(1);
    }
}

void cleanup(){
    WSACleanup();
}

bool getIsHost(){
    int hosting;

    printf("Are you the host or the client? (1=host, 0=client)  ");
    std::cin >> hosting;

    if (hosting != 0){
        return true;
    }
    return false;
}

void *get_in_addr(struct sockaddr *sa){
    if (sa->sa_family == AF_INET){
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }
    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

void printNetworkAddress(){
    std::cout << "Getting Host Name" << std::endl;
    char ac[80];
    if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR){
        std::cerr << "Error " << WSAGetLastError() << " when getting local host name." << std::endl;
        exit(1);
    }
    std::cout << "Host name is " << ac << "." << std::endl;

    struct hostent *phe = gethostbyname(ac);
    if (phe == 0){
        std::cerr << "Bad host lookup." << std::endl;
        exit(1);
    }

    for (int i = 0; phe->h_addr_list[i] != 0; ++i){
        struct in_addr addr;
        memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
        std::cout << "Address " << i << ": " << inet_ntoa(addr) << std::endl;
    }
}

void serverFunction();
void clientFunction();

int main(){

    bool isHost;

    // Header
    printf("Client/Server Program\n");

    isHost = getIsHost();

    startup();

    if (isHost){
        serverFunction();
    }
    else{
        clientFunction();
    }

    cleanup();

    printf("\n");
    std::cin >> isHost;

    return 0;
}

void serverFunction(){
    printf("Setting up Server\n");

    int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv; // Error checking on getaddrinfo
    int numbytes;
    struct sockaddr_storage their_addr;
    char buf[MAXBUFLEN];
    socklen_t addr_len;
    char s[INET6_ADDRSTRLEN];

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

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

    for (p = servinfo; p != NULL; p = p->ai_next){
        if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
            perror("listener: socket");
            continue;
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
            closesocket(sockfd);
            perror("listener: bind");
        }

        break;
    }

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

    printNetworkAddress();

    freeaddrinfo(servinfo);

    printf("listener: waiting to recvfrom ... \n");

    addr_len = sizeof their_addr;
    if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN - 1, 0, (struct sockaddr *)&their_addr, &addr_len)) == -1){
        perror("recvfrom");
        cleanup();
        exit(1);
    }

    printf("listener: got packet from %s\n", inet_ntop(their_addr.ss_family,
        get_in_addr((struct sockaddr *)&their_addr),
        s, sizeof s));
    printf("listener: packet is %d bytes long\n", numbytes);
    buf[numbytes] = '\0';
    printf("listener: packet contains\"%s\"\n", buf);

    closesocket(sockfd);
}

void clientFunction(){
    printf("Setting up Client\n");

    int sockfd; 
    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    char connectaddr[16];
    memset(connectaddr, 0, sizeof connectaddr);
    printf("connectaddr len: %u\n", strlen(connectaddr));

    std::cout << "Enter the host IP Address: ";

    std::cin >> connectaddr;
    printf("connectaddr len: %u\n", strlen(connectaddr));
    //connectaddr[strlen(connectaddr)] = '\0';

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

    for (p = servinfo; p != NULL; p = p->ai_next){
        if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
            perror("talker: socket");
            continue;
        }
        break;
    }

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

    char message[256];

    std::cout << "Enter your message: ";
    std::cin >> message;

    if ((numbytes = sendto(sockfd, message, strlen(message), 0, p->ai_addr, p->ai_addrlen)) == -1) {
        perror("talker: sendto");
        exit(1);
    }

    freeaddrinfo(servinfo);

    printf("talker: sent %d bytes to %s\n", numbytes, connectaddr);
    closesocket(sockfd);
}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ I really have no idea what you're asking. You want code that magically guesses correctly which host your game server is running on? Or is your question about getaddrinfo implying you just want to do a hostname to IP address lookup? At some point you're going to have to put an IP or hostname into a config file, on the command line, or hardcode it into your game. \$\endgroup\$ Commented Jan 30, 2014 at 6:27
  • \$\begingroup\$ Ok, sorry for being unclear. I've done some more digging around google and I might be able to ask a better question. (I'll just edit the post to reflect this). \$\endgroup\$ Commented Jan 30, 2014 at 7:50
  • \$\begingroup\$ @Peteyslatts still not sure what you are asking. Just save the server ips in a config file. Otherwise how are you going to know ? \$\endgroup\$
    – concept3d
    Commented Jan 30, 2014 at 21:08

3 Answers 3

1
\$\begingroup\$

If you have multiple addresses configured on several interfaces and want to find out which address that you appear as to a foreign host, the simple way is to make a connection to the host or a known host on the external network.

Have that host echo back the address of the peer (you), much like the "what is my IP" websites do. This is also similar to the workings of STUN servers or other service catalogs, master servers and rendezvous services.

You cannot reliably determine much about what an address configured to one of interfaces is good for even if you are able to enumerate them all. The sure-fire way is to attempt to make a connection somewhere and empirically see what happens. Things like NAT/PAT and VPN gateways imply that it's possible that all the local addresses are on private networks.

\$\endgroup\$
0
\$\begingroup\$

If I understand yo correctly, there are three possible answers:

  1. Assuming there is a list of possible IP addreses:store this list of all possible server IP's on the client and write a loop that iterates and tries them one by one. Afterwards wait and check if you got a response. If not then try again. You can check without blocking with the flag MSG_DONTWAIT (if not you can use other non blocking methods).
  2. You can buy a domain name and use that instead of an IP address.

I would like to add that you probably should use an existing server implementation. Writing a robust game server is very challenging and time consuming. I personally think SmartFox may be a good place to start looking.

\$\endgroup\$
0
\$\begingroup\$

You want to look at 2 possible addresses:

Local IP Address: This is the address that your PC uses. This will typically be assigned by a router or switch, but can be from virtually any DHCP source. You can check your network adapter for this (No code provided as this is not typically what you would use).

Remote IP Address: Any computer that wants to connect to your host must use the IP address on the same common network, and you need something on that network to report the address back to you. This is the IP address as seen by that external source.

Now for your application, you're likely looking for the Remote IP Address. This is what other people will be connecting to since it's the address that exists on the internet.

The reason your PC cannot simply get the remote IP address is because it has no way to know how that information is being routed.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged .