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"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\socket.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common.c"
|
||||
>
|
||||
@ -768,6 +772,10 @@
|
||||
RelativePath="..\src\shearwater_predator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\socket.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common.h"
|
||||
>
|
||||
|
||||
@ -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
|
||||
|
||||
324
src/bluetooth.c
324
src/bluetooth.c
@ -25,22 +25,14 @@
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOGDI
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#ifdef HAVE_WS2BTH_H
|
||||
#define BLUETOOTH
|
||||
#include <ws2bth.h>
|
||||
#endif
|
||||
#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
|
||||
#define BLUETOOTH
|
||||
#include <bluetooth/bluetooth.h>
|
||||
@ -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
|
||||
|
||||
345
src/irda.c
345
src/irda.c
@ -25,28 +25,21 @@
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <stdio.h> // snprintf
|
||||
#include <string.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOGDI
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#ifdef HAVE_AF_IRDA_H
|
||||
#define IRDA
|
||||
#include <af_irda.h>
|
||||
#endif
|
||||
#ifdef HAVE_AF_IRDA_H
|
||||
#define IRDA
|
||||
#include <af_irda.h>
|
||||
#endif
|
||||
#else
|
||||
#include <string.h> // strerror
|
||||
#include <errno.h> // errno
|
||||
#include <unistd.h> // close
|
||||
#include <sys/types.h> // socket, getsockopt
|
||||
#include <sys/socket.h> // socket, getsockopt
|
||||
#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>
|
||||
#ifdef HAVE_LINUX_IRDA_H
|
||||
#define IRDA
|
||||
#include <linux/types.h>
|
||||
#include <linux/irda.h>
|
||||
#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
|
||||
|
||||
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