GeneralZero
GeneralZero

Reputation: 320

Multi Client Server, Multi interface, Multi IP version Socket

I want to make a server that accepts both IPv4 and IPv6 on all interfaces.

It does not seems to work for any address including localhost, 127.0.0.1, ::1, 192.168.1.26. What am I missing?

According to getaddrinfo(3) since ai_family is set to the AI_PASSIVE flag. 'The returned socket address will contain the "wildcard address"'

Here is my code so far.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/times.h>
#include <errno.h>


#define MAXBUF  1024

const char* PORTNUM = "687";

int init_address(struct addrinfo* hints)
{
    hints->ai_flags=     AI_PASSIVE;
    hints->ai_family=    AF_UNSPEC;
    hints->ai_socktype=  SOCK_DGRAM;
    hints->ai_protocol=  IPPROTO_UDP;
    return 1;
}

socklen_t init_socket(struct addrinfo* res, int* sockfd)
{
    struct addrinfo* ressave;
    struct sockaddr_in* all_interface;
    socklen_t addrlength;

    ressave=res;
    all_interface = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));

    do {/* each of the returned IP address is tried*/
        (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if ((*sockfd)<0)
            continue; /* fail, try next one*/

        if (bind((*sockfd), (struct sockaddr*)all_interface, sizeof(all_interface)) == 0)
            break; /*success*/

        close(*sockfd);

    }while(res->ai_next != NULL  && (res = res->ai_next)!= NULL);

    if(&addrlength)
        addrlength = res->ai_addrlen;

    freeaddrinfo(ressave);
    free(all_interface);

    return addrlength;
}

int doprocessing(char* buffer, size_t buff_size)
{
    return 0;
}

int peak_data(char* buffer, size_t buff_size)
{
    return 0;
}

int main(int argc, char const *argv[])
{
    int sockfd, newsockfd;
    int bytes_read;
    char* port;
    char buffer[MAXBUF];
    pid_t pid;
    socklen_t addrlen, len;
    struct addrinfo* socket_info;
    struct addrinfo* res;
    struct addrinfo* backup_res;
    struct sockaddr* cliaddr;
    int  n;

    socket_info = (struct addrinfo*)malloc(sizeof(struct addrinfo));
    res = (struct addrinfo*)malloc(sizeof(struct addrinfo));

    memset(socket_info, 0, sizeof(struct addrinfo));
    init_address(socket_info);


    if((n = getaddrinfo(NULL, PORTNUM, socket_info, &res)) !=0)
    {
        printf("multi_server: error for %s: %s", PORTNUM, gai_strerror(n));
        exit(0);
    }

    if ((addrlen = init_socket(res, &sockfd)) < 0)
    {
        printf("multi_server: Socket or Bind error");
        exit(0);
    }

    free(socket_info);

    cliaddr=malloc(addrlen);

    len=addrlen;

    printf("\nUDP Server: waiting for connection...");
    while (1) {
        bytes_read = recvfrom(sockfd, buffer, MAXBUF-1, MSG_PEEK, cliaddr, &len);

        if (bytes_read > 0) {
            // a connection has been established
            buffer[MAXBUF] = '\0';
            printf("\nUDP Server: received %d bytes ", bytes_read);
            pid = fork();

            if (pid < 0) {
                perror("UDP Server: ERROR while forking new process.\n");
                exit(1);
            }
            // check if the process ID is zero
            if (pid == 0) {
                // we are now inside the new forked process
                if(peak_data(buffer, bytes_read))
                {
                    doprocessing(buffer, bytes_read);
                }
                printf("Now in %d\n", pid);
                close(sockfd);
                exit(0);
            }
        }
    }
}

Upvotes: 0

Views: 179

Answers (1)

KrisSodroski
KrisSodroski

Reputation: 2842

You're not missing anything. It is accepting connections to ::1 you said? Then it will accept ipv6 connections. And since IPv6 is backwards compatible, if you've created the correct ipv6 socket, it should be able to send and receive ipv4 packets as well.

Upvotes: 1

Related Questions