kopia lustrzana https://github.com/Hamlib/Hamlib
290 wiersze
8.2 KiB
C
290 wiersze
8.2 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "asyncpipe.h"
|
|
|
|
#if defined(WIN32) && defined(HAVE_WINDOWS_H)
|
|
|
|
static volatile long pipe_serial_nunber;
|
|
|
|
int async_pipe_create(hamlib_async_pipe_t **pipe_out, unsigned long pipe_buffer_size, unsigned long pipe_connect_timeout_millis)
|
|
{
|
|
DWORD error_code;
|
|
CHAR pipe_name[MAX_PATH];
|
|
hamlib_async_pipe_t *pipe;
|
|
|
|
pipe = calloc(1, sizeof(hamlib_async_pipe_t));
|
|
if (pipe == NULL)
|
|
{
|
|
return -RIG_ENOMEM;
|
|
}
|
|
|
|
if (pipe_buffer_size == 0)
|
|
{
|
|
pipe_buffer_size = PIPE_BUFFER_SIZE_DEFAULT;
|
|
}
|
|
|
|
snprintf(pipe_name, sizeof(pipe_name),
|
|
"\\\\.\\Pipe\\Hamlib.%08lx.%08lx",
|
|
GetCurrentProcessId(),
|
|
InterlockedIncrement(&pipe_serial_nunber)
|
|
);
|
|
|
|
pipe->read = CreateNamedPipe(
|
|
pipe_name,
|
|
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
|
PIPE_TYPE_BYTE | PIPE_WAIT,
|
|
1, // Number of pipes
|
|
pipe_buffer_size, // Out buffer size
|
|
pipe_buffer_size, // In buffer size
|
|
pipe_connect_timeout_millis, // Timeout in ms
|
|
NULL);
|
|
|
|
if (!pipe->read)
|
|
{
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
|
|
pipe->write = CreateFile(
|
|
pipe_name,
|
|
GENERIC_WRITE,
|
|
0, // No sharing
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL // Template file
|
|
);
|
|
|
|
if (pipe->write == INVALID_HANDLE_VALUE)
|
|
{
|
|
error_code = GetLastError();
|
|
CloseHandle(pipe->read);
|
|
free(pipe);
|
|
SetLastError(error_code);
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
|
|
pipe->read_overlapped.hEvent = CreateEvent(
|
|
NULL, // default security attribute
|
|
TRUE, // manual-reset event
|
|
FALSE, // initial state = not signaled
|
|
NULL); // unnamed event object
|
|
|
|
if (pipe->read_overlapped.hEvent == NULL)
|
|
{
|
|
error_code = GetLastError();
|
|
CloseHandle(pipe->read);
|
|
CloseHandle(pipe->write);
|
|
free(pipe);
|
|
SetLastError(error_code);
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
|
|
pipe->write_overlapped.hEvent = CreateEvent(
|
|
NULL, // default security attribute
|
|
TRUE, // manual-reset event
|
|
FALSE, // initial state = not signaled
|
|
NULL); // unnamed event object
|
|
|
|
if (pipe->write_overlapped.hEvent == NULL)
|
|
{
|
|
error_code = GetLastError();
|
|
CloseHandle(pipe->read_overlapped.hEvent);
|
|
CloseHandle(pipe->read);
|
|
CloseHandle(pipe->write);
|
|
free(pipe);
|
|
SetLastError(error_code);
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
|
|
*pipe_out = pipe;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
void async_pipe_close(hamlib_async_pipe_t *pipe)
|
|
{
|
|
if (pipe->read != NULL)
|
|
{
|
|
CloseHandle(pipe->read);
|
|
pipe->read = NULL;
|
|
}
|
|
if (pipe->write != NULL)
|
|
{
|
|
CloseHandle(pipe->write);
|
|
pipe->write = NULL;
|
|
}
|
|
|
|
if (pipe->read_overlapped.hEvent != NULL)
|
|
{
|
|
CloseHandle(pipe->read_overlapped.hEvent);
|
|
pipe->read_overlapped.hEvent = NULL;
|
|
}
|
|
if (pipe->write_overlapped.hEvent != NULL)
|
|
{
|
|
CloseHandle(pipe->write_overlapped.hEvent);
|
|
pipe->write_overlapped.hEvent = NULL;
|
|
}
|
|
|
|
free(pipe);
|
|
}
|
|
|
|
ssize_t async_pipe_read(hamlib_async_pipe_t *pipe, void *buf, size_t count, int timeout)
|
|
{
|
|
HANDLE event_handles[1] = {
|
|
pipe->read_overlapped.hEvent,
|
|
};
|
|
HANDLE read_handle = pipe->read;
|
|
LPOVERLAPPED overlapped = &pipe->read_overlapped;
|
|
DWORD wait_result;
|
|
int result;
|
|
ssize_t bytes_read;
|
|
|
|
result = ReadFile(read_handle, buf, count, NULL, overlapped);
|
|
if (!result)
|
|
{
|
|
result = GetLastError();
|
|
switch (result)
|
|
{
|
|
case ERROR_SUCCESS:
|
|
// No error?
|
|
break;
|
|
case ERROR_IO_PENDING:
|
|
wait_result = WaitForMultipleObjects(1, event_handles, FALSE, timeout);
|
|
|
|
switch (wait_result)
|
|
{
|
|
case WAIT_OBJECT_0 + 0:
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
if (count == 0)
|
|
{
|
|
// Zero-length reads are used to wait for incoming data,
|
|
// so the I/O operation needs to be cancelled in case of a timeout
|
|
CancelIo(read_handle);
|
|
return -RIG_ETIMEOUT;
|
|
}
|
|
else
|
|
{
|
|
// Should not happen, as reads with count > 0 are used only when there is data available in the pipe
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
|
|
default:
|
|
result = GetLastError();
|
|
rig_debug(RIG_DEBUG_ERR, "%s: WaitForMultipleObjects() error: %d\n", __func__, result);
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
break;
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s: ReadFile() error: %d\n", __func__, result);
|
|
return -RIG_EIO;
|
|
}
|
|
}
|
|
|
|
result = GetOverlappedResult(read_handle, overlapped, (LPDWORD) &bytes_read, FALSE);
|
|
if (!result)
|
|
{
|
|
result = GetLastError();
|
|
switch (result)
|
|
{
|
|
case ERROR_SUCCESS:
|
|
// No error?
|
|
break;
|
|
case ERROR_IO_PENDING:
|
|
// Shouldn't happen?
|
|
return -RIG_ETIMEOUT;
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s: GetOverlappedResult() error: %d\n", __func__, result);
|
|
return -RIG_EIO;
|
|
}
|
|
}
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
int async_pipe_wait_for_data(hamlib_async_pipe_t *pipe, int timeout)
|
|
{
|
|
unsigned char data;
|
|
int result;
|
|
|
|
// Use a zero-length read to wait for data in pipe
|
|
result = async_pipe_read(pipe, &data, 0, timeout);
|
|
|
|
if (result > 0)
|
|
{
|
|
return RIG_OK;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
ssize_t async_pipe_write(hamlib_async_pipe_t *pipe, const unsigned char *buf, size_t count, int timeout)
|
|
{
|
|
HANDLE event_handles[1] = {
|
|
pipe->write_overlapped.hEvent,
|
|
};
|
|
HANDLE write_handle = pipe->write;
|
|
LPOVERLAPPED overlapped = &pipe->write_overlapped;
|
|
DWORD wait_result;
|
|
int result;
|
|
ssize_t bytes_written;
|
|
|
|
result = WriteFile(write_handle, buf, count, NULL, overlapped);
|
|
if (!result)
|
|
{
|
|
result = GetLastError();
|
|
switch (result)
|
|
{
|
|
case ERROR_SUCCESS:
|
|
// No error?
|
|
break;
|
|
case ERROR_IO_PENDING:
|
|
wait_result = WaitForMultipleObjects(1, event_handles, FALSE, timeout);
|
|
|
|
switch (wait_result)
|
|
{
|
|
case WAIT_OBJECT_0 + 0:
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
CancelIo(write_handle);
|
|
return -RIG_ETIMEOUT;
|
|
|
|
default:
|
|
result = GetLastError();
|
|
rig_debug(RIG_DEBUG_ERR, "%s: WaitForMultipleObjects() error: %d\n", __func__, result);
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
break;
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s: WriteFile() error: %d\n", __func__, result);
|
|
return -RIG_EIO;
|
|
}
|
|
}
|
|
|
|
result = GetOverlappedResult(write_handle, overlapped, (LPDWORD) &bytes_written, FALSE);
|
|
if (!result)
|
|
{
|
|
result = GetLastError();
|
|
switch (result)
|
|
{
|
|
case ERROR_SUCCESS:
|
|
// No error?
|
|
break;
|
|
case ERROR_IO_PENDING:
|
|
// Shouldn't happen?
|
|
return -RIG_ETIMEOUT;
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s: GetOverlappedResult() error: %d\n", __func__, result);
|
|
return -RIG_EIO;
|
|
}
|
|
}
|
|
|
|
return bytes_written;
|
|
}
|
|
|
|
#endif
|