socket bind - IPv6: invalid argument

0

Witam.

Piszę prosty serwer TCP dla IPv6. kod wygląda tak:

int rc;
  struct sockaddr_in6 serverSa;

  int on = 1;
  int family;
  socklen_t serverSaSize;
  int c;
  char buf[INET6_ADDRSTRLEN];

  int s = socket(PF_INET6,SOCK_STREAM,0);
  if (s < 0)
  {
    fprintf(stderr, "IPv6 not active, falling back to IPv4...\n");
  }

  family = AF_INET6;

  printf("socket descriptor is: %d ", s);
  //setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on);
  rc = setsockopt(s,IPPROTO_IPV6,IPV6_RECVPKTINFO,&on,sizeof(on));
  int result = 8;
  /* initialize the server's sockaddr */
  memset(&serverSa,0,sizeof(serverSa));
  serverSa.sin6_family = AF_INET6;
 // serverSa.sin6_addr = "fe80::800:27ff:fe00:0";
  serverSa.sin6_port = htons(serverPort);

  tmp = (char*)(&serverSa.sin6_addr);
  result = inet_pton6(addr, tmp);
  printf ("\n result: %d \n", result); 
  serverSaSize = sizeof(struct sockaddr_in6);
  rc = bind(s,(struct sockaddr *)&serverSa,serverSaSize);
  if (rc < 0)
  {
    printf("\n TCP bind failed\n ");
    exit(1);
  } else {
    printf("\n TCP Binding OK.\n " );
  }

Kod niestety nie bind-uje mi sokcet'u. Wywala bład: "Unable to bind socket: invalid argument"
Po zakomentowaniu tej linijki:

result = inet_pton6(addr, tmp); 

Jest już ok. Wygląda na to, że ta funkcja psuje coś strukturę adresową. inet_pton6 wygląda tak:

int inet_pton6(const char *src, char * dst)
{
    static char xdigits[] = "0123456789abcdef";
    u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
    const char *curtok;
    int ch, saw_xdigit;
    u_int val;

    memset(tmp, '\0', NS_IN6ADDRSZ);
    tp = tmp;
    endp = tp + NS_IN6ADDRSZ;
    colonp = NULL;
    /* Leading :: requires some special handling. */
    if (*src == ':')
        if (*++src != ':')
            return (0);
    curtok = src;
    saw_xdigit = 0;
    val = 0;
    while ((ch = tolower (*src++)) != '\0') {
        char * pch;

        pch = strchr(xdigits, ch);
        if (pch != NULL) {
            val <<= 4;
            val |= (pch - xdigits);
            if (val > 0xffff)
                return (0);
            saw_xdigit = 1;
            continue;
        }
        if (ch == ':') {
            curtok = src;
            if (!saw_xdigit) {
                if (colonp)
                    return (0);
                colonp = tp;
                continue;
            } else if (*src == '\0') {
                return (0);
            }
            if (tp + NS_INT16SZ > endp)
                return (0);
            *tp++ = (u_char) (val >> 8) & 0xff;
            *tp++ = (u_char) val & 0xff;
            saw_xdigit = 0;
            val = 0;
            continue;
        }
        if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
            inet_pton4(curtok, (char*)tp) > 0) {
            tp += NS_INADDRSZ;
            saw_xdigit = 0;
            break;  /* '\0' was seen by inet_pton4(). */
        }
        return (0);
    }
    if (saw_xdigit) {
        if (tp + NS_INT16SZ > endp)
            return (0);
        *tp++ = (u_char) (val >> 8) & 0xff;
        *tp++ = (u_char) val & 0xff;
    }
    if (colonp != NULL) {
        /*
         * Since some memmove()'s erroneously fail to handle
         * overlapping regions, we'll do the shift by hand.
         */
        const int n = tp - colonp;
        int i;

        if (tp == endp)
            return (0);
        for (i = 1; i <= n; i++) {
            endp[- i] = colonp[n - i];
            colonp[n - i] = 0;
        }
        tp = endp;
    }
    if (tp != endp)
        return (0);
    memcpy(dst, tmp, NS_IN6ADDRSZ);
    return (1);
}

Czy ktoś ma jakiś pomysł, dlaczego to może nie działać ?

0

Dodam, że próbuje zrobić bind na vboxnet0 o adresie jak w komentarzu.

0

Na szybko skrobnalem, porownaj ze swoim u mnie sie nic nie crashuje, ani nie wywala.

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

#define PORT 9880

void ate()
{
    if(errno != 0)
        printf("%d\n", errno);
}

int main()
{
    int sockfd;
    struct sockaddr_in6 serv;
    int tr = 1;

    atexit(ate);

    if((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
        exit(-1);

    if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &tr, sizeof(int)) < 0)
        exit(-1);

    memset(&serv, 0, sizeof(serv));
    serv.sin6_family = AF_INET6;
    serv.sin6_port = htons(PORT);
    if(inet_pton(AF_INET6, "0000:0000:0000:0000:0000:0000:0000:0000", &serv.sin6_port) <= 0)
        exit(-1);
    //serv.sin6_addr = in6addr_any;

    if(bind(sockfd, (struct sockaddr*)&serv, sizeof(serv)) < 0)
        exit(-1);

    if(listen(sockfd, 10) < 0)
        exit(-1);

    while(1);

    close(sockfd);

    return 0;
}
  1. Nie obslugujesz bledow (tzn. tylko drukujesz informacje diagnostyczne)

  2. Wszystko co zwiazane z Twoim "inet_pton6" to jakies potworki

  3. Jest jeszcze szansa, ze bindujesz zle lokalny adres: http://stackoverflow.com/ques[...]cal-address-to-an-ipv6-socket

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

#define PORT 9880

void ate()
{
    if(errno != 0)
        printf("%d\n", errno);
}

int main(int argc, char** argv)
{
    int sockfd, connfd;
    int n;
    const int on = 1;
    struct addrinfo hints, *res, *ressave;
    socklen_t addrlenp;
    char port[5] = "9880";
    char buffer[256];

    atexit(ate);

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

    if((n = getaddrinfo(NULL, port, &hints, &res)) != 0)
        exit(-1);

    ressave = res;

    do
    {
        if(res->ai_family != AF_INET6)
            continue;

        if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
            continue;

        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
            exit(-1);

        if(bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
            break;

        if(close(sockfd) < 0)
            exit(-1);
    }
    while((res = res->ai_next) != NULL);

    if(res == NULL)
        exit(-1);

    if(listen(sockfd, 10) < 0)
        exit(-1);

    addrlenp = res->ai_addrlen;

    freeaddrinfo(ressave);

    while(1)
    {
        if((connfd = accept(sockfd, NULL, NULL)) < 0)
            exit(-1);
    }

    close(sockfd);

    return 0;
}

Doszedlem do czegos takiego:

  1. Program pobiera wszystkie dostepne interfejsy sieciowe (jako liste wskaznikowa)
  2. Przelatuje je w poszukiwaniu interfejsow AF_INET6
  3. Binduje dla pierwszego poprawnego adresu, przerywa i dalej leci standard

Jesli dobrze Cie zrozumialem, musialbys lekko zmodyfikowac, zeby zamiast Od razu bindowac, etc, etc. To zapisywac gdzies te struktury, a nastepnie w formie user-friendly dawac mozliwosc wyboru.

0

Zupełnie nie rozumiem po co to wszystko. Wcześniejszą wersję Twojego programu zmodyfikowałem do takiej i działa mi w tym sensie, że chociaż inet_pton nie zwraca błędu, jednak bind dalej nie działa:


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

#define PORT 10000

void ate()
{
    if(errno != 0)
        printf("%d\n", errno);
}

int main() {

    unsigned int port=10000;
    int sockfd;
    int res=0, result = 8;
    struct sockaddr_in6 serv;
    int tr = 1;

    atexit(ate);

    if((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0){
        exit(-1);
    }

    if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &tr, sizeof(int)) < 0) {
        exit(-1);
    }

    memset(&serv, 0, sizeof(serv));
    serv.sin6_family = AF_INET6;
    serv.sin6_port = htons(port);
    //fe80::d2df:9aff:fe65:feea
    result = inet_pton(AF_INET6, "fe80:0000:0000:0000:d2df:9aff:fe65:feea", &serv.sin6_port);
    printf ("result: %d", result );

    //serv.sin6_addr = in6addr_any;
    res=bind(sockfd, (struct sockaddr*)&serv, sizeof(serv));
    printf("res: %d ", res);

    if(listen(sockfd, 10) < 0) {
        exit(-1);
    }

    getchar();
    close(sockfd);

    return 0;
}

Jak odpalisz ten program to bind wywali błąd: "unable to bind... ", chodzi o to, żeby znaleźć odpowiedź na pytanie dlaczego tak się dzieje, że bind zwraca kod -1.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0