Skip to content
Advertisement

Socket binding through JNI

I try to open a socket connection on a Linux machine through JNI. If I combine Java_Socket_socket and Java_Socket_bind in same C function, the JNI call works perfectly, but it doesn’t work when I run methods sequentially.

This is my code

#include <jni.h>        // JNI header provided by JDK
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
#include "Socket.h"   // Generated

JNIEXPORT jint JNICALL Java_Socket_socket(JNIEnv *env, jobject thisObj) {
    int sockfd;

    if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        printf("socket creation failed...n");
        return (jint)-1;
    } else {
        printf("Socket successfully created..n");
        printf("Socket descriptor: %dn", sockfd);
        return (jint) sockfd;
    }
}

JNIEXPORT jint JNICALL Java_Socket_bind(JNIEnv *env, jobject thisObj, jint sockfd, jint port) {
    struct sockaddr_in servaddr;
    bzero(&servaddr, sizeof(servaddr));

    int c_sockfd = (int) sockfd;
    short int c_port = (int) port;

    printf("socket binding sockfd - %d, port - %dn", c_sockfd, c_port);

    // assign IP, PORT
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(c_port);
    printf("htons - %dn", htons(c_port));


    int one = 1;
    int res = setsockopt(c_sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    res = setsockopt(c_sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    if (res < 0) {
        perror("setsockopt");
    }

    printf("sizeof - %dn", sizeof(servaddr));

    if (fcntl(c_sockfd, F_GETFD) != -1 || errno != EBADF) {
        printf("fd is validn");
    } else {
        printf("fd is invalidn");
    }

    // Binding newly created socket to given IP and verification
    if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed...n");
        printf("Error code: %dn", errno);
        return (jint)-1;
    }
    else {
        printf("Socket successfully binded..n");
        return (jint)0;
    }
}

Java code

public class Socket {
    static {
        System.load(".../libsocket.so");
    }

    private native int socket();

    private native int bind(int sockFd, int port);

    public static void main(String[] args) {
        var socket = new Socket();
        int sockFd = socket.socket();
        System.out.println("sockFd " + sockFd);
        int bind = socket.bind(sockFd, 9900);
        System.out.println("Bind " + bind);
    }
}

Output:

Socket descriptor: 4
socket binding sockfd - 4, port - 9900
htons - 44070
sizeof - 16
fd is valid
socket bind failed...
Error code: 22

If I create C program from this code, and as regular C program, gcc ... && a.out -> then no error occurs. What can be reason?

Can it be because file descriptor is closed?

Answer

The issue is that you’re treating AF_UNIX socket as AF_INET one. You can’t use sockaddr_in for AF_UNIX socket and also you can’t bind it to an IP address.

I think that you’ve made a typo in your socket definition code. Instead of

if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {

it should be

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
Advertisement