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;
}