--- include/openobex/obex_const.h | 1 + lib/CMakeLists.txt | 1 + lib/Makefile.am | 2 +- lib/btobex.c | 12 ++++++++- lib/fdobex.c | 58 +++++++++++++++++++++++++++++----------- lib/inobex.c | 12 ++++++++ lib/irobex.c | 21 ++++++++++----- lib/nonblock.h | 43 ++++++++++++++++++++++++++++++ lib/obex.c | 1 + lib/obex_main.c | 19 +++++++++---- lib/obex_transport.c | 51 ++++++++++++++++++++++++++---------- 11 files changed, 176 insertions(+), 45 deletions(-) create mode 100644 lib/nonblock.h
diff --git a/include/openobex/obex_const.h b/include/openobex/obex_const.h index b4bad7f..8276aae 100644 --- a/include/openobex/obex_const.h +++ b/include/openobex/obex_const.h @@ -167,6 +167,7 @@ typedef union { #define OBEX_FL_FILTERHINT (1 << 2) /* Filter devices based on hint bit */ #define OBEX_FL_FILTERIAS (1 << 3) /* Filter devices based on IAS entry */ #define OBEX_FL_CLOEXEC (1 << 4) /* Set CLOEXEC flag on file descriptors */ +#define OBEX_FL_NONBLOCK (1 << 5) /* Set the NONBLOCK flag on file descriptors */ /* For OBEX_ObjectAddHeader */ #define OBEX_FL_FIT_ONE_PACKET 0x01 /* This header must fit in one packet */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f404529..eacc1dd 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -53,6 +53,7 @@ set ( HEADERS fdobex.h customtrans.h cloexec.h + nonblock.h ) set ( openobex_PUBLIC_HEADER diff --git a/lib/Makefile.am b/lib/Makefile.am index ae92239..8da0860 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -19,7 +19,7 @@ libopenobex_la_SOURCES = \ irda_wrap.h \ usbutils.c usbutils.h \ usbobex.c usb1obex.c usbobex.h \ - visibility.h defines.h debug.h cloexec.h + visibility.h defines.h debug.h cloexec.h nonblock.h libopenobex_la_CPPFLAGS = -I$(top_srcdir)/include libopenobex_la_CFLAGS = -D_GNU_SOURCE @CFLAG_VISIBILITY@ @USB1_CFLAGS@ diff --git a/lib/btobex.c b/lib/btobex.c index 8df237a..652e3db 100644 --- a/lib/btobex.c +++ b/lib/btobex.c @@ -46,6 +46,7 @@ bdaddr_t bluez_compat_bdaddr_any = { BTH_ADDR_NULL }; #endif #include "cloexec.h" +#include "nonblock.h" static int btobex_init(obex_t *self) { @@ -233,6 +234,8 @@ static int btobex_accept(obex_t *self) return -1; trans->mtu = OBEX_DEFAULT_MTU; + if (self->init_flags & OBEX_FL_NONBLOCK) + socket_set_nonblocking(trans->fd); return 0; } @@ -268,7 +271,14 @@ static int btobex_connect_request(obex_t *self) ret = connect(trans->fd, (struct sockaddr*) &data->peer, sizeof(data->peer)); - if (ret < 0) { +#if defined(_WIN32) + if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + ret = 0; +#else + if (ret == -1 && errno == EINPROGRESS) + ret = 0; +#endif + if (ret == -1) { DEBUG(4, "connect(): error %d\n", errno); goto out_freesock; } diff --git a/lib/fdobex.c b/lib/fdobex.c index fa2d64a..70ae791 100644 --- a/lib/fdobex.c +++ b/lib/fdobex.c @@ -68,6 +68,9 @@ static int fdobex_write(obex_t *self, buf_t *msg) struct obex_transport *trans = &self->trans; int fd = trans->data.fd.writefd; size_t size = msg->data_size; + int status; + fd_set fdset; + struct timeval time = {trans->timeout, 0}; if (size == 0) return 0; @@ -76,35 +79,58 @@ static int fdobex_write(obex_t *self, buf_t *msg) size = trans->mtu; DEBUG(1, "sending %zu bytes\n", size); - if (trans->timeout >= 0) { - /* setup everything to check for blocking writes */ - fd_set fdset; - struct timeval time = {trans->timeout, 0}; - int status; - - FD_ZERO(&fdset); - FD_SET(fd, &fdset); + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + if (trans->timeout >= 0) status = select((int)fd+1, NULL, &fdset, NULL, &time); - if (status == 0) - return 0; - } + else + status = select((int)fd+1, NULL, &fdset, NULL, NULL); -#ifdef _WIN32 - return _write(fd, msg->data, size); + if (status == 0) + return 0; + +#if defined(_WIN32) + status = _write(fd, msg->data, size); #else - return write(fd, msg->data, size); + status = write(fd, msg->data, size); + /* The following are not really transport errors. */ + if (status == -1 && + (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) + status = 0; #endif + + return status; } static int fdobex_read(obex_t *self, void *buf, int buflen) { struct obex_transport *trans = &self->trans; + int status; + int fd = trans->fd; + fd_set fdset; + struct timeval time = {trans->timeout, 0}; + + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + if (trans->timeout >= 0) + status = select((int)fd+1, NULL, &fdset, NULL, &time); + else + status = select((int)fd+1, NULL, &fdset, NULL, NULL); + + if (status == 0) + return 0; #ifdef _WIN32 - return _read(trans->fd, buf, buflen); + status = _read(fd, buf, buflen); #else - return read(trans->fd, buf, buflen); + status = read(fd, buf, buflen); + /* The following are not really transport errors */ + if (status == -1 && + (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) + status = 0; #endif + + return status; } void fdobex_get_ops(struct obex_transport_ops* ops) diff --git a/lib/inobex.c b/lib/inobex.c index 4ae2b61..51302fd 100644 --- a/lib/inobex.c +++ b/lib/inobex.c @@ -40,9 +40,11 @@ #include "obex_main.h" #include "inobex.h" +#include <errno.h> #include <stdio.h> #include <string.h> #include "cloexec.h" +#include "nonblock.h" #define OBEX_PORT 650 @@ -292,6 +294,9 @@ static int inobex_accept(obex_t *self) /* Just use the default MTU for now */ trans->mtu = OBEX_DEFAULT_MTU; + if (self->init_flags & OBEX_FL_NONBLOCK) + socket_set_nonblocking(trans->fd); + return 1; } @@ -346,6 +351,13 @@ static int inobex_connect_request(obex_t *self) ret = connect(trans->fd, (struct sockaddr *) &data->peer, sizeof(data->peer)); +#if defined(_WIN32) + if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + ret = 0; +#else + if (ret == -1 && errno == EINPROGRESS) + ret = 0; +#endif if (ret == -1) { DEBUG(4, "Connect failed\n"); obex_delete_socket(self, trans->fd); diff --git a/lib/irobex.c b/lib/irobex.c index b0aeaa2..d2512d1 100644 --- a/lib/irobex.c +++ b/lib/irobex.c @@ -59,6 +59,7 @@ #include "obex_main.h" #include "irobex.h" #include "cloexec.h" +#include "nonblock.h" static int irobex_init (obex_t *self) { @@ -363,6 +364,8 @@ static int irobex_accept(obex_t *self) trans->mtu = irobex_get_mtu(self); DEBUG(3, "transport mtu=%d\n", trans->mtu); + if (self->init_flags & OBEX_FL_NONBLOCK) + socket_set_nonblocking(trans->fd); return 1; } @@ -519,20 +522,24 @@ static int irobex_connect_request(obex_t *self) ret = connect(trans->fd, (struct sockaddr*) &data->peer, sizeof(data->peer)); - if (ret < 0) { +#if defined(_WIN32) + if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + ret = 0; +#else + if (ret == -1 && errno == EINPROGRESS) + ret = 0; +#endif + if (ret == -1) { DEBUG(4, "ret=%d\n", ret); - goto out_freesock; + obex_delete_socket(self, trans->fd); + trans->fd = INVALID_SOCKET; + return ret; } trans->mtu = irobex_get_mtu(self); DEBUG(3, "transport mtu=%d\n", trans->mtu); return 1; - -out_freesock: - obex_delete_socket(self, trans->fd); - trans->fd = INVALID_SOCKET; - return ret; } /* diff --git a/lib/nonblock.h b/lib/nonblock.h new file mode 100644 index 0000000..fad6058 --- /dev/null +++ b/lib/nonblock.h @@ -0,0 +1,43 @@ +/** + \file nonblock.h + wrapper functions to enable/disable non-blocking + OpenOBEX library - Free implementation of the Object Exchange protocol. + + Copyright (c) 2010 Hendrik Sattler, All Rights Reserved. + + OpenOBEX 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 program 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 OpenOBEX. If not, see <http://www.gnu.org/>. + */ + +#if defined(_WIN32) +#include <winsock2.h> +#else +#include <fcntl.h> +#endif + +static __inline void socket_set_nonblocking(socket_t fd) +{ +#if defined(_WIN32) + unsigned long val = 1; + + (void)ioctlsocket(fd, FIONBIO, &val); + +#else + long status = fcntl(fd, F_GETFL); + + if (status == -1) + status = 0; + + (void)fcntl(fd, F_SETFL, status | O_NONBLOCK); +#endif +} diff --git a/lib/obex.c b/lib/obex.c index 277dbf2..eaa50b0 100644 --- a/lib/obex.c +++ b/lib/obex.c @@ -81,6 +81,7 @@ - #OBEX_FL_FILTERHINT : Filter target devices based on Obex hint bit - #OBEX_FL_FILTERIAS : Filter target devices based on IAS entry - #OBEX_FL_CLOEXEC : Open all sockets with SO_CLOEXEC set + - #OBEX_FL_NONBLOCK : Open all sockets non-blocking \return an OBEX handle or NULL on error. */ LIB_SYMBOL diff --git a/lib/obex_main.c b/lib/obex_main.c index b3a8a45..03819a2 100644 --- a/lib/obex_main.c +++ b/lib/obex_main.c @@ -56,6 +56,7 @@ int obex_debug; int obex_dump; #include "cloexec.h" +#include "nonblock.h" /* * Function obex_create_socket() @@ -80,6 +81,9 @@ socket_t obex_create_socket(obex_t *self, int domain) else fd = socket(domain, type, proto); + if (self->init_flags & OBEX_FL_NONBLOCK) + socket_set_nonblocking(fd); + return fd; } @@ -211,7 +215,11 @@ void obex_response_request(obex_t *self, uint8_t opcode) msg = buf_reuse(self->tx_msg); obex_data_request_prepare(self, msg, opcode | OBEX_FINAL); - obex_data_request(self, msg); + do { + int status = obex_data_request(self, msg); + if (status < 0) + break; + } while (!buf_empty(msg)); } /* @@ -249,11 +257,10 @@ int obex_data_request(obex_t *self, buf_t *msg) DEBUG(1, "len = %lu bytes\n", (unsigned long) msg->data_size); - do { - status = obex_transport_write(self, msg); - if (status > 0) - buf_remove_begin(msg, status); - } while (status >= 0 && !buf_empty(msg)); + status = obex_transport_write(self, msg); + if (status > 0) + buf_remove_begin(msg, status); + return status; } diff --git a/lib/obex_transport.c b/lib/obex_transport.c index 6207279..a41f6e6 100644 --- a/lib/obex_transport.c +++ b/lib/obex_transport.c @@ -366,6 +366,10 @@ int obex_transport_do_send (obex_t *self, buf_t *msg) struct obex_transport *trans = &self->trans; int fd = trans->fd; size_t size = msg->data_size; + int status; + fd_set fdset; + struct timeval *time_ptr = NULL; + struct timeval timeout = {trans->timeout, 0}; if (size == 0) return 0; @@ -374,21 +378,28 @@ int obex_transport_do_send (obex_t *self, buf_t *msg) size = trans->mtu; DEBUG(1, "sending %zu bytes\n", size); - if (trans->timeout >= 0) { - /* setup everything to check for blocking writes */ - fd_set fdset; - struct timeval time = {trans->timeout, 0}; - int status; - - FD_ZERO(&fdset); - FD_SET(fd, &fdset); - status = select((int)fd+1, NULL, &fdset, NULL, &time); - if (status == 0) - return 0; - } + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + if (trans->timeout >= 0) + time_ptr = &timeout; + status = select((int)fd+1, NULL, &fdset, NULL, time_ptr); + if (status == 0) + return 0; /* call send() if no error */ - return send(fd, msg->data, size, 0); + status = send(fd, msg->data, size, 0); + + /* The following are not really transport errors. */ +#if defined(_WIN32) + if (status == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + status = 0; +#else + if (status == -1 && + (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) + status = 0; +#endif + + return status; } /* @@ -408,7 +419,19 @@ int obex_transport_write(obex_t *self, buf_t *msg) int obex_transport_do_recv (obex_t *self, void *buf, int buflen) { struct obex_transport *trans = &self->trans; - return recv(trans->fd, buf, buflen, 0); + int status = recv(trans->fd, buf, buflen, 0); + + /* The following are not really transport errors. */ +#if defined(_WIN32) + if (status == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) + status = 0; +#else + if (status == -1 && + (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) + status = 0; +#endif + + return status; } /* -- 1.7.5.4 ------------------------------------------------------------------------------ Got Input? Slashdot Needs You. Take our quick survey online. Come on, we don't ask for help often. Plus, you'll get a chance to win $100 to spend on ThinkGeek. http://p.sf.net/sfu/slashdot-survey _______________________________________________ Openobex-users mailing list Openobex-users@lists.sourceforge.net http://lists.sourceforge.net/lists/listinfo/openobex-users