/* * Class: org_newsclub_net_unix_NativeUnixSocket * Method: connect * Signature: (Ljava/lang/String;Ljava/io/FileDescriptor;)V */ JNIEXPORT void JNICALL Java_org_newsclub_net_unix_NativeUnixSocket_connect (JNIEnv * env, jclass clazz, jstring file, jobject fd, jboolean abstract, jboolean dgram) { const char* socketFile = (*env)->GetStringUTFChars(env, file, NULL); if(socketFile == NULL) { return; // OOME } if(strlen(socketFile) >= 104) { (*env)->ReleaseStringUTFChars(env, file, socketFile); org_newsclub_net_unix_NativeUnixSocket_throwException(env, "Pathname too long for socket", file); return; } int sockType = SOCK_STREAM; if ( dgram == JNI_TRUE ) { sockType = SOCK_DGRAM; } int socketHandle = socket(AF_UNIX, sockType, 0); if(socketHandle == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); return; } struct sockaddr_un su; memset(&su, 0, sizeof(struct sockaddr_un)); su.sun_family = AF_UNIX; #ifdef junixsocket_have_sun_len su.sun_len = (sizeof(su) - sizeof(su.sun_path) + strlen(su.sun_path)); #endif size_t pathlen = 0; if ( abstract == JNI_TRUE ) { strcpy(su.sun_path+1, socketFile); pathlen = strlen(socketFile) + 1; } else { strcpy(su.sun_path, socketFile); pathlen = strlen(socketFile); } (*env)->ReleaseStringUTFChars(env, file, socketFile); socklen_t suLength = pathlen + sizeof(su.sun_family) #ifdef junixsocket_have_sun_len + sizeof(su.sun_len) #endif ; int ret = connect(socketHandle, (struct sockaddr *)&su, suLength); if(ret == -1) { close(socketHandle); org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); return; } org_newsclub_net_unix_NativeUnixSocket_initFD(env, fd, socketHandle); }
/* * Class: org_newsclub_net_unix_NativeUnixSocket * Method: bind * Signature: (Ljava/lang/String;Ljava/io/FileDescriptor;I)V */ JNIEXPORT void JNICALL Java_org_newsclub_net_unix_NativeUnixSocket_bind (JNIEnv * env, jclass clazz, jstring file, jobject fd, jint backlog) { const char* socketFile = (*env)->GetStringUTFChars(env, file, NULL); if(socketFile == NULL) { return; // OOME } if(strlen(socketFile) >= 104) { (*env)->ReleaseStringUTFChars(env, file, socketFile); org_newsclub_net_unix_NativeUnixSocket_throwException(env, "Pathname too long for socket", file); return; } int serverHandle = socket(AF_UNIX, SOCK_STREAM, 0); if(serverHandle == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env,strerror(errno), file); return; } struct sockaddr_un su; su.sun_family = AF_UNIX; #ifndef __linux__ su.sun_len = (sizeof(su) - sizeof(su.sun_path) + strlen(su.sun_path)); #endif strcpy(su.sun_path, socketFile); (*env)->ReleaseStringUTFChars(env, file, socketFile); socklen_t suLength = strlen(su.sun_path) + sizeof(su.sun_family) #ifndef __linux__ + sizeof(su.sun_len) #endif ; int bindRes = bind(serverHandle, (struct sockaddr *)&su, suLength); if(bindRes == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); return; } int chmodRes = chmod(su.sun_path, 0666); if(chmodRes == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); } int listenRes = listen(serverHandle, backlog); if(listenRes == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); return; } org_newsclub_net_unix_NativeUnixSocket_initFD(env, fd, serverHandle); }
/* * Class: org_newsclub_net_unix_NativeUnixSocket * Method: accept * Signature: (Ljava/lang/String;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;)V */ JNIEXPORT void JNICALL Java_org_newsclub_net_unix_NativeUnixSocket_accept (JNIEnv * env, jclass clazz, jstring file, jobject fdServer, jobject fd) { const char* socketFile = (*env)->GetStringUTFChars(env, file, NULL); if(socketFile == NULL) { return; // OOME } if(strlen(socketFile) >= 104) { (*env)->ReleaseStringUTFChars(env, file, socketFile); org_newsclub_net_unix_NativeUnixSocket_throwException(env, "Pathname too long for socket", file); return; } int serverHandle = org_newsclub_net_unix_NativeUnixSocket_getFD(env, fdServer); struct sockaddr_un su; su.sun_family = AF_UNIX; #ifndef __linux__ su.sun_len = (sizeof(su) - sizeof(su.sun_path) + strlen(su.sun_path)); #endif strcpy(su.sun_path, socketFile); (*env)->ReleaseStringUTFChars(env, file, socketFile); socklen_t suLength = strlen(su.sun_path) + sizeof(su.sun_family) #ifndef __linux__ + sizeof(su.sun_len) #endif ; int socketHandle = accept(serverHandle, (struct sockaddr *)&su, &suLength); if(socketHandle == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); return; } org_newsclub_net_unix_NativeUnixSocket_initFD(env, fd, socketHandle); return; }
/* * Class: org_newsclub_net_unix_NativeUnixSocket * Method: bind * Signature: (Ljava/lang/String;Ljava/io/FileDescriptor;I)V */ JNIEXPORT void JNICALL Java_org_newsclub_net_unix_NativeUnixSocket_bind (JNIEnv * env, jclass clazz, jstring file, jobject fd, jint backlog, jboolean abstract, jboolean dgram) { const char* socketFile = (*env)->GetStringUTFChars(env, file, NULL); if(socketFile == NULL) { return; // OOME } if(strlen(socketFile) >= 104) { (*env)->ReleaseStringUTFChars(env, file, socketFile); org_newsclub_net_unix_NativeUnixSocket_throwException(env, "Pathname too long for socket", file); return; } int sockType = SOCK_STREAM; if ( dgram == JNI_TRUE ) { sockType = SOCK_DGRAM; } int serverHandle = socket(AF_UNIX, sockType, 0); if(serverHandle == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env,strerror(errno), file); return; } // This block is only prophylactic, as SO_REUSEADDR seems not to work with AF_UNIX int optVal = 1; int ret = setsockopt(serverHandle, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal)); if(ret == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), NULL); } struct sockaddr_un su; memset(&su, 0, sizeof(struct sockaddr_un)); su.sun_family = AF_UNIX; #ifdef junixsocket_have_sun_len su.sun_len = (sizeof(su) - sizeof(su.sun_path) + strlen(su.sun_path)); #endif size_t pathlen = 0; if ( abstract == JNI_TRUE ) { strcpy(su.sun_path+1, socketFile); pathlen = strlen(socketFile) + 1; } else { strcpy(su.sun_path, socketFile); pathlen = strlen(socketFile); } (*env)->ReleaseStringUTFChars(env, file, socketFile); socklen_t suLength = pathlen + sizeof(su.sun_family) #ifdef junixsocket_have_sun_len + sizeof(su.sun_len) #endif ; int bindRes = bind(serverHandle, (struct sockaddr *)&su, suLength); if(bindRes == -1) { int myErr = errno; if(errno == EADDRINUSE) { // Let's check whether the address *really* is in use. // Maybe it's just a dead reference // if the given file exists, but is not a socket, ENOTSOCK is returned // if access is denied, EACCESS is returned ret = connect(serverHandle, (struct sockaddr *)&su, suLength); if(ret == -1 && errno == ECONNREFUSED) { // assume non-connected socket close(serverHandle); if(unlink(socketFile) == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env,strerror(errno), file); return; } serverHandle = socket(AF_UNIX, SOCK_STREAM, 0); if(serverHandle == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env,strerror(errno), file); return; } bindRes = bind(serverHandle, (struct sockaddr *)&su, suLength); if(bindRes == -1) { close(serverHandle); org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(myErr), file); return; } } else { close(serverHandle); org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(myErr), file); return; } } else { close(serverHandle); org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(myErr), file); return; } } if ( abstract == JNI_FALSE ) { int chmodRes = chmod(su.sun_path, 0666); if(chmodRes == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); } } int listenRes = listen(serverHandle, backlog); if(listenRes == -1) { org_newsclub_net_unix_NativeUnixSocket_throwException(env, strerror(errno), file); return; } org_newsclub_net_unix_NativeUnixSocket_initFD(env, fd, serverHandle); }