+ // We may need to write back a new address into the session using a versioned update loop.
+ if (client_addr) {
+ m_log.info("binding session (%s) to new client address (%s)", key, client_addr);
+ do {
+ // We have to reconstitute the session object ourselves.
+ DDF sessionobj;
+ DDFJanitor sessionjan(sessionobj);
+ istringstream src(record);
+ src >> sessionobj;
+ ver = sessionobj["version"].integer();
+ const char* saddr = nullptr;
+ if (strchr(client_addr, ':'))
+ saddr = sessionobj["client_addr"]["6"].string();
+ else
+ saddr = sessionobj["client_addr"]["4"].string();
+ if (saddr) {
+ // Something snuck in and bound the session to this address type, so it better match what we have.
+ if (!XMLString::equals(saddr, client_addr)) {
+ m_log.warn("client address mismatch, client (%s), session (%s)", client_addr, saddr);
+ throw RetryableProfileException(
+ "Your IP address ($1) does not match the address recorded at the time the session was established.",
+ params(1, client_addr)
+ );
+ }
+ break; // No need to update.
+ }
+ else {
+ // Bind it into the session.
+ if (strchr(client_addr, ':'))
+ sessionobj["client_addr"].addmember("6").string(client_addr);
+ else
+ sessionobj["client_addr"].addmember("4").string(client_addr);
+ }
+
+ // Tentatively increment the version.
+ sessionobj["version"].integer(sessionobj["version"].integer() + 1);
+
+ ostringstream str;
+ str << sessionobj;
+ record = str.str();
+
+ ver = m_storage->updateText(key, "session", record.c_str(), 0, ver);
+ if (!ver) {
+ // Fatal problem with update.
+ m_log.error("updateText failed on StorageService for session (%s)", key);
+ throw IOException("Unable to update stored session.");
+ }
+ if (ver < 0) {
+ // Out of sync.
+ m_log.warn("storage service indicates the record is out of sync, updating with a fresh copy...");
+ sessionobj["version"].integer(sessionobj["version"].integer() - 1);
+ ver = m_storage->readText(key, "session", &record);
+ if (!ver) {
+ m_log.error("readText failed on StorageService for session (%s)", key);
+ throw IOException("Unable to read back stored session.");
+ }
+ ver = -1;
+ }
+ } while (ver < 0); // negative indicates a sync issue so we retry
+ }
+