On Fri, 2009-12-18 at 12:23 +0100, Julien Kerihuel wrote:
> On Fri, 2009-12-18 at 16:53 +0530, Johnny Jacob wrote:
> > Hello,
> > 
> > Attached a patch for MonitorNotification (IMAPISupport) to make it
> > non-blocking. The API takes a callback to check if it should
> continue
> > processing notifications or return.
> > 
> > **Patch causes a API change**
> 
> Hi Johnny,
> 
> The new version of this patch sounds good for integration.
> Maybe one last remark (since you also mentioned it within your patch).
> 
> It may be useful to refactor the 3rd argument within a data structure
> which would take a pointer on a timeval structure and a pointer on the
> notification callback.
> 
> The main idea being to make the 2sec notification timeout customizable
> and the whole idea a bit more generic.
> 

Attached a updated patch. Also added a 'void *data' for the callback to
use.

Thanks.

-- 
[johnnyjacob.org] "May you share freely, never taking more than you give "
commit 4120c22f6908398de4e9a27e827f4c11e9281a20
Author: Johnny Jacob <[email protected]>
Date:   Mon Dec 21 16:03:40 2009 +0530

        Changed MonitorNotification to be non-blocking.
    
        Also checks whether to process notifications using a callback.

	Modified libmapi/IMAPISupport.c
diff --git a/libmapi/IMAPISupport.c b/libmapi/IMAPISupport.c
index 32d97fc..f6a9784 100644
--- a/libmapi/IMAPISupport.c
+++ b/libmapi/IMAPISupport.c
@@ -365,14 +365,15 @@ _PUBLIC_ enum MAPISTATUS DispatchNotifications(struct mapi_session *session)
 /**
    \details Wait for notifications and process them
 
-   This function indefinively waits for notifications on the UDP port
+   This function waits for notifications on the UDP port
    and generates the traffic needed to receive MAPI
    notifications. These MAPI notifications are next compared to the
    registered ones and the callback specified in Subscribe() called if
    it matches.
 
-   Note that the function will loop indefinitively until an error
-   occurs.
+   The function takes a callback in cb_data to check if it should 
+   continue to process notifications. Timeval in cb_data can be
+   used to control the behavior of select.
 
    \return MAPI_E_SUCCESS on success, otherwise MAPI error.  
 
@@ -388,37 +389,56 @@ _PUBLIC_ enum MAPISTATUS DispatchNotifications(struct mapi_session *session)
    non-threaded, only supports fnevNewmail and fnevCreatedObject
    notifications and will block your process until you send a signal.
 */
