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 */