Hi,
I have been working on an OBEX Object Push server implementation, which
allows the user to interactively allow or deny an incoming PUT request.
The server-side user should be provided with as much as possible
information about the incomming request, including information in
potential name and type headers in the first PUT packet.
The current openobex server implementation is done so that OBEX_EV_REQ
for the put is signaled to the user only after all packets have been
received. There is the OBEX_EV_REQHINT which is intended for performing
early denying of the request, but there are two problems with it:
1. It only works for single packet requests. The state machine in
obex_server.c will break if the response is set to something else than
SUCCESS or CONTINUE for a packet which is not the final one.
2. The headers for the first packet have not yet been parsed by openobex
when REQHINT is signaled, so there is no way for the user application to
access them.
While thinking about this problem several solutions came to my mind. The
first one was to move REQHINT further down in the obex_server function
after the headers have been parsed. This however will not work since one
of the purposes of REQHINT is to allow the user callback to set the
headeroffset (in case of some special extension of OBEX), i.e. REQHINT
*must* be called before the header parsing.
The second idea was to send REQHINT a second time after header parsing,
but this is also not good since it would break any application which
expects to get only one REQHINT for each request.
So, the solution I ended up with was to add a completely new event which
the user callback can use for checking the headers in the first packet
and then deny the request if needed. I didn't come up with a better name
than OBEX_EV_REQCHECK, so if you have a better idea, feel free to rename
it :-)
Another thing which the patch fixes is that it allows the server to deny
the request also between the first and last packets (which is something
that could be useful e.g. if the server runs out of diskspace or if the
user presses a "cancel" button) by setting the response in the
OBEX_EV_PROGRESS callback.
Johan
Index: include/obex_const.h
===================================================================
RCS file: /cvsroot/openobex/openobex/include/obex_const.h,v
retrieving revision 1.27
diff -u -r1.27 obex_const.h
--- include/obex_const.h 10 Feb 2006 01:18:04 -0000 1.27
+++ include/obex_const.h 28 Feb 2006 11:32:45 -0000
@@ -90,6 +90,7 @@
#define OBEX_EV_STREAMEMPTY 8 /* Need to feed more data when sending
a stream */
#define OBEX_EV_STREAMAVAIL 9 /* Time to pick up data when receiving
a stream */
#define OBEX_EV_UNEXPECTED 10 /* Unexpected data, not fatal */
+#define OBEX_EV_REQCHECK 11 /* First packet of an incoming request
has been parsed */
/* For OBEX_Init() */
#define OBEX_FL_KEEPSERVER 0x02 /* Keep the server alive */
Index: lib/obex_object.h
===================================================================
RCS file: /cvsroot/openobex/openobex/lib/obex_object.h,v
retrieving revision 1.13
diff -u -r1.13 obex_object.h
--- lib/obex_object.h 10 Feb 2006 01:12:55 -0000 1.13
+++ lib/obex_object.h 28 Feb 2006 11:32:45 -0000
@@ -72,6 +72,8 @@
int totallen; /* Size of all headers */
int abort; /* Request shall be aborted */
+ int checked; /* OBEX_EV_REQCHECK has been signaled */
+
int suspend; /* Temporarily stop transfering object
*/
int continue_received; /* CONTINUE received after sending last
command */
Index: lib/obex_server.c
===================================================================
RCS file: /cvsroot/openobex/openobex/lib/obex_server.c,v
retrieving revision 1.16
diff -u -r1.16 obex_server.c
--- lib/obex_server.c 3 Jan 2006 18:36:15 -0000 1.16
+++ lib/obex_server.c 28 Feb 2006 11:32:45 -0000
@@ -48,7 +48,7 @@
int obex_server(obex_t *self, GNetBuf *msg, int final)
{
obex_common_hdr_t *request;
- int cmd, ret;
+ int cmd, ret, deny = 0;
unsigned int len;
@@ -135,7 +135,29 @@
obex_deliver_event(self, OBEX_EV_PARSEERR,
self->object->opcode, 0, TRUE);
return -1;
}
-
+
+ if (!final) {
+ /* Let the user decide whether to accept or deny a
multi-packet
+ * request by examining all headers in the first packet
*/
+ if (!self->object->checked) {
+ obex_deliver_event(self, OBEX_EV_REQCHECK, cmd,
0, FALSE);
+ self->object->checked = 1;
+ }
+
+ /* Everything except 0x1X and 0x2X means that the user
callback
+ * denied the request. In the denied cases treat the
last
+ * packet as a final one but don't signal OBEX_EV_REQ */
+ switch ((self->object->opcode & ~OBEX_FINAL) & 0xF0) {
+ case 0x10:
+ case 0x20:
+ break;
+ default:
+ final = 1;
+ deny = 1;
+ break;
+ }
+ }
+
if(!final) {
/* As a server, the final bit is always SET- Jean II */
if(obex_object_send(self, self->object, FALSE, TRUE) <
0) {
@@ -156,7 +178,8 @@
/* Tell the app that a whole request has arrived. While
this event is delivered the app should append the
headers that should be in the response */
- obex_deliver_event(self, OBEX_EV_REQ, cmd, 0, FALSE);
+ if (!deny)
+ obex_deliver_event(self, OBEX_EV_REQ, cmd, 0,
FALSE);
self->state = MODE_SRV | STATE_SEND;
len = 3; /* Otherwise sanitycheck later will fail */
}