From: <svn...@op...> - 2009-09-24 17:09:00
|
Author: bellmich Date: Thu Sep 24 19:08:41 2009 New Revision: 1282 URL: http://libsyncml.opensync.org/changeset/1282 Log: added code to support the splitting of map commands If maps are really huge then they can exceed MaxMsgSize. The Map command has no MoreData element. So one Map command is simply splitted into several Map commands. Modified: trunk/libsyncml/sml_command.c trunk/libsyncml/sml_command.h trunk/libsyncml/sml_parse.c trunk/libsyncml/sml_session.c Modified: trunk/libsyncml/sml_command.c ============================================================================== --- trunk/libsyncml/sml_command.c Thu Sep 24 19:07:03 2009 (r1281) +++ trunk/libsyncml/sml_command.c Thu Sep 24 19:08:41 2009 (r1282) @@ -1042,6 +1042,66 @@ return g_list_nth_data(cmd->private.map.items, n); } +SmlCommand* +smlCommandCloneWithNumMappings (SmlCommand *cmd, + gsize n, + GError **error) +{ + CHECK_ERROR_REF + smlAssert(cmd); + smlAssert(cmd->type == SML_COMMAND_TYPE_MAP); + + SmlCommand *clone = NULL; + + /* create clone command */ + + clone = smlCommandNew(cmd->type, error); + if (!clone) + goto error; + clone->source = sml_location_clone(cmd->source); + clone->target = sml_location_clone(cmd->target); + + gsize i = 0; + for (; i < n; i++) + { + SmlMapItem *item = smlCommandGetNthMapping(cmd, i); + g_object_ref(item); + clone->private.map.items = g_list_append (clone->private.map.items, item); + } + + return clone; +error: + if (clone) + smlCommandUnref(clone); + return NULL; +} + +gboolean +smlCommandRemoveNumMappings (SmlCommand *cmd, + gsize n, + GError **error) +{ + CHECK_ERROR_REF + smlAssert(cmd); + smlAssert(cmd->type == SML_COMMAND_TYPE_MAP); + + while (n && cmd->private.map.items) + { + n--; + SmlMapItem *item = cmd->private.map.items->data; + if (!item) { + g_set_error(error, SML_ERROR, SML_ERROR_GENERIC, + "The item number %d of the map command is empty.", (n+1)); + goto error; + } + cmd->private.map.items = g_list_remove(cmd->private.map.items, item); + g_object_unref(item); + } + return TRUE; +error: + return FALSE; +} + gsize smlCommandGetNthItemSize (SmlCommand *cmd, gsize n, Modified: trunk/libsyncml/sml_command.h ============================================================================== --- trunk/libsyncml/sml_command.h Thu Sep 24 19:07:03 2009 (r1281) +++ trunk/libsyncml/sml_command.h Thu Sep 24 19:08:41 2009 (r1282) @@ -98,11 +98,13 @@ G_CONST_RETURN gchar *smlCommandTypeToString(SmlCommandType type, GError **error); -gsize smlCommandGetNumberOfChanges (SmlCommand *cmd); /* NumberOfChanges in sync command */ -gsize smlCommandGetNumChanges (SmlCommand *cmd); /* number of items in change command */ -SmlDataSyncChangeItem* smlCommandGetNthChange (SmlCommand *cmd, gsize n); -gsize smlCommandGetNumMappings (SmlCommand *cmd); /* number of items in change command */ -SmlMapItem* smlCommandGetNthMapping (SmlCommand *cmd, gsize n); +gsize smlCommandGetNumberOfChanges (SmlCommand *cmd); /* NumberOfChanges in sync command */ +gsize smlCommandGetNumChanges (SmlCommand *cmd); /* number of items in change command */ +SmlDataSyncChangeItem* smlCommandGetNthChange (SmlCommand *cmd, gsize n); +gsize smlCommandGetNumMappings (SmlCommand *cmd); /* number of items in change command */ +SmlMapItem* smlCommandGetNthMapping (SmlCommand *cmd, gsize n); +SmlCommand* smlCommandCloneWithNumMappings (SmlCommand *cmd, gsize n, GError **error); +gboolean smlCommandRemoveNumMappings (SmlCommand *cmd, gsize n, GError **error); SmlStatus* smlCommandResultsGetStatus (SmlCommand *cmd); void smlCommandTransferItems (SmlCommand *source, SmlCommand *target, gsize start); Modified: trunk/libsyncml/sml_parse.c ============================================================================== --- trunk/libsyncml/sml_parse.c Thu Sep 24 19:07:03 2009 (r1281) +++ trunk/libsyncml/sml_parse.c Thu Sep 24 19:08:41 2009 (r1282) @@ -594,16 +594,19 @@ smlAssert(cmd); smlAssert(assm->functions.start_cmd); smlAssert(assm->functions.rem_cmd); - smlAssert(smlCommandGetType(cmd) == SML_COMMAND_TYPE_ADD || smlCommandGetType(cmd) == SML_COMMAND_TYPE_REPLACE); + /* only one change per command is supported by libsyncml * It is possible to parse commands with more items * but it is not supported to send more items than one */ - smlAssert(smlCommandGetNumChanges(cmd) == 1); + if (smlCommandGetType(cmd) == SML_COMMAND_TYPE_ADD || + smlCommandGetType(cmd) == SML_COMMAND_TYPE_REPLACE) + smlAssert(smlCommandGetNumChanges(cmd) == 1); unsigned int parentID = 0; gsize limit = smlAssemblerGetRemoteMaxMsgSize(assm); if (!limit) { + /* The function call is useless in this case. */ *space = -1; smlTrace(TRACE_EXIT, "%s: No limit", __func__); return TRUE; @@ -640,7 +643,9 @@ * The data can be splitted into several chunks. * Please see SupportLargeObj and MoreData. */ - size -= strlen(sml_data_sync_change_item_get_data(smlCommandGetNthChange(cmd, 0))); + if (smlCommandGetType(cmd) == SML_COMMAND_TYPE_ADD || + smlCommandGetType(cmd) == SML_COMMAND_TYPE_REPLACE) + size -= strlen(sml_data_sync_change_item_get_data(smlCommandGetNthChange(cmd, 0))); if (limit <= size) *space = 0; Modified: trunk/libsyncml/sml_session.c ============================================================================== --- trunk/libsyncml/sml_session.c Thu Sep 24 19:07:03 2009 (r1281) +++ trunk/libsyncml/sml_session.c Thu Sep 24 19:08:41 2009 (r1282) @@ -398,8 +398,109 @@ smlTrace(TRACE_INTERNAL, "%s: Fragmented. Added %i already", __func__, session->frag_size); } } + + /* A Map command cannot be splitted like an Add or Change command. + * A map can be splitted into several maps if no Final is sent. + * Maps can be splitted for every SyncML protocol version. + * This is no large object handling. + */ + if (smlCommandGetType(cmd) == SML_COMMAND_TYPE_MAP && + smlAssemblerGetRemoteMaxMsgSize(session->assembler) > 0) + { + smlTrace(TRACE_INTERNAL, "%s: Checking if a map command needs to be splitted", __func__); + + /* Do we need fragmentation? */ + + gssize space = 0; + if (!smlAssemblerGetSpace(session->assembler, &space, parent, cmd, error)) + goto error; + + if (!session->frag_command && space <= 0) + { + /* Yes, fragmentation is required */ + session->frag_size = 0; + + session->frag_command = cmd; + smlCommandRef(cmd); + + session->frag_callback = callback; + session->frag_userdata = userdata; + } + + /* Fragmentation code */ + + if (session->frag_command) + { + /* We need to fragment */ + smlTrace(TRACE_INTERNAL, "%s: Space %i. Fragmenting.", __func__, space); + + /* loop until we found the maximum map */ + gsize count = 0; + do { + count++; + smlTrace(TRACE_INTERNAL, "%s: Try %d mappings ...", __func__, count); + cmd = smlCommandCloneWithNumMappings(session->frag_command, count, error); + if (!smlAssemblerGetSpace(session->assembler, &space, parent, cmd, error)) + goto error; + if (space <= 0) + { + /* to many mappings */ + count--; + } + smlCommandUnref(cmd); + cmd = NULL; + } while (space > 0 && smlCommandGetNumMappings(session->frag_command) > count); + smlTrace(TRACE_INTERNAL, "%s: Add %d mappings ...", __func__, count); + + /* if all mappings are to huge then wait for the next message */ + + if (count == 0 && + smlCommandGetPushedBack(session->frag_command)) + { + g_set_error(error, SML_ERROR, SML_ERROR_GENERIC, "Even a single mapping is too large for one message."); + goto error; + } + else if (count == 0) + { + smlTrace(TRACE_INTERNAL, "%s: Fragmentation is need but starts with the next message.", __func__); + smlCommandSetPushedBack(session->frag_command, TRUE); + fragmented = TRUE; + } + else if (count < smlCommandGetNumMappings(session->frag_command)) + { + /* partial command */ + smlTrace(TRACE_INTERNAL, "%s: This is a partial map.", __func__); + cmd = smlCommandCloneWithNumMappings(session->frag_command, count, error); + if (!cmd) + goto error; + if (!smlCommandRemoveNumMappings(session->frag_command, count, error)) + goto error; + callback = _smlSessionFragmentStatus; + userdata = NULL; + fragmented = TRUE; + } + else if (count == smlCommandGetNumMappings(session->frag_command)) + { + /* complete map command */ + smlTrace(TRACE_INTERNAL, "%s: This is the last chunk", __func__); + cmd = session->frag_command; + session->frag_command = NULL; + callback = session->frag_callback; + userdata = session->frag_userdata; + fragmented = FALSE; + } + else + { + /* bug */ + g_set_error(error, SML_ERROR, SML_ERROR_GENERIC, "The counting of mappings failed."); + goto error; + } + smlTrace(TRACE_INTERNAL, "%s: cmd %p", __func__, cmd); + } + } /* We now increment the session ID */ + smlTrace(TRACE_INTERNAL, "%s: cmd %p", __func__, cmd); session->lastCommandID++; smlCommandSetID(cmd, session->lastCommandID); smlTrace(TRACE_INTERNAL, "%s: last command id is %i", __func__, session->lastCommandID); @@ -541,7 +642,7 @@ SmlSession *session = userdata; GError *error = NULL; //SmlPendingStatus *pending = NULL; - smlTrace(TRACE_INTERNAL, "%s: session cmd type %i", __func__, sesscmd->type); + smlTrace(TRACE_INTERNAL, "%s: session cmd %p type %i", __func__, sesscmd->cmd, sesscmd->type); /* check if the header is ready */ if (!session->assmHasHeader) |