diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index ee31af8..c54c3d7 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -426,6 +426,10 @@
RelativePath="..\src\shearwater_predator_parser.c"
>
+
+
@@ -768,6 +772,10 @@
RelativePath="..\src\shearwater_predator.h"
>
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 24ede8c..586b89b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -78,6 +78,7 @@ else
libdivecomputer_la_SOURCES += serial.h serial_posix.c
endif
+libdivecomputer_la_SOURCES += socket.h socket.c
libdivecomputer_la_SOURCES += irda.h irda.c
libdivecomputer_la_SOURCES += usbhid.h usbhid.c
libdivecomputer_la_SOURCES += bluetooth.h bluetooth.c
diff --git a/src/bluetooth.c b/src/bluetooth.c
index 40fa7a6..3399cd2 100644
--- a/src/bluetooth.c
+++ b/src/bluetooth.c
@@ -25,22 +25,14 @@
#include // malloc, free
+#include "socket.h"
+
#ifdef _WIN32
-#define NOGDI
-#include
-#include
#ifdef HAVE_WS2BTH_H
#define BLUETOOTH
#include
#endif
#else
-#include // errno
-#include // close
-#include // socket, getsockopt
-#include // socket, getsockopt
-#include // select
-#include // ioctl
-#include
#ifdef HAVE_BLUEZ
#define BLUETOOTH
#include
@@ -56,34 +48,6 @@
#include "context-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
#define DC_ADDRESS_FORMAT "%012I64X"
#else
@@ -98,58 +62,25 @@ typedef int s_errcode_t;
#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_bluetooth_vtable)
#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 = {
- sizeof(dc_bluetooth_t),
- dc_bluetooth_set_timeout, /* set_timeout */
+ sizeof(dc_socket_t),
+ dc_socket_set_timeout, /* set_timeout */
NULL, /* set_latency */
NULL, /* set_halfduplex */
NULL, /* set_break */
NULL, /* set_dtr */
NULL, /* set_rts */
NULL, /* get_lines */
- dc_bluetooth_get_available, /* get_received */
+ dc_socket_get_available, /* get_received */
NULL, /* configure */
- dc_bluetooth_read, /* read */
- dc_bluetooth_write, /* write */
+ dc_socket_read, /* read */
+ dc_socket_write, /* write */
NULL, /* flush */
NULL, /* purge */
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
static dc_bluetooth_address_t
dc_address_get (const bdaddr_t *ba)
@@ -182,65 +113,33 @@ dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
- dc_bluetooth_t *device = NULL;
+ dc_socket_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// 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) {
SYSERROR (context, S_ENOMEM);
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.
#ifdef _WIN32
- device->fd = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
+ status = dc_socket_open (&device->base, AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
#else
- device->fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ status = dc_socket_open (&device->base, AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
#endif
- if (device->fd == S_INVALID) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (context, errcode);
- status = syserror(errcode);
- goto error_wsacleanup;
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_free;
}
*out = (dc_iostream_t *) device;
return DC_STATUS_SUCCESS;
-error_wsacleanup:
-#ifdef _WIN32
- WSACleanup ();
error_free:
-#endif
dc_iostream_deallocate ((dc_iostream_t *) device);
return status;
#else
@@ -248,46 +147,6 @@ error_free:
#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_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;
} else {
SYSERROR (abstract->context, errcode);
- status = syserror(errcode);
+ status = dc_socket_syserror(errcode);
}
goto error_exit;
}
@@ -332,7 +191,7 @@ dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback
break; // No more results.
}
SYSERROR (abstract->context, errcode);
- status = syserror(errcode);
+ status = dc_socket_syserror(errcode);
goto error_close;
}
@@ -362,7 +221,7 @@ error_close:
if (dev < 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (abstract->context, errcode);
- status = syserror(errcode);
+ status = dc_socket_syserror(errcode);
goto error_exit;
}
@@ -371,7 +230,7 @@ error_close:
if (fd < 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (abstract->context, errcode);
- status = syserror(errcode);
+ status = dc_socket_syserror(errcode);
goto error_exit;
}
@@ -380,7 +239,7 @@ error_close:
if (devices == NULL) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (abstract->context, errcode);
- status = syserror(errcode);
+ status = dc_socket_syserror(errcode);
goto error_close;
}
@@ -391,7 +250,7 @@ error_close:
if (ndevices < 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (abstract->context, errcode);
- status = syserror(errcode);
+ status = dc_socket_syserror(errcode);
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)
{
#ifdef BLUETOOTH
- dc_bluetooth_t *device = (dc_bluetooth_t *) abstract;
+ dc_socket_t *device = (dc_socket_t *) abstract;
if (!ISINSTANCE (abstract))
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);
#endif
- if (connect (device->fd, (struct sockaddr *) &sa, sizeof (sa)) != 0) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- return syserror(errcode);
- }
-
- return DC_STATUS_SUCCESS;
+ return dc_socket_connect (&device->base, (struct sockaddr *) &sa, sizeof (sa));
#else
return DC_STATUS_UNSUPPORTED;
#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
diff --git a/src/irda.c b/src/irda.c
index 980fab5..527e3c0 100644
--- a/src/irda.c
+++ b/src/irda.c
@@ -25,28 +25,21 @@
#include // malloc, free
#include // snprintf
+#include
+
+#include "socket.h"
+
#ifdef _WIN32
- #define NOGDI
- #include
- #include
- #ifdef HAVE_AF_IRDA_H
- #define IRDA
- #include
- #endif
+#ifdef HAVE_AF_IRDA_H
+#define IRDA
+#include
+#endif
#else
- #include // strerror
- #include // errno
- #include // close
- #include // socket, getsockopt
- #include // socket, getsockopt
- #ifdef HAVE_LINUX_IRDA_H
- #define IRDA
- #include // irda
- #include // irda
- #endif
- #include // select
- #include // ioctl
- #include
+#ifdef HAVE_LINUX_IRDA_H
+#define IRDA
+#include
+#include
+#endif
#endif
#include "irda.h"
@@ -57,88 +50,27 @@
#include "array.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)
#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 = {
- sizeof(dc_irda_t),
- dc_irda_set_timeout, /* set_timeout */
+ sizeof(dc_socket_t),
+ dc_socket_set_timeout, /* set_timeout */
NULL, /* set_latency */
NULL, /* set_halfduplex */
NULL, /* set_break */
NULL, /* set_dtr */
NULL, /* set_rts */
NULL, /* get_lines */
- dc_irda_get_available, /* get_received */
+ dc_socket_get_available, /* get_received */
NULL, /* configure */
- dc_irda_read, /* read */
- dc_irda_write, /* write */
+ dc_socket_read, /* read */
+ dc_socket_write, /* write */
NULL, /* flush */
NULL, /* purge */
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
dc_status_t
@@ -146,61 +78,29 @@ dc_irda_open (dc_iostream_t **out, dc_context_t *context)
{
#ifdef IRDA
dc_status_t status = DC_STATUS_SUCCESS;
- dc_irda_t *device = NULL;
+ dc_socket_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// 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) {
SYSERROR (context, S_ENOMEM);
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.
- device->fd = socket (AF_IRDA, SOCK_STREAM, 0);
- if (device->fd == S_INVALID) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (context, errcode);
- status = syserror(errcode);
- goto error_wsacleanup;
+ status = dc_socket_open (&device->base, AF_IRDA, SOCK_STREAM, 0);
+ if (status != DC_STATUS_SUCCESS) {
+ goto error_free;
}
*out = (dc_iostream_t *) device;
return DC_STATUS_SUCCESS;
-error_wsacleanup:
-#ifdef _WIN32
- WSACleanup ();
error_free:
-#endif
dc_iostream_deallocate ((dc_iostream_t *) device);
return status;
#else
@@ -208,46 +108,6 @@ error_free:
#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_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)
{
#ifdef IRDA
- dc_irda_t *device = (dc_irda_t *) abstract;
+ dc_socket_t *device = (dc_socket_t *) abstract;
if (!ISINSTANCE (abstract))
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;
if (errcode != S_EAGAIN) {
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)
{
#ifdef IRDA
- dc_irda_t *device = (dc_irda_t *) abstract;
+ dc_socket_t *device = (dc_socket_t *) abstract;
if (!ISINSTANCE (abstract))
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);
#endif
- if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- return syserror(errcode);
- }
-
- return DC_STATUS_SUCCESS;
+ return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
#else
return DC_STATUS_UNSUPPORTED;
#endif
@@ -391,7 +245,7 @@ dc_status_t
dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned int lsap)
{
#ifdef IRDA
- dc_irda_t *device = (dc_irda_t *) abstract;
+ dc_socket_t *device = (dc_socket_t *) abstract;
if (!ISINSTANCE (abstract))
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);
#endif
- if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
- s_errcode_t errcode = S_ERRNO;
- SYSERROR (abstract->context, errcode);
- return syserror(errcode);
- }
-
- return DC_STATUS_SUCCESS;
+ return dc_socket_connect (&device->base, (struct sockaddr *) &peer, sizeof (peer));
#else
return DC_STATUS_UNSUPPORTED;
#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
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..948aa46
--- /dev/null
+++ b/src/socket.c
@@ -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;
+}
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..1a8aa18
--- /dev/null
+++ b/src/socket.h
@@ -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
+#include
+#else
+#include // errno
+#include // close
+#include // socket, getsockopt
+#include // socket, getsockopt
+#include // select
+#include // ioctl
+#include
+#endif
+
+#include
+#include
+
+#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 */