From: <svn...@op...> - 2009-03-18 17:33:16
|
Author: bellmich Date: Wed Mar 18 18:33:12 2009 New Revision: 996 URL: http://libsyncml.opensync.org/changeset/996 Log: fixed device information agent to be multi session safe The old code only works if the manager manages exactly one session. If there is more than one session then the agent must take care about the different remote device capabilities. Modified: trunk/libsyncml/objects/sml_devinf_obj.c trunk/libsyncml/objects/sml_devinf_obj.h trunk/libsyncml/objects/sml_devinf_obj_internals.h Modified: trunk/libsyncml/objects/sml_devinf_obj.c ============================================================================== --- trunk/libsyncml/objects/sml_devinf_obj.c Wed Mar 18 18:31:30 2009 (r995) +++ trunk/libsyncml/objects/sml_devinf_obj.c Wed Mar 18 18:33:12 2009 (r996) @@ -31,6 +31,71 @@ #include<sys/utsname.h> +/* Design notice + * + * There is only one SmlDevInfAgent per SmlManager + * because there is only one local device information. + * Therefore the agent must be able to manage one + * device information per session because every remote + * device can have different capabilities. + */ + +/* functions to manage SmlDevInfAgentSession */ + +static SmlDevInfAgentSession* _new_session( + SmlDevInfAgent *agent, + SmlSession *session, + SmlError **error) +{ + smlTrace(TRACE_ENTRY, "%s", __func__); + + CHECK_ERROR_REF + smlAssert(agent); + smlAssert(agent->sessions); + smlAssert(session); + + SmlDevInfAgentSession *as = smlTryMalloc0(sizeof(SmlDevInfAgentSession), error); + if (!as) + goto error; + + g_hash_table_insert(agent->sessions, session, as); + + smlTrace(TRACE_EXIT, "%s", __func__); + return as; +error: + smlSafeFree((gpointer *) &as); + smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error)); + return NULL; +} + +static SmlDevInfAgentSession* _get_session( + SmlDevInfAgent *agent, + SmlSession *session) +{ + smlTrace(TRACE_ENTRY, "%s", __func__); + + smlAssert(agent); + smlAssert(agent->sessions); + smlAssert(session); + + smlTrace(TRACE_EXIT, "%s", __func__); + return g_hash_table_lookup(agent->sessions, session); +} + +static void _free_session (gpointer data) +{ + smlTrace(TRACE_ENTRY, "%s(%p)", __func__, data); + + SmlDevInfAgentSession *as = data; + if (as->recvDevInf) + smlDevInfUnref(as->recvDevInf); + smlSafeFree((gpointer *) &as); + + smlTrace(TRACE_EXIT, "%s", __func__); +} + +/* functions to manage SmlDevInfAgent */ + static void _get_devinf_reply(SmlSession *session, SmlStatus *status, void *userdata) { smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata); @@ -40,9 +105,22 @@ if (smlStatusIsResult(status)) { SmlCommand *result = smlStatusGetResult(status); - agent->recvDevInf = smlDevInfFromResult(result, &error); - if (!agent->recvDevInf) + /* get cached session or add session to agent cache */ + + SmlDevInfAgentSession *as = _get_session(agent, session); + if (!as) { + as = _new_session(agent, session, &error); + if (!as) + goto error; + } + + /* cache device information */ + + as->recvDevInf = smlDevInfFromResult(result, &error); + if (!as->recvDevInf) goto error; + + /* send answer */ SmlStatus *reply = smlCommandNewReply(result, SML_NO_ERROR, &error); if (!reply) @@ -114,9 +192,18 @@ } } + /* get cached session or add session to agent cache */ + + SmlDevInfAgentSession *as = _get_session(agent, session); + if (!as) { + as = _new_session(agent, session, error); + if (!as) + goto error; + } + /* Sanity checks complete. Sending device information ... */ - if (!agent->devinfSent) { + if (!as->devinfSent) { if (get) { if (smlSessionGetVersion(session) == SML_VERSION_10) result = smlDevInfNewResult(get, agent->devinf, SML_DEVINF_VERSION_10, error); @@ -163,7 +250,7 @@ smlCommandUnref(cmd); } - agent->devinfSent = TRUE; + as->devinfSent = TRUE; } else { smlTrace(TRACE_INTERNAL, "%s: Already sent the devinf!", __func__); @@ -189,7 +276,9 @@ * with its own device information. Nevertheless * this is an error - but it can be ignored. */ - g_warning("libsyncml does not send local device information twice."); + smlTrace(TRACE_INTERNAL, + "%s: libsyncml does not send local device information twice.", + __func__); } } @@ -212,8 +301,15 @@ if (!smlItemGetData(cmd->private.access.item, &data, &size, &error)) goto error; - agent->recvDevInf = smlDevInfParse(data, size, &error); - if (!agent->recvDevInf) + SmlDevInfAgentSession *as = _get_session(agent, session); + if (!as) { + as = _new_session(agent, session, &error); + if (!as) + goto error; + } + + as->recvDevInf = smlDevInfParse(data, size, &error); + if (!as->recvDevInf) goto error; SmlStatus *reply = smlCommandNewReply(cmd, SML_NO_ERROR, &error); @@ -262,9 +358,12 @@ if (!agent) goto error; - agent->devinfSent = FALSE; agent->devinf = devinf; - agent->recvDevInf = NULL; + agent->sessions = g_hash_table_new_full(NULL, NULL, NULL, _free_session); + if (!agent->sessions) { + smlErrorSet(error, SML_ERROR_INTERNAL_NO_MEMORY, "Cannot create new hash table."); + goto error; + } if (!smlDevInfGetManufacturer(devinf)) smlDevInfSetManufacturer(devinf, "OpenSync"); @@ -287,6 +386,8 @@ return agent; error: + if (agent) + smlSafeFree((gpointer *) &agent); smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error)); return NULL; } @@ -299,29 +400,74 @@ if (agent->devinf) smlDevInfUnref(agent->devinf); - if (agent->recvDevInf) - smlDevInfUnref(agent->recvDevInf); + g_hash_table_destroy(agent->sessions); smlSafeFree((gpointer *)&agent); smlTrace(TRACE_EXIT, "%s", __func__); } -/* Set the devinf of the remote peer. */ +/* FIXME: DEPRECATED */ void smlDevInfAgentSetDevInf(SmlDevInfAgent *agent, SmlDevInf *devinf) { - smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, agent, devinf); + smlAssertMsg(NULL, "This function is a design bug."); +} + +/* FIXME: DEPRECATED */ +SmlDevInf *smlDevInfAgentGetDevInf(SmlDevInfAgent *agent) +{ + smlAssertMsg(NULL, "This function is a design bug."); + return NULL; +} + +/* Set the devinf of the remote peer. */ +SmlBool smlDevInfAgentSetSessionDevInf( + SmlDevInfAgent *agent, + SmlSession *session, + SmlDevInf *devinf, + SmlError **error) +{ + smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, agent, session, devinf, error); + + CHECK_ERROR_REF smlAssert(agent); + smlAssert(agent->sessions); + smlAssert(session); smlAssert(devinf); - agent->recvDevInf = devinf; - smlTrace(TRACE_EXIT, "%s", __func__); + + SmlDevInfAgentSession *as = _get_session(agent, session); + if (!as) { + as = _new_session(agent, session, error); + if (!as) + goto error; + } + + as->recvDevInf = devinf; + + smlTrace(TRACE_EXIT, "%s", __func__); + return TRUE; +error: + smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error)); + return FALSE; } /* Get the devinf that was sent in the session. Returns FALSE if no devinf was received yet. */ -SmlDevInf *smlDevInfAgentGetDevInf(SmlDevInfAgent *agent) +SmlDevInf *smlDevInfAgentGetSessionDevInf(SmlDevInfAgent *agent, SmlSession *session) { - smlTrace(TRACE_INTERNAL, "%s(%p)", __func__, agent); + smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, agent, session); + smlAssert(agent); - return agent->recvDevInf; + smlAssert(agent->sessions); + smlAssert(session); + + SmlDevInfAgentSession *as = _get_session(agent, session); + if (!as) + { + smlTrace(TRACE_EXIT, "%s - the session is not cached until now", __func__); + return NULL; + } + + smlTrace(TRACE_EXIT, "%s - %p", __func__, as->recvDevInf); + return as->recvDevInf; } /** Issues a put request on the session if needed */ @@ -349,28 +495,42 @@ CHECK_ERROR_REF smlAssert(agent); SmlCommand *get = NULL; + + SmlDevInfAgentSession *as = _get_session(agent, session); + if (!as) { + as = _new_session(agent, session, error); + if (!as) + goto error; + } - if (agent->recvDevInf) { + if (as->recvDevInf) { smlTrace(TRACE_EXIT, "%s: Already have the devinf", __func__); return TRUE; } - if (smlSessionGetVersion(session) == SML_VERSION_10) - get = smlDevInfNewGet(SML_DEVINF_VERSION_10, error); - else if (smlSessionGetVersion(session) == SML_VERSION_12) - get = smlDevInfNewGet(SML_DEVINF_VERSION_12, error); - else - get = smlDevInfNewGet(SML_DEVINF_VERSION_11, error); - - if (!get) - goto error; - - if (!smlSessionSendCommand(session, get, NULL, _get_devinf_reply, agent, error)) { + if (!as->devinfRequested) + { + if (smlSessionGetVersion(session) == SML_VERSION_10) + get = smlDevInfNewGet(SML_DEVINF_VERSION_10, error); + else if (smlSessionGetVersion(session) == SML_VERSION_12) + get = smlDevInfNewGet(SML_DEVINF_VERSION_12, error); + else + get = smlDevInfNewGet(SML_DEVINF_VERSION_11, error); + + if (!get) + goto error; + + if (!smlSessionSendCommand(session, get, NULL, _get_devinf_reply, agent, error)) { + smlCommandUnref(get); + goto error; + } + smlCommandUnref(get); - goto error; + + as->devinfRequested = TRUE; + } else { + smlTrace(TRACE_INTERNAL, "%s: Already requested the devinf!", __func__); } - - smlCommandUnref(get); smlTrace(TRACE_EXIT, "%s", __func__); return TRUE; Modified: trunk/libsyncml/objects/sml_devinf_obj.h ============================================================================== --- trunk/libsyncml/objects/sml_devinf_obj.h Wed Mar 18 18:31:30 2009 (r995) +++ trunk/libsyncml/objects/sml_devinf_obj.h Wed Mar 18 18:33:12 2009 (r996) @@ -37,12 +37,21 @@ SmlDevInfAgent *smlDevInfAgentNew(SmlDevInf *devinf, SmlError **error); void smlDevInfAgentFree(SmlDevInfAgent *agent); -void smlDevInfAgentSetDevInf(SmlDevInfAgent *agent, SmlDevInf *devinf); -SmlDevInf *smlDevInfAgentGetDevInf(SmlDevInfAgent *agent); SmlBool smlDevInfAgentRegisterSession(SmlDevInfAgent *agent, SmlManager *manager, SmlSession *session, SmlError **error); SmlBool smlDevInfAgentRegister(SmlDevInfAgent *agent, SmlManager *manager, SmlError **error); SmlBool smlDevInfAgentSendDevInf(SmlDevInfAgent *agent, SmlSession *session, SmlError **error); SmlBool smlDevInfAgentRequestDevInf(SmlDevInfAgent *agent, SmlSession *session, SmlError **error); +SmlBool smlDevInfAgentSetSessionDevInf(SmlDevInfAgent *agent, SmlSession *session, SmlDevInf *devinf, SmlError **error); +SmlDevInf *smlDevInfAgentGetSessionDevInf(SmlDevInfAgent *agent, SmlSession *session); + +/* These functions can only work in a single session environemnt. +/* This is a design bug. The functions are not removed immediately + * to avoid breaking applications which ignore the device information. + * These functions always fire an assertion. + */ +void smlDevInfAgentSetDevInf(SmlDevInfAgent *agent, SmlDevInf *devinf) LIBSYNCML_DEPRECATED; +SmlDevInf *smlDevInfAgentGetDevInf(SmlDevInfAgent *agent) LIBSYNCML_DEPRECATED; + #endif //_SML_DEVINF_OBJ_H_ /*@}*/ Modified: trunk/libsyncml/objects/sml_devinf_obj_internals.h ============================================================================== --- trunk/libsyncml/objects/sml_devinf_obj_internals.h Wed Mar 18 18:31:30 2009 (r995) +++ trunk/libsyncml/objects/sml_devinf_obj_internals.h Wed Mar 18 18:33:12 2009 (r996) @@ -29,11 +29,18 @@ #ifndef _SML_DEVINF_OBJ_INTERNALS_H_ #define _SML_DEVINF_OBJ_INTERNALS_H_ -struct SmlDevInfAgent { - SmlDevInf *devinf; +typedef struct SmlDevInfAgentSession { + /* states */ SmlBool devinfSent; - + SmlBool devinfRequested; + /* remote device information */ SmlDevInf *recvDevInf; + +} SmlDevInfAgentSession; + +struct SmlDevInfAgent { + SmlDevInf *devinf; + GHashTable *sessions; }; #endif //_SML_DEVINF_OBJ_INTERNALS_H_ |