-_PUBLIC_ enum MAPISTATUS MonitorNotification(struct mapi_session *session,
-					     void *private_data)
+_PUBLIC_ enum MAPISTATUS MonitorNotification(struct mapi_session *session, void *private_data, 
+					     struct mapi_notify_continue_callback_data *cb_data)
 {
 	struct mapi_response	*mapi_response;
 	struct mapi_notify_ctx	*notify_ctx;
-	enum MAPISTATUS		retval;
 	NTSTATUS		status;
 	int			is_done;
 	int			err;
 	char			buf[512];
-	
+	fd_set                  read_fds;
+	int                     nread;
+        mapi_notify_continue_callback_t callback;
+	void                    *data;
+	struct timeval          *tv;
+	enum MAPISTATUS		retval;
+
 	/* sanity checks */
 	OPENCHANGE_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
 	OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
 	OPENCHANGE_RETVAL_IF(!session->notify_ctx, MAPI_E_INVALID_PARAMETER, NULL);
 
 	notify_ctx = session->notify_ctx;
+	callback = cb_data ? cb_data->callback : NULL;
+	data = cb_data ? cb_data->data : NULL;
+	tv = cb_data ? &cb_data->tv : NULL;
 
+	nread = 0;
 	is_done = 0;
 	while (!is_done) {
-		err = read(notify_ctx->fd, buf, sizeof(buf));
-		if (err > 0) {
-			status = emsmdb_transaction_null((struct emsmdb_context *)session->emsmdb->ctx, &mapi_response);
-			if (!NT_STATUS_IS_OK(status)) {
-				err = -1;
-			} else {
-				retval = ProcessNotification(notify_ctx, mapi_response);
-				OPENCHANGE_RETVAL_IF(retval, retval, NULL);
-			}
+	        FD_ZERO(&read_fds);
+		FD_SET(notify_ctx->fd, &read_fds);
+
+		err = select(notify_ctx->fd + 1, &read_fds, NULL, NULL, tv);
+		if (FD_ISSET(notify_ctx->fd, &read_fds)) {
+		        do {
+			         nread = read(notify_ctx->fd, buf, sizeof(buf));
+				 if (nread > 0) {
+			                status = emsmdb_transaction_null((struct emsmdb_context *)session->emsmdb->ctx,
+									 &mapi_response);
+					if (!NT_STATUS_IS_OK(status))
+					         err = -1;
+					else {
+					         retval = ProcessNotification(notify_ctx, mapi_response);
+						 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
+					}
+				 }
+			} while (nread > 0 && err != -1);
 		}
-		if (err <= 0) is_done = 1;
+		if ((callback != NULL && callback (data)) || err < 0)
+		        is_done = 1;
 	}
 
 	return MAPI_E_SUCCESS;
	Modified libmapi/emsmdb.c
diff --git a/libmapi/emsmdb.c b/libmapi/emsmdb.c
index 52f6ae4..a2cbcb2 100644
--- a/libmapi/emsmdb.c
+++ b/libmapi/emsmdb.c
@@ -18,6 +18,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <unistd.h>
+#include <fcntl.h>
 #include <libmapi/libmapi.h>
 #include <libmapi/proto_private.h>
 #include <gen_ndr/ndr_exchange.h>
@@ -412,6 +414,8 @@ retry:
 		return NULL;
 	}
 
+	fcntl(notify_ctx->fd, F_SETFL, O_NONBLOCK);
+
 	if (bind(notify_ctx->fd, notify_ctx->addr, sizeof(struct sockaddr)) == -1) {
 		shutdown(notify_ctx->fd, SHUT_RDWR);
 		close(notify_ctx->fd);
	Modified libmapi/mapi_notification.h
diff --git a/libmapi/mapi_notification.h b/libmapi/mapi_notification.h
index 4ffa63f..8dda76c 100644
--- a/libmapi/mapi_notification.h
+++ b/libmapi/mapi_notification.h
@@ -27,6 +27,8 @@
 */
 typedef int (*mapi_notify_callback_t)(uint16_t, void *, void *);
 
+typedef int (*mapi_notify_continue_callback_t)(void *);
+
 struct notifications {
 	uint32_t		ulConnection;		/* connection number */
 	uint32_t		NotificationFlags;	/* events mask associated */
@@ -45,6 +47,12 @@ struct mapi_notify_ctx {
 	struct notifications	*notifications;
 };
 
+struct mapi_notify_continue_callback_data {
+        mapi_notify_continue_callback_t callback; /* Consulted for continuing processing events*/
+        void *data;                               /* Data for callback */
+        struct timeval tv;                        /* Timeout for Select call */
+};
+
 #define	DFLT_NOTIF_PORT	2500
 
 #endif /*!__MAPI_NOTIFICATION_H__ */
	Modified torture/mapi_newmail.c
diff --git a/torture/mapi_newmail.c b/torture/mapi_newmail.c
index b2f892a..0310c40 100644
--- a/torture/mapi_newmail.c
+++ b/torture/mapi_newmail.c
@@ -109,7 +109,7 @@ bool torture_rpc_mapi_newmail(struct torture_context *torture)
 	if (retval != MAPI_E_SUCCESS) return false;
 
  	/* wait for notifications */
-	MonitorNotification(mapi_object_get_session(&obj_inbox),(void *)&obj_store);
+	MonitorNotification(mapi_object_get_session(&obj_inbox),(void *)&obj_store, NULL);
 
 	mapi_object_release(&obj_inbox);
 	mapi_object_release(&obj_store);
	Modified utils/openchangeclient.c
diff --git a/utils/openchangeclient.c b/utils/openchangeclient.c
index e6bb2fd..e47f4bb 100644
--- a/utils/openchangeclient.c
+++ b/utils/openchangeclient.c
@@ -2318,7 +2318,7 @@ static bool openchangeclient_notifications(TALLOC_CTX *mem_ctx, mapi_object_t *o
 	if (retval != MAPI_E_SUCCESS) return false;
 
 	/* wait for notifications: infinite loop */
-	retval = MonitorNotification(mapi_object_get_session(obj_store), (void *)obj_store);
+	retval = MonitorNotification(mapi_object_get_session(obj_store), (void *)obj_store, NULL);
 	if (retval != MAPI_E_SUCCESS) return false;
 
 	retval = Unsubscribe(mapi_object_get_session(obj_store), ulConnection);

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
devel mailing list
[email protected]
http://mailman.openchange.org/listinfo/devel

Reply via email to