JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative()

in src/main/c/Posix/SerialPort_Posix.c [497:586]


JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(JNIEnv *env, jobject obj)
{
	// Retrieve the serial port parameter fields
	jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
	if (checkJniError(env, __LINE__ - 1)) return 0;
	unsigned char disableExclusiveLock = (*env)->GetBooleanField(env, obj, disableExclusiveLockField);
	if (checkJniError(env, __LINE__ - 1)) return 0;
	unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
	if (checkJniError(env, __LINE__ - 1)) return 0;
	unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
	if (checkJniError(env, __LINE__ - 1)) return 0;
	unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
	if (checkJniError(env, __LINE__ - 1)) return 0;
	unsigned char isRtsEnabled = (*env)->GetBooleanField(env, obj, isRtsEnabledField);
	if (checkJniError(env, __LINE__ - 1)) return 0;
	const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
	if (checkJniError(env, __LINE__ - 1)) return 0;

	// Ensure that the serial port still exists and is not already open
	pthread_mutex_lock(&criticalSection);
	serialPort *port = fetchPort(&serialPorts, portName);
	if (!port)
	{
		// Create port representation and add to serial port listing
		port = pushBack(&serialPorts, portName, "User-Specified Port", "User-Specified Port", "0-0", "Unknown", "Unknown", "Unknown", -1, -1, 0);
	}
	pthread_mutex_unlock(&criticalSection);
	if (!port || (port->handle > 0))
	{
		(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
		checkJniError(env, __LINE__ - 1);
		lastErrorLineNumber = __LINE__ - 3;
		lastErrorNumber = (!port ? 1 : 2);
		return 0;
	}

	// Fix user permissions so that they can open the port, if allowed
	if (requestElevatedPermissions)
		verifyAndSetUserPortGroup(portName);

	// Try to open the serial port with read/write access
	port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
	int portHandle = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
	if (portHandle > 0)
	{
		// Set the newly opened port handle in the serial port structure
		pthread_mutex_lock(&criticalSection);
		port->handle = portHandle;
		pthread_mutex_unlock(&criticalSection);

		// Quickly set the desired RTS/DTR line status immediately upon opening
		Java_com_fazecast_jSerialComm_SerialPort_setDTRandRTS(env, obj, (jlong)(intptr_t)port, isDtrEnabled, isRtsEnabled);

		// Ensure that multiple root users cannot access the device simultaneously
		if (!disableExclusiveLock && flock(port->handle, LOCK_EX | LOCK_NB))
		{
			port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
			port->errorNumber = lastErrorNumber = errno;
			while (close(port->handle) && (errno == EINTR))
				errno = 0;
			pthread_mutex_lock(&criticalSection);
			port->handle = -1;
			pthread_mutex_unlock(&criticalSection);
		}
		else if (!Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
		{
			// Close the port if there was a problem setting the parameters
			fcntl(port->handle, F_SETFL, O_NONBLOCK);
			while (close(port->handle) && (errno == EINTR))
				errno = 0;
			pthread_mutex_lock(&criticalSection);
			port->handle = -1;
			pthread_mutex_unlock(&criticalSection);
		}
		else if (autoFlushIOBuffers)
		{
			// Sleep to workaround kernel bug about flushing immediately after opening
			const struct timespec sleep_time = { 0, 10000000 };
			nanosleep(&sleep_time, NULL);
			Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(env, obj, (jlong)(intptr_t)port);
		}
	}
	else
		port->errorNumber = lastErrorNumber = errno;

	// Return a pointer to the serial port data structure
	(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
	checkJniError(env, __LINE__ - 1);
	return (port->handle > 0) ? (jlong)(intptr_t)port : 0;
}