Jacob Jones
Jacob Jones

Reputation: 501

C Sockets on Mac OS X

Im trying to use sockets with C. Now Im writing server side software. My new connection handler:

int handle_new_connection(SOCKET *server_socket_descriptor, unsigned int *max_known_socket_descriptor, fd_set *main_socket_set)
{
    const int yes = 1;

    struct sockaddr_in remote_address;
    SOCKET new_connection_socket_descriptor;
    int address_size;
    char buffer[1000] = {0};
    struct hostent *host_entry;

    address_size = sizeof(struct sockaddr_in);

    if (SOCKET_ERROR == (new_connection_socket_descriptor = accept((*server_socket_descriptor), (struct sockaddr *)&remote_address, (socklen_t *)&address_size)))
    {
        return SOCKET_ERROR;
    }

    if ( SOCKET_ERROR == setsockopt(new_connection_socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
    {
        return SOCKET_ERROR;
    }

    printf ("Server: new connection from \'%s\' accepted successfully.\n", inet_ntoa(remote_address.sin_addr));

    unsigned long remote_address_size = sizeof(remote_address.sin_addr);

    if (NULL == (host_entry = gethostbyaddr((void *)&(remote_address.sin_addr), (socklen_t)&(remote_address_size), AF_INET)))
    {
        closesocket (new_connection_socket_descriptor);
        printf ("Server: new connection from \'%s\' was immediately closed because of gethostbyaddr() failure.\n", host_entry -> h_addr);
        return SOCKET_ERROR;
    }

    printf("Been here!\n");


    return 1;
}

When new user connects (via telnet) if sentence if (NULL == (host_entry = gethostbyaddr((void *)&(remote_address.sin_addr), (socklen_t)&(remote_address_size), AF_INET))) brings error: Segmentation fault: 11. Also, this code works perfectly on Linux. My operating system is Mac OS X. How to solve this issue?

Upvotes: 0

Views: 4163

Answers (1)

Ken Thomases
Ken Thomases

Reputation: 90531

You are passing the address of remote_address_size as the len parameter of gethostbyaddr(). That parameter should not be an address, just a length value, directly.


Update:

Also, you may not be getting a struct sockaddr_in from accept(). For example, if the connection is an IPv6 connection, you would get a struct sockaddr_in6. The safest approach would be to use a struct sockaddr_storage.

Ideally, you should switch from gethostbyaddr() to getnameinfo(). The latter takes a struct sockaddr* argument, to which you can supply the pointer to your struct sockaddr_storage without having to care about what address family it actually contains. The man page has sample code.

If you want to keep using gethostbyaddr(), you will need to examine the sa_family field of the struct sockaddr_storage. If it's AF_INET, you should use &((struct sockaddr_in*)&remote_address)->sin_addr as the first argument. If it's AF_INET6, you should use &((struct sockaddr_in6*)&remote_address)->sin6_addr. The second argument would be the size of the same field.

If the family is something else, you'll need to either look up how to handle that or return failure for a case not understood by your code.

Upvotes: 2

Related Questions