sctp_connectx() gives EINVAL on FreeBSD
Asked Answered
E

1

14
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/sctp.h>
#include <stdio.h>
#include <string.h>

int main(int argc,char **argv)
{

    struct sockaddr_in remoteAddr;

    int clientSock = socket(PF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);
    if(clientSock == -1) {
        perror("socket");
        return 1;
    }
    memset(&remoteAddr,0,sizeof remoteAddr);
    remoteAddr.sin_family = AF_INET;
    remoteAddr.sin_len = sizeof remoteAddr;
    remoteAddr.sin_port = htons(5555);
    remoteAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    sctp_assoc_t assoc_id = 0;
    if(sctp_connectx(clientSock,(struct sockaddr*)&remoteAddr,1, &assoc_id)!= 0) {
        perror("sctp_connectx");
        return 1;
    }
    printf("Connected! Assoc ID %d\n",(int)assoc_id);

    return 0;   
}

When run, this code fails:

$ clang  -Wall sctp_connect.c 
$ ./a.out 
sctp_connectx: Invalid argument
$ uname -rp
11.0-RELEASE-p9 amd64

But I cannot figure out what's wrong. The sctp_connectx() manpage says it will fail with EINVAL if an address with invalid family or no addresses was provided - but that seems not to be the case from the code.

The sctp_connectx() has several parts where it can fail with EINVAL, but truss shows it gets to the setsockopt() call, so it's the kernel that fails the call:

socket(PF_INET,SOCK_SEQPACKET,132)       = 3 (0x3)
mmap(0x0,2097152,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34374418432 (0x800e00000)
setsockopt(0x3,0x84,0x8007,0x800e16000,0x14)     ERR#22 'Invalid argument'
Elevate answered 17/5, 2017 at 15:4 Comment(10)
a good minimal reproducible example... the good output... try to solve this problem alone... why this question has no up vote ?Badgett
The man on linux said "EINVAL Invalid port or address.". Hope this help.Badgett
Conectx implies it's a 1:1 interface? I think you can't use SOCK_SEQPACKET type of socket here you need to use SOCK_STREAM?Enriqueenriqueta
@Badgett It does not help. The very same code works fine on Linux.Elevate
@Enriqueenriqueta Same problem if using SOCK_STREAM,Elevate
yeah, actually I don't have a freebsd setup mostly on linux and was trying to extrapolate things to help you, note I dont get an EINVAL on linux for your code. Moving ahead, the call to setsocketopt will map to sctp_do_connectx in sctp_usrreq.c, one of the reason this call to connect can fail (with EINVAL) is if SCTP_REUSE_PORT is not enabled for the socket.Enriqueenriqueta
It works perfectly fine for me. But I have slightly different version of FreeBSD :( michalo@darkstar:~/src % ./a.out Connected! Assoc ID 3 michalo@darkstar:~/src % uname -rp 10.3-RELEASE-p11 amd64Wraparound
try to find out is your address is valid? print address after convert it to string ba2str() it seem you are not use true argument freebsd.org/cgi/…Mousey
petanode.com/blog/posts/…Mousey
@Elevate I have faced the same issue, have you find the resolution for this problem ?Faulkner
C
1

I think answer is there in your query. If we follow the truss trace then as you said it fails on setsockopt().

So the error EINVAL is returned by setsockopt(). And as per FreeBSD setsockopt() manual:

[EINVAL]: Installing an accept_filter(9) on a non-listening socket was attempted.

is the description of the error. So I think you should do below things:

  1. Explore your socket options whether they are correct with respect to you listener socket.
  2. Check for the errors for functions htons() and inet_addr()

And my suggestion is that you should not use inet_addr(), for more details see man pages, as per that:

Use of this function is problematic because -1 is a valid address (255.255.255.255). Avoid its use in favor of inet_aton(), inet_pton(3), or getaddrinfo(3), which provide a cleaner way to indicate error return.

Contribute answered 12/9, 2017 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.