Move the socket code to a common file
A large part of the irda and bluetooth code is the Windows and BSD socket code. Moving this code to a common file reduces code duplication.
This commit is contained in:
parent
283eaa1ca6
commit
823303980e
@ -426,6 +426,10 @@
|
|||||||
RelativePath="..\src\shearwater_predator_parser.c"
|
RelativePath="..\src\shearwater_predator_parser.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\socket.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\suunto_common.c"
|
RelativePath="..\src\suunto_common.c"
|
||||||
>
|
>
|
||||||
@ -768,6 +772,10 @@
|
|||||||
RelativePath="..\src\shearwater_predator.h"
|
RelativePath="..\src\shearwater_predator.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\src\socket.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\src\suunto_common.h"
|
RelativePath="..\src\suunto_common.h"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -78,6 +78,7 @@ else
|
|||||||
libdivecomputer_la_SOURCES += serial.h serial_posix.c
|
libdivecomputer_la_SOURCES += serial.h serial_posix.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
libdivecomputer_la_SOURCES += socket.h socket.c
|
||||||
libdivecomputer_la_SOURCES += irda.h irda.c
|
libdivecomputer_la_SOURCES += irda.h irda.c
|
||||||
libdivecomputer_la_SOURCES += usbhid.h usbhid.c
|
libdivecomputer_la_SOURCES += usbhid.h usbhid.c
|
||||||
libdivecomputer_la_SOURCES += bluetooth.h bluetooth.c
|
libdivecomputer_la_SOURCES += bluetooth.h bluetooth.c
|
||||||
|
|||||||
324
src/bluetooth.c
324
src/bluetooth.c
@ -25,22 +25,14 @@
|
|||||||
|
|
||||||
#include <stdlib.h> // malloc, free
|
#include <stdlib.h> // malloc, free
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define NOGDI
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#ifdef HAVE_WS2BTH_H
|
#ifdef HAVE_WS2BTH_H
|
||||||
#define BLUETOOTH
|
#define BLUETOOTH
|
||||||
#include <ws2bth.h>
|
#include <ws2bth.h>
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#include <errno.h> // errno
|
|
||||||
#include <unistd.h> // close
|
|
||||||
#include <sys/types.h> // socket, getsockopt
|
|
||||||
#include <sys/socket.h> // socket, getsockopt
|
|
||||||
#include <sys/select.h> // select
|
|
||||||
#include <sys/ioctl.h> // ioctl
|
|
||||||
#include <sys/time.h>
|
|
||||||
#ifdef HAVE_BLUEZ
|
#ifdef HAVE_BLUEZ
|
||||||
#define BLUETOOTH
|
#define BLUETOOTH
|
||||||
#include <bluetooth/bluetooth.h>
|
#include <bluetooth/bluetooth.h>
|
||||||
@ -56,34 +48,6 @@
|
|||||||
#include "context-private.h"
|
#include "context-private.h"
|
||||||
#include "iostream-private.h"
|
#include "iostream-private.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
typedef int s_ssize_t;
|
|
||||||
typedef DWORD s_errcode_t;
|
|
||||||
#define S_ERRNO WSAGetLastError ()
|
|
||||||
#define S_EINTR WSAEINTR
|
|
||||||
#define S_EAGAIN WSAEWOULDBLOCK
|
|
||||||
#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY
|
|
||||||
#define S_EINVAL WSAEINVAL
|
|
||||||
#define S_EACCES WSAEACCES
|
|
||||||
#define S_EAFNOSUPPORT WSAEAFNOSUPPORT
|
|
||||||
#define S_INVALID INVALID_SOCKET
|
|
||||||
#define S_IOCTL ioctlsocket
|
|
||||||
#define S_CLOSE closesocket
|
|
||||||
#else
|
|
||||||
typedef ssize_t s_ssize_t;
|
|
||||||
typedef int s_errcode_t;
|
|
||||||
#define S_ERRNO errno
|
|
||||||
#define S_EINTR EINTR
|
|
||||||
#define S_EAGAIN EAGAIN
|
|
||||||
#define S_ENOMEM ENOMEM
|
|
||||||
#define S_EINVAL EINVAL
|
|
||||||
#define S_EACCES EACCES
|
|
||||||
#define S_EAFNOSUPPORT EAFNOSUPPORT
|
|
||||||
#define S_INVALID -1
|
|
||||||
#define S_IOCTL ioctl
|
|
||||||
#define S_CLOSE close
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define DC_ADDRESS_FORMAT "%012I64X"
|
#define DC_ADDRESS_FORMAT "%012I64X"
|
||||||
#else
|
#else
|
||||||
@ -98,58 +62,25 @@ typedef int s_errcode_t;
|
|||||||
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_bluetooth_vtable)
|
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_bluetooth_vtable)
|
||||||
|
|
||||||
#ifdef BLUETOOTH
|
#ifdef BLUETOOTH
|
||||||
static dc_status_t dc_bluetooth_set_timeout (dc_iostream_t *iostream, int timeout);
|
|
||||||
static dc_status_t dc_bluetooth_get_available (dc_iostream_t *iostream, size_t *value);
|
|
||||||
static dc_status_t dc_bluetooth_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
|
||||||
static dc_status_t dc_bluetooth_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
|
||||||
static dc_status_t dc_bluetooth_close (dc_iostream_t *iostream);
|
|
||||||
|
|
||||||
typedef struct dc_bluetooth_t {
|
|
||||||
dc_iostream_t base;
|
|
||||||
#ifdef _WIN32
|
|
||||||
SOCKET fd;
|
|
||||||
#else
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
int timeout;
|
|
||||||
} dc_bluetooth_t;
|
|
||||||
|
|
||||||
static const dc_iostream_vtable_t dc_bluetooth_vtable = {
|
static const dc_iostream_vtable_t dc_bluetooth_vtable = {
|
||||||
sizeof(dc_bluetooth_t),
|
sizeof(dc_socket_t),
|
||||||
dc_bluetooth_set_timeout, /* set_timeout */
|
dc_socket_set_timeout, /* set_timeout */
|
||||||
NULL, /* set_latency */
|
NULL, /* set_latency */
|
||||||
NULL, /* set_halfduplex */
|
NULL, /* set_halfduplex */
|
||||||
NULL, /* set_break */
|
NULL, /* set_break */
|
||||||
NULL, /* set_dtr */
|
NULL, /* set_dtr */
|
||||||
NULL, /* set_rts */
|
NULL, /* set_rts */
|
||||||
NULL, /* get_lines */
|
NULL, /* get_lines */
|
||||||
dc_bluetooth_get_available, /* get_received */
|
dc_socket_get_available, /* get_received */
|
||||||
NULL, /* configure */
|
NULL, /* configure */
|
||||||
dc_bluetooth_read, /* read */
|
dc_socket_read, /* read */
|
||||||
dc_bluetooth_write, /* write */
|
dc_socket_write, /* write */
|
||||||
NULL, /* flush */
|
NULL, /* flush */
|
||||||
NULL, /* purge */
|
NULL, /* purge */
|
||||||
NULL, /* sleep */
|
NULL, /* sleep */
|
||||||
dc_bluetooth_close, /* close */
|
dc_socket_close, /* close */
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
syserror(s_errcode_t errcode)
|
|
||||||
{
|
|
||||||
switch (errcode) {
|
|
||||||
case S_EINVAL:
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
case S_ENOMEM:
|
|
||||||
return DC_STATUS_NOMEMORY;
|
|
||||||
case S_EACCES:
|
|
||||||
return DC_STATUS_NOACCESS;
|
|
||||||
case S_EAFNOSUPPORT:
|
|
||||||
return DC_STATUS_UNSUPPORTED;
|
|
||||||
default:
|
|
||||||
return DC_STATUS_IO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_BLUEZ
|
#ifdef HAVE_BLUEZ
|
||||||
static dc_bluetooth_address_t
|
static dc_bluetooth_address_t
|
||||||
dc_address_get (const bdaddr_t *ba)
|
dc_address_get (const bdaddr_t *ba)
|
||||||
@ -182,65 +113,33 @@ dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context)
|
|||||||
{
|
{
|
||||||
#ifdef BLUETOOTH
|
#ifdef BLUETOOTH
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
dc_bluetooth_t *device = NULL;
|
dc_socket_t *device = NULL;
|
||||||
|
|
||||||
if (out == NULL)
|
if (out == NULL)
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// Allocate memory.
|
||||||
device = (dc_bluetooth_t *) dc_iostream_allocate (context, &dc_bluetooth_vtable);
|
device = (dc_socket_t *) dc_iostream_allocate (context, &dc_bluetooth_vtable);
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
SYSERROR (context, S_ENOMEM);
|
SYSERROR (context, S_ENOMEM);
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to blocking reads.
|
|
||||||
device->timeout = -1;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Initialize the winsock dll.
|
|
||||||
WSADATA wsaData;
|
|
||||||
WORD wVersionRequested = MAKEWORD (2, 2);
|
|
||||||
int rc = WSAStartup (wVersionRequested, &wsaData);
|
|
||||||
if (rc != 0) {
|
|
||||||
SYSERROR (context, rc);
|
|
||||||
status = DC_STATUS_UNSUPPORTED;
|
|
||||||
goto error_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm that the winsock dll supports version 2.2.
|
|
||||||
// Note that if the dll supports versions greater than 2.2 in addition to
|
|
||||||
// 2.2, it will still return 2.2 since that is the version we requested.
|
|
||||||
if (LOBYTE (wsaData.wVersion) != 2 ||
|
|
||||||
HIBYTE (wsaData.wVersion) != 2) {
|
|
||||||
ERROR (context, "Incorrect winsock version.");
|
|
||||||
status = DC_STATUS_UNSUPPORTED;
|
|
||||||
goto error_wsacleanup;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Open the socket.
|
// Open the socket.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
device->fd = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
|
status = dc_socket_open (&device->base, AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
|
||||||
#else
|
#else
|
||||||
device->fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
status = dc_socket_open (&device->base, AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
||||||
#endif
|
#endif
|
||||||
if (device->fd == S_INVALID) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
s_errcode_t errcode = S_ERRNO;
|
goto error_free;
|
||||||
SYSERROR (context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto error_wsacleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = (dc_iostream_t *) device;
|
*out = (dc_iostream_t *) device;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
error_wsacleanup:
|
|
||||||
#ifdef _WIN32
|
|
||||||
WSACleanup ();
|
|
||||||
error_free:
|
error_free:
|
||||||
#endif
|
|
||||||
dc_iostream_deallocate ((dc_iostream_t *) device);
|
dc_iostream_deallocate ((dc_iostream_t *) device);
|
||||||
return status;
|
return status;
|
||||||
#else
|
#else
|
||||||
@ -248,46 +147,6 @@ error_free:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BLUETOOTH
|
|
||||||
static dc_status_t
|
|
||||||
dc_bluetooth_close (dc_iostream_t *abstract)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
|
|
||||||
|
|
||||||
// Terminate all send and receive operations.
|
|
||||||
shutdown (device->fd, 0);
|
|
||||||
|
|
||||||
// Close the socket.
|
|
||||||
if (S_CLOSE (device->fd) != 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
dc_status_set_error(&status, syserror(errcode));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Terminate the winsock dll.
|
|
||||||
if (WSACleanup () != 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
dc_status_set_error(&status, syserror(errcode));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
dc_bluetooth_set_timeout (dc_iostream_t *abstract, int timeout)
|
|
||||||
{
|
|
||||||
dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
|
|
||||||
|
|
||||||
device->timeout = timeout;
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback, void *userdata)
|
dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback, void *userdata)
|
||||||
{
|
{
|
||||||
@ -312,7 +171,7 @@ dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback
|
|||||||
status = DC_STATUS_SUCCESS;
|
status = DC_STATUS_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
status = syserror(errcode);
|
status = dc_socket_syserror(errcode);
|
||||||
}
|
}
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
@ -332,7 +191,7 @@ dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback
|
|||||||
break; // No more results.
|
break; // No more results.
|
||||||
}
|
}
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
status = syserror(errcode);
|
status = dc_socket_syserror(errcode);
|
||||||
goto error_close;
|
goto error_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +221,7 @@ error_close:
|
|||||||
if (dev < 0) {
|
if (dev < 0) {
|
||||||
s_errcode_t errcode = S_ERRNO;
|
s_errcode_t errcode = S_ERRNO;
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
status = syserror(errcode);
|
status = dc_socket_syserror(errcode);
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +230,7 @@ error_close:
|
|||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
s_errcode_t errcode = S_ERRNO;
|
s_errcode_t errcode = S_ERRNO;
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
status = syserror(errcode);
|
status = dc_socket_syserror(errcode);
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +239,7 @@ error_close:
|
|||||||
if (devices == NULL) {
|
if (devices == NULL) {
|
||||||
s_errcode_t errcode = S_ERRNO;
|
s_errcode_t errcode = S_ERRNO;
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
status = syserror(errcode);
|
status = dc_socket_syserror(errcode);
|
||||||
goto error_close;
|
goto error_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +250,7 @@ error_close:
|
|||||||
if (ndevices < 0) {
|
if (ndevices < 0) {
|
||||||
s_errcode_t errcode = S_ERRNO;
|
s_errcode_t errcode = S_ERRNO;
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
status = syserror(errcode);
|
status = dc_socket_syserror(errcode);
|
||||||
goto error_free;
|
goto error_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +286,7 @@ dc_status_t
|
|||||||
dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, unsigned int port)
|
dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, unsigned int port)
|
||||||
{
|
{
|
||||||
#ifdef BLUETOOTH
|
#ifdef BLUETOOTH
|
||||||
dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
|
dc_socket_t *device = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
if (!ISINSTANCE (abstract))
|
if (!ISINSTANCE (abstract))
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -447,147 +306,8 @@ dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, u
|
|||||||
dc_address_set (&sa.rc_bdaddr, address);
|
dc_address_set (&sa.rc_bdaddr, address);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (connect (device->fd, (struct sockaddr *) &sa, sizeof (sa)) != 0) {
|
return dc_socket_connect (&device->base, (struct sockaddr *) &sa, sizeof (sa));
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
return syserror(errcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
#else
|
#else
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BLUETOOTH
|
|
||||||
static dc_status_t
|
|
||||||
dc_bluetooth_get_available (dc_iostream_t *abstract, size_t *value)
|
|
||||||
{
|
|
||||||
dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
unsigned long bytes = 0;
|
|
||||||
#else
|
|
||||||
int bytes = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
return syserror(errcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value)
|
|
||||||
*value = bytes;
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
dc_bluetooth_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
|
|
||||||
size_t nbytes = 0;
|
|
||||||
|
|
||||||
while (nbytes < size) {
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO (&fds);
|
|
||||||
FD_SET (device->fd, &fds);
|
|
||||||
|
|
||||||
struct timeval tvt;
|
|
||||||
if (device->timeout > 0) {
|
|
||||||
tvt.tv_sec = (device->timeout / 1000);
|
|
||||||
tvt.tv_usec = (device->timeout % 1000) * 1000;
|
|
||||||
} else if (device->timeout == 0) {
|
|
||||||
timerclear (&tvt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = select (device->fd + 1, &fds, NULL, NULL, device->timeout >= 0 ? &tvt : NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (rc == 0) {
|
|
||||||
break; // Timeout.
|
|
||||||
}
|
|
||||||
|
|
||||||
s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
|
|
||||||
if (n < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR || errcode == S_EAGAIN)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (n == 0) {
|
|
||||||
break; // EOF reached.
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes != size) {
|
|
||||||
status = DC_STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (actual)
|
|
||||||
*actual = nbytes;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
dc_bluetooth_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
|
|
||||||
size_t nbytes = 0;
|
|
||||||
|
|
||||||
while (nbytes < size) {
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO (&fds);
|
|
||||||
FD_SET (device->fd, &fds);
|
|
||||||
|
|
||||||
int rc = select (device->fd + 1, NULL, &fds, NULL, NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (rc == 0) {
|
|
||||||
break; // Timeout.
|
|
||||||
}
|
|
||||||
|
|
||||||
s_ssize_t n = send (device->fd, (const char *) data + nbytes, size - nbytes, 0);
|
|
||||||
if (n < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR || errcode == S_EAGAIN)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (n == 0) {
|
|
||||||
break; // EOF.
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes != size) {
|
|
||||||
status = DC_STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (actual)
|
|
||||||
*actual = nbytes;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
345
src/irda.c
345
src/irda.c
@ -25,28 +25,21 @@
|
|||||||
|
|
||||||
#include <stdlib.h> // malloc, free
|
#include <stdlib.h> // malloc, free
|
||||||
#include <stdio.h> // snprintf
|
#include <stdio.h> // snprintf
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define NOGDI
|
#ifdef HAVE_AF_IRDA_H
|
||||||
#include <winsock2.h>
|
#define IRDA
|
||||||
#include <windows.h>
|
#include <af_irda.h>
|
||||||
#ifdef HAVE_AF_IRDA_H
|
#endif
|
||||||
#define IRDA
|
|
||||||
#include <af_irda.h>
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#include <string.h> // strerror
|
#ifdef HAVE_LINUX_IRDA_H
|
||||||
#include <errno.h> // errno
|
#define IRDA
|
||||||
#include <unistd.h> // close
|
#include <linux/types.h>
|
||||||
#include <sys/types.h> // socket, getsockopt
|
#include <linux/irda.h>
|
||||||
#include <sys/socket.h> // socket, getsockopt
|
#endif
|
||||||
#ifdef HAVE_LINUX_IRDA_H
|
|
||||||
#define IRDA
|
|
||||||
#include <linux/types.h> // irda
|
|
||||||
#include <linux/irda.h> // irda
|
|
||||||
#endif
|
|
||||||
#include <sys/select.h> // select
|
|
||||||
#include <sys/ioctl.h> // ioctl
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "irda.h"
|
#include "irda.h"
|
||||||
@ -57,88 +50,27 @@
|
|||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
typedef int s_ssize_t;
|
|
||||||
typedef DWORD s_errcode_t;
|
|
||||||
#define S_ERRNO WSAGetLastError ()
|
|
||||||
#define S_EINTR WSAEINTR
|
|
||||||
#define S_EAGAIN WSAEWOULDBLOCK
|
|
||||||
#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY
|
|
||||||
#define S_EINVAL WSAEINVAL
|
|
||||||
#define S_EACCES WSAEACCES
|
|
||||||
#define S_EAFNOSUPPORT WSAEAFNOSUPPORT
|
|
||||||
#define S_INVALID INVALID_SOCKET
|
|
||||||
#define S_IOCTL ioctlsocket
|
|
||||||
#define S_CLOSE closesocket
|
|
||||||
#else
|
|
||||||
typedef ssize_t s_ssize_t;
|
|
||||||
typedef int s_errcode_t;
|
|
||||||
#define S_ERRNO errno
|
|
||||||
#define S_EINTR EINTR
|
|
||||||
#define S_EAGAIN EAGAIN
|
|
||||||
#define S_ENOMEM ENOMEM
|
|
||||||
#define S_EINVAL EINVAL
|
|
||||||
#define S_EACCES EACCES
|
|
||||||
#define S_EAFNOSUPPORT EAFNOSUPPORT
|
|
||||||
#define S_INVALID -1
|
|
||||||
#define S_IOCTL ioctl
|
|
||||||
#define S_CLOSE close
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_irda_vtable)
|
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_irda_vtable)
|
||||||
|
|
||||||
#ifdef IRDA
|
#ifdef IRDA
|
||||||
static dc_status_t dc_irda_set_timeout (dc_iostream_t *iostream, int timeout);
|
|
||||||
static dc_status_t dc_irda_get_available (dc_iostream_t *iostream, size_t *value);
|
|
||||||
static dc_status_t dc_irda_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
|
||||||
static dc_status_t dc_irda_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
|
||||||
static dc_status_t dc_irda_close (dc_iostream_t *iostream);
|
|
||||||
|
|
||||||
typedef struct dc_irda_t {
|
|
||||||
dc_iostream_t base;
|
|
||||||
#ifdef _WIN32
|
|
||||||
SOCKET fd;
|
|
||||||
#else
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
int timeout;
|
|
||||||
} dc_irda_t;
|
|
||||||
|
|
||||||
static const dc_iostream_vtable_t dc_irda_vtable = {
|
static const dc_iostream_vtable_t dc_irda_vtable = {
|
||||||
sizeof(dc_irda_t),
|
sizeof(dc_socket_t),
|
||||||
dc_irda_set_timeout, /* set_timeout */
|
dc_socket_set_timeout, /* set_timeout */
|
||||||
NULL, /* set_latency */
|
NULL, /* set_latency */
|
||||||
NULL, /* set_halfduplex */
|
NULL, /* set_halfduplex */
|
||||||
NULL, /* set_break */
|
NULL, /* set_break */
|
||||||
NULL, /* set_dtr */
|
NULL, /* set_dtr */
|
||||||
NULL, /* set_rts */
|
NULL, /* set_rts */
|
||||||
NULL, /* get_lines */
|
NULL, /* get_lines */
|
||||||
dc_irda_get_available, /* get_received */
|
dc_socket_get_available, /* get_received */
|
||||||
NULL, /* configure */
|
NULL, /* configure */
|
||||||
dc_irda_read, /* read */
|
dc_socket_read, /* read */
|
||||||
dc_irda_write, /* write */
|
dc_socket_write, /* write */
|
||||||
NULL, /* flush */
|
NULL, /* flush */
|
||||||
NULL, /* purge */
|
NULL, /* purge */
|
||||||
NULL, /* sleep */
|
NULL, /* sleep */
|
||||||
dc_irda_close, /* close */
|
dc_socket_close, /* close */
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
syserror(s_errcode_t errcode)
|
|
||||||
{
|
|
||||||
switch (errcode) {
|
|
||||||
case S_EINVAL:
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
case S_ENOMEM:
|
|
||||||
return DC_STATUS_NOMEMORY;
|
|
||||||
case S_EACCES:
|
|
||||||
return DC_STATUS_NOACCESS;
|
|
||||||
case S_EAFNOSUPPORT:
|
|
||||||
return DC_STATUS_UNSUPPORTED;
|
|
||||||
default:
|
|
||||||
return DC_STATUS_IO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
@ -146,61 +78,29 @@ dc_irda_open (dc_iostream_t **out, dc_context_t *context)
|
|||||||
{
|
{
|
||||||
#ifdef IRDA
|
#ifdef IRDA
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
dc_irda_t *device = NULL;
|
dc_socket_t *device = NULL;
|
||||||
|
|
||||||
if (out == NULL)
|
if (out == NULL)
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// Allocate memory.
|
||||||
device = (dc_irda_t *) dc_iostream_allocate (context, &dc_irda_vtable);
|
device = (dc_socket_t *) dc_iostream_allocate (context, &dc_irda_vtable);
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
SYSERROR (context, S_ENOMEM);
|
SYSERROR (context, S_ENOMEM);
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to blocking reads.
|
|
||||||
device->timeout = -1;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Initialize the winsock dll.
|
|
||||||
WSADATA wsaData;
|
|
||||||
WORD wVersionRequested = MAKEWORD (2, 2);
|
|
||||||
int rc = WSAStartup (wVersionRequested, &wsaData);
|
|
||||||
if (rc != 0) {
|
|
||||||
SYSERROR (context, rc);
|
|
||||||
status = DC_STATUS_UNSUPPORTED;
|
|
||||||
goto error_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm that the winsock dll supports version 2.2.
|
|
||||||
// Note that if the dll supports versions greater than 2.2 in addition to
|
|
||||||
// 2.2, it will still return 2.2 since that is the version we requested.
|
|
||||||
if (LOBYTE (wsaData.wVersion) != 2 ||
|
|
||||||
HIBYTE (wsaData.wVersion) != 2) {
|
|
||||||
ERROR (context, "Incorrect winsock version.");
|
|
||||||
status = DC_STATUS_UNSUPPORTED;
|
|
||||||
goto error_wsacleanup;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Open the socket.
|
// Open the socket.
|
||||||
device->fd = socket (AF_IRDA, SOCK_STREAM, 0);
|
status = dc_socket_open (&device->base, AF_IRDA, SOCK_STREAM, 0);
|
||||||
if (device->fd == S_INVALID) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
s_errcode_t errcode = S_ERRNO;
|
goto error_free;
|
||||||
SYSERROR (context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto error_wsacleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = (dc_iostream_t *) device;
|
*out = (dc_iostream_t *) device;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
error_wsacleanup:
|
|
||||||
#ifdef _WIN32
|
|
||||||
WSACleanup ();
|
|
||||||
error_free:
|
error_free:
|
||||||
#endif
|
|
||||||
dc_iostream_deallocate ((dc_iostream_t *) device);
|
dc_iostream_deallocate ((dc_iostream_t *) device);
|
||||||
return status;
|
return status;
|
||||||
#else
|
#else
|
||||||
@ -208,46 +108,6 @@ error_free:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IRDA
|
|
||||||
static dc_status_t
|
|
||||||
dc_irda_close (dc_iostream_t *abstract)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
|
||||||
|
|
||||||
// Terminate all send and receive operations.
|
|
||||||
shutdown (device->fd, 0);
|
|
||||||
|
|
||||||
// Close the socket.
|
|
||||||
if (S_CLOSE (device->fd) != 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
dc_status_set_error(&status, syserror(errcode));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Terminate the winsock dll.
|
|
||||||
if (WSACleanup () != 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
dc_status_set_error(&status, syserror(errcode));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
dc_irda_set_timeout (dc_iostream_t *abstract, int timeout)
|
|
||||||
{
|
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
|
||||||
|
|
||||||
device->timeout = timeout;
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DISCOVER_MAX_DEVICES 16 // Maximum number of devices.
|
#define DISCOVER_MAX_DEVICES 16 // Maximum number of devices.
|
||||||
#define DISCOVER_MAX_RETRIES 4 // Maximum number of retries.
|
#define DISCOVER_MAX_RETRIES 4 // Maximum number of retries.
|
||||||
|
|
||||||
@ -263,7 +123,7 @@ dc_status_t
|
|||||||
dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *userdata)
|
dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *userdata)
|
||||||
{
|
{
|
||||||
#ifdef IRDA
|
#ifdef IRDA
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
dc_socket_t *device = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
if (!ISINSTANCE (abstract))
|
if (!ISINSTANCE (abstract))
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -294,7 +154,7 @@ dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *us
|
|||||||
s_errcode_t errcode = S_ERRNO;
|
s_errcode_t errcode = S_ERRNO;
|
||||||
if (errcode != S_EAGAIN) {
|
if (errcode != S_EAGAIN) {
|
||||||
SYSERROR (abstract->context, errcode);
|
SYSERROR (abstract->context, errcode);
|
||||||
return syserror(errcode);
|
return dc_socket_syserror(errcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +207,7 @@ dc_status_t
|
|||||||
dc_irda_connect_name (dc_iostream_t *abstract, unsigned int address, const char *name)
|
dc_irda_connect_name (dc_iostream_t *abstract, unsigned int address, const char *name)
|
||||||
{
|
{
|
||||||
#ifdef IRDA
|
#ifdef IRDA
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
dc_socket_t *device = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
if (!ISINSTANCE (abstract))
|
if (!ISINSTANCE (abstract))
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -375,13 +235,7 @@ dc_irda_connect_name (dc_iostream_t *abstract, unsigned int address, const char
|
|||||||
memset (peer.sir_name, 0x00, 25);
|
memset (peer.sir_name, 0x00, 25);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
|
return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
return syserror(errcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
#else
|
#else
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
#endif
|
#endif
|
||||||
@ -391,7 +245,7 @@ dc_status_t
|
|||||||
dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned int lsap)
|
dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned int lsap)
|
||||||
{
|
{
|
||||||
#ifdef IRDA
|
#ifdef IRDA
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
dc_socket_t *device = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
if (!ISINSTANCE (abstract))
|
if (!ISINSTANCE (abstract))
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -414,147 +268,8 @@ dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned in
|
|||||||
memset (peer.sir_name, 0x00, 25);
|
memset (peer.sir_name, 0x00, 25);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
|
return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
return syserror(errcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
#else
|
#else
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IRDA
|
|
||||||
static dc_status_t
|
|
||||||
dc_irda_get_available (dc_iostream_t *abstract, size_t *value)
|
|
||||||
{
|
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
unsigned long bytes = 0;
|
|
||||||
#else
|
|
||||||
int bytes = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
return syserror(errcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value)
|
|
||||||
*value = bytes;
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
dc_irda_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
|
||||||
size_t nbytes = 0;
|
|
||||||
|
|
||||||
while (nbytes < size) {
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO (&fds);
|
|
||||||
FD_SET (device->fd, &fds);
|
|
||||||
|
|
||||||
struct timeval tvt;
|
|
||||||
if (device->timeout > 0) {
|
|
||||||
tvt.tv_sec = (device->timeout / 1000);
|
|
||||||
tvt.tv_usec = (device->timeout % 1000) * 1000;
|
|
||||||
} else if (device->timeout == 0) {
|
|
||||||
timerclear (&tvt);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = select (device->fd + 1, &fds, NULL, NULL, device->timeout >= 0 ? &tvt : NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (rc == 0) {
|
|
||||||
break; // Timeout.
|
|
||||||
}
|
|
||||||
|
|
||||||
s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
|
|
||||||
if (n < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR || errcode == S_EAGAIN)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (n == 0) {
|
|
||||||
break; // EOF reached.
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes != size) {
|
|
||||||
status = DC_STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (actual)
|
|
||||||
*actual = nbytes;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
dc_irda_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
dc_irda_t *device = (dc_irda_t *) abstract;
|
|
||||||
size_t nbytes = 0;
|
|
||||||
|
|
||||||
while (nbytes < size) {
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO (&fds);
|
|
||||||
FD_SET (device->fd, &fds);
|
|
||||||
|
|
||||||
int rc = select (device->fd + 1, NULL, &fds, NULL, NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (rc == 0) {
|
|
||||||
break; // Timeout.
|
|
||||||
}
|
|
||||||
|
|
||||||
s_ssize_t n = send (device->fd, (const char *) data + nbytes, size - nbytes, 0);
|
|
||||||
if (n < 0) {
|
|
||||||
s_errcode_t errcode = S_ERRNO;
|
|
||||||
if (errcode == S_EINTR || errcode == S_EAGAIN)
|
|
||||||
continue; // Retry.
|
|
||||||
SYSERROR (abstract->context, errcode);
|
|
||||||
status = syserror(errcode);
|
|
||||||
goto out;
|
|
||||||
} else if (n == 0) {
|
|
||||||
break; // EOF.
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes != size) {
|
|
||||||
status = DC_STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (actual)
|
|
||||||
*actual = nbytes;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
295
src/socket.c
Normal file
295
src/socket.c
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* libdivecomputer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jef Driesen
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
#include "common-private.h"
|
||||||
|
#include "context-private.h"
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_syserror (s_errcode_t errcode)
|
||||||
|
{
|
||||||
|
switch (errcode) {
|
||||||
|
case S_EINVAL:
|
||||||
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
case S_ENOMEM:
|
||||||
|
return DC_STATUS_NOMEMORY;
|
||||||
|
case S_EACCES:
|
||||||
|
return DC_STATUS_NOACCESS;
|
||||||
|
case S_EAFNOSUPPORT:
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
default:
|
||||||
|
return DC_STATUS_IO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_init (dc_context_t *context)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Initialize the winsock dll.
|
||||||
|
WSADATA wsaData;
|
||||||
|
WORD wVersionRequested = MAKEWORD (2, 2);
|
||||||
|
int rc = WSAStartup (wVersionRequested, &wsaData);
|
||||||
|
if (rc != 0) {
|
||||||
|
SYSERROR (context, rc);
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm that the winsock dll supports version 2.2.
|
||||||
|
// Note that if the dll supports versions greater than 2.2 in addition to
|
||||||
|
// 2.2, it will still return 2.2 since that is the version we requested.
|
||||||
|
if (LOBYTE (wsaData.wVersion) != 2 ||
|
||||||
|
HIBYTE (wsaData.wVersion) != 2) {
|
||||||
|
ERROR (context, "Incorrect winsock version.");
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_exit (dc_context_t *context)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Terminate the winsock dll.
|
||||||
|
if (WSACleanup () != 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
SYSERROR (context, errcode);
|
||||||
|
return dc_socket_syserror(errcode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_open (dc_iostream_t *abstract, int family, int type, int protocol)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_socket_t *device = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
|
// Default to blocking reads.
|
||||||
|
device->timeout = -1;
|
||||||
|
|
||||||
|
// Initialize the socket library.
|
||||||
|
status = dc_socket_init (abstract->context);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the socket.
|
||||||
|
device->fd = socket (family, type, protocol);
|
||||||
|
if (device->fd == S_INVALID) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
status = dc_socket_syserror(errcode);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
dc_socket_exit (abstract->context);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_close (dc_iostream_t *abstract)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_socket_t *socket = (dc_socket_t *) abstract;
|
||||||
|
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
// Terminate all send and receive operations.
|
||||||
|
shutdown (socket->fd, 0);
|
||||||
|
|
||||||
|
// Close the socket.
|
||||||
|
if (S_CLOSE (socket->fd) != 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
dc_status_set_error(&status, dc_socket_syserror(errcode));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate the socket library.
|
||||||
|
rc = dc_socket_exit (abstract->context);
|
||||||
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
|
dc_status_set_error(&status, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_connect (dc_iostream_t *abstract, const struct sockaddr *addr, s_socklen_t addrlen)
|
||||||
|
{
|
||||||
|
dc_socket_t *socket = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
|
if (connect (socket->fd, addr, addrlen) != 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
return dc_socket_syserror(errcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_set_timeout (dc_iostream_t *abstract, int timeout)
|
||||||
|
{
|
||||||
|
dc_socket_t *socket = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
|
socket->timeout = timeout;
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_get_available (dc_iostream_t *abstract, size_t *value)
|
||||||
|
{
|
||||||
|
dc_socket_t *socket = (dc_socket_t *) abstract;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
unsigned long bytes = 0;
|
||||||
|
#else
|
||||||
|
int bytes = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (S_IOCTL (socket->fd, FIONREAD, &bytes) != 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
return dc_socket_syserror(errcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
*value = bytes;
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_socket_t *socket = (dc_socket_t *) abstract;
|
||||||
|
size_t nbytes = 0;
|
||||||
|
|
||||||
|
while (nbytes < size) {
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO (&fds);
|
||||||
|
FD_SET (socket->fd, &fds);
|
||||||
|
|
||||||
|
struct timeval tvt;
|
||||||
|
if (socket->timeout > 0) {
|
||||||
|
tvt.tv_sec = (socket->timeout / 1000);
|
||||||
|
tvt.tv_usec = (socket->timeout % 1000) * 1000;
|
||||||
|
} else if (socket->timeout == 0) {
|
||||||
|
timerclear (&tvt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = select (socket->fd + 1, &fds, NULL, NULL, socket->timeout >= 0 ? &tvt : NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
if (errcode == S_EINTR)
|
||||||
|
continue; // Retry.
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
status = dc_socket_syserror(errcode);
|
||||||
|
goto out;
|
||||||
|
} else if (rc == 0) {
|
||||||
|
break; // Timeout.
|
||||||
|
}
|
||||||
|
|
||||||
|
s_ssize_t n = recv (socket->fd, (char *) data + nbytes, size - nbytes, 0);
|
||||||
|
if (n < 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
if (errcode == S_EINTR || errcode == S_EAGAIN)
|
||||||
|
continue; // Retry.
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
status = dc_socket_syserror(errcode);
|
||||||
|
goto out;
|
||||||
|
} else if (n == 0) {
|
||||||
|
break; // EOF reached.
|
||||||
|
}
|
||||||
|
|
||||||
|
nbytes += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes != size) {
|
||||||
|
status = DC_STATUS_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (actual)
|
||||||
|
*actual = nbytes;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_socket_t *socket = (dc_socket_t *) abstract;
|
||||||
|
size_t nbytes = 0;
|
||||||
|
|
||||||
|
while (nbytes < size) {
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO (&fds);
|
||||||
|
FD_SET (socket->fd, &fds);
|
||||||
|
|
||||||
|
int rc = select (socket->fd + 1, NULL, &fds, NULL, NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
if (errcode == S_EINTR)
|
||||||
|
continue; // Retry.
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
status = dc_socket_syserror(errcode);
|
||||||
|
goto out;
|
||||||
|
} else if (rc == 0) {
|
||||||
|
break; // Timeout.
|
||||||
|
}
|
||||||
|
|
||||||
|
s_ssize_t n = send (socket->fd, (const char *) data + nbytes, size - nbytes, 0);
|
||||||
|
if (n < 0) {
|
||||||
|
s_errcode_t errcode = S_ERRNO;
|
||||||
|
if (errcode == S_EINTR || errcode == S_EAGAIN)
|
||||||
|
continue; // Retry.
|
||||||
|
SYSERROR (abstract->context, errcode);
|
||||||
|
status = dc_socket_syserror(errcode);
|
||||||
|
goto out;
|
||||||
|
} else if (n == 0) {
|
||||||
|
break; // EOF.
|
||||||
|
}
|
||||||
|
|
||||||
|
nbytes += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes != size) {
|
||||||
|
status = DC_STATUS_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (actual)
|
||||||
|
*actual = nbytes;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
119
src/socket.h
Normal file
119
src/socket.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* libdivecomputer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jef Driesen
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DC_SOCKET_H
|
||||||
|
#define DC_SOCKET_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define NOGDI
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <errno.h> // errno
|
||||||
|
#include <unistd.h> // close
|
||||||
|
#include <sys/types.h> // socket, getsockopt
|
||||||
|
#include <sys/socket.h> // socket, getsockopt
|
||||||
|
#include <sys/select.h> // select
|
||||||
|
#include <sys/ioctl.h> // ioctl
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <libdivecomputer/common.h>
|
||||||
|
#include <libdivecomputer/context.h>
|
||||||
|
|
||||||
|
#include "iostream-private.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef SOCKET s_socket_t;
|
||||||
|
typedef int s_ssize_t;
|
||||||
|
typedef DWORD s_errcode_t;
|
||||||
|
typedef int s_socklen_t;
|
||||||
|
#define S_ERRNO WSAGetLastError ()
|
||||||
|
#define S_EINTR WSAEINTR
|
||||||
|
#define S_EAGAIN WSAEWOULDBLOCK
|
||||||
|
#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY
|
||||||
|
#define S_EINVAL WSAEINVAL
|
||||||
|
#define S_EACCES WSAEACCES
|
||||||
|
#define S_EAFNOSUPPORT WSAEAFNOSUPPORT
|
||||||
|
#define S_INVALID INVALID_SOCKET
|
||||||
|
#define S_IOCTL ioctlsocket
|
||||||
|
#define S_CLOSE closesocket
|
||||||
|
#else
|
||||||
|
typedef int s_socket_t;
|
||||||
|
typedef ssize_t s_ssize_t;
|
||||||
|
typedef int s_errcode_t;
|
||||||
|
typedef socklen_t s_socklen_t;
|
||||||
|
#define S_ERRNO errno
|
||||||
|
#define S_EINTR EINTR
|
||||||
|
#define S_EAGAIN EAGAIN
|
||||||
|
#define S_ENOMEM ENOMEM
|
||||||
|
#define S_EINVAL EINVAL
|
||||||
|
#define S_EACCES EACCES
|
||||||
|
#define S_EAFNOSUPPORT EAFNOSUPPORT
|
||||||
|
#define S_INVALID -1
|
||||||
|
#define S_IOCTL ioctl
|
||||||
|
#define S_CLOSE close
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
typedef struct dc_socket_t {
|
||||||
|
dc_iostream_t base;
|
||||||
|
s_socket_t fd;
|
||||||
|
int timeout;
|
||||||
|
} dc_socket_t;
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_syserror (s_errcode_t errcode);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_init (dc_context_t *context);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_exit (dc_context_t *context);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_open (dc_iostream_t *iostream, int family, int type, int protocol);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_close (dc_iostream_t *iostream);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_connect (dc_iostream_t *iostream, const struct sockaddr *addr, s_socklen_t addrlen);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_set_timeout (dc_iostream_t *iostream, int timeout);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_get_available (dc_iostream_t *iostream, size_t *value);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_socket_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* DC_SOCKET_H */
|
||||||
Loading…
x
Reference in New Issue
Block a user