[CalendarServer-changes] [8361] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Dec 1 12:53:41 PST 2011
Revision: 8361
http://trac.macosforge.org/projects/calendarserver/changeset/8361
Author: sagen at apple.com
Date: 2011-12-01 12:53:39 -0800 (Thu, 01 Dec 2011)
Log Message:
-----------
Fix for handling APN feedback in cases where data received does not line up with expected message length.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/push/applepush.py
CalendarServer/trunk/calendarserver/push/test/test_applepush.py
CalendarServer/trunk/twistedcaldav/upgrade.py
Modified: CalendarServer/trunk/calendarserver/push/applepush.py
===================================================================
--- CalendarServer/trunk/calendarserver/push/applepush.py 2011-11-30 23:22:46 UTC (rev 8360)
+++ CalendarServer/trunk/calendarserver/push/applepush.py 2011-12-01 20:53:39 UTC (rev 8361)
@@ -26,7 +26,7 @@
from twext.web2.server import parsePOSTData
from twisted.application import service
from twisted.internet import reactor, protocol
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.protocol import ClientFactory, ReconnectingClientFactory
from twistedcaldav.extensions import DAVResource, DAVResourceWithoutChildrenMixin
from twistedcaldav.resource import ReadOnlyNoCopyResourceMixIn
@@ -212,7 +212,7 @@
# Clear the reference to us from the factory
self.factory.connection = None
- def dataReceived(self, data):
+ def dataReceived(self, data, fn=None):
self.log_debug("ProviderProtocol dataReceived %d bytes" % (len(data),))
command, status, identifier = struct.unpack("!BBI", data)
if command == self.COMMAND_ERROR:
@@ -369,20 +369,38 @@
Implements the Feedback portion of APNS
"""
+ MESSAGE_LENGTH = 38
+
def connectionMade(self):
self.log_debug("FeedbackProtocol connectionMade")
+ self.buffer = ""
- def dataReceived(self, data):
+ @inlineCallbacks
+ def dataReceived(self, data, fn=None):
+ """
+ Buffer and divide up received data into feedback messages which are
+ always 38 bytes long
+ """
+
+ if fn is None:
+ fn = self.processFeedback
+
self.log_debug("FeedbackProtocol dataReceived %d bytes" % (len(data),))
- try:
- timestamp, tokenLength, binaryToken = struct.unpack("!IH32s", data)
- except struct.error:
- self.log_warn("FeedbackProtocol received malformed data: %s" %
- (data.encode("hex"),))
- return succeed(None)
- token = binaryToken.encode("hex").lower()
- return self.processFeedback(timestamp, token)
+ self.buffer += data
+ while len(self.buffer) >= self.MESSAGE_LENGTH:
+ message = self.buffer[:self.MESSAGE_LENGTH]
+ self.buffer = self.buffer[self.MESSAGE_LENGTH:]
+
+ try:
+ timestamp, tokenLength, binaryToken = struct.unpack("!IH32s",
+ message)
+ token = binaryToken.encode("hex").lower()
+ yield fn(timestamp, token)
+ except Exception, e:
+ self.log_warn("FeedbackProtocol could not process message: %s (%s)" %
+ (message.encode("hex"), e))
+
@inlineCallbacks
def processFeedback(self, timestamp, token):
"""
Modified: CalendarServer/trunk/calendarserver/push/test/test_applepush.py
===================================================================
--- CalendarServer/trunk/calendarserver/push/test/test_applepush.py 2011-11-30 23:22:46 UTC (rev 8360)
+++ CalendarServer/trunk/calendarserver/push/test/test_applepush.py 2011-12-01 20:53:39 UTC (rev 8361)
@@ -18,7 +18,7 @@
ApplePushNotifierService, APNProviderProtocol
)
from twistedcaldav.test.util import TestCase
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import inlineCallbacks, succeed
from twisted.internet.task import Clock
import struct
from txdav.common.datastore.test.util import buildStore, CommonCommonTests
@@ -115,17 +115,40 @@
yield txn.commit()
self.assertEquals(len(subscriptions), 2)
- # Simulate malformed feedback
+
+ # Simulate feedback with a single token
connector = service.feedbacks["CalDAV"].testConnector
- yield connector.receiveData("malformed")
-
- # Simulate feedback
timestamp = 2000
binaryToken = token.decode("hex")
feedbackData = struct.pack("!IH32s", timestamp, len(binaryToken),
binaryToken)
yield connector.receiveData(feedbackData)
+ # Simulate feedback with multiple tokens, and dataReceived called
+ # with amounts of data not fitting message boundaries
+ history = []
+ def testFunction(timestamp, token):
+ history.append((timestamp, token))
+ return succeed(None)
+ timestamp = 2000
+ binaryToken = token.decode("hex")
+ feedbackData = struct.pack("!IH32sIH32s",
+ timestamp, len(binaryToken), binaryToken,
+ timestamp, len(binaryToken), binaryToken,
+ )
+ # Send 1st 10 bytes
+ yield connector.receiveData(feedbackData[:10], fn=testFunction)
+ # Send remaining bytes
+ yield connector.receiveData(feedbackData[10:], fn=testFunction)
+ self.assertEquals(history, [(timestamp, token), (timestamp, token)])
+ # Buffer is empty
+ self.assertEquals(len(connector.service.protocol.buffer), 0)
+
+ # Sending 39 bytes
+ yield connector.receiveData("!" * 39, fn=testFunction)
+ # Buffer has 1 byte remaining
+ self.assertEquals(len(connector.service.protocol.buffer), 1)
+
# The second subscription should now be gone
# Prior to feedback, there are 2 subscriptions
txn = self.store.newTransaction()
@@ -143,8 +166,8 @@
self.transport = StubTransport()
service.protocol.makeConnection(self.transport)
- def receiveData(self, data):
- return self.service.protocol.dataReceived(data)
+ def receiveData(self, data, fn=None):
+ return self.service.protocol.dataReceived(data, fn=fn)
class StubTransport(object):
Modified: CalendarServer/trunk/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/upgrade.py 2011-11-30 23:22:46 UTC (rev 8360)
+++ CalendarServer/trunk/twistedcaldav/upgrade.py 2011-12-01 20:53:39 UTC (rev 8361)
@@ -873,21 +873,22 @@
# Fetch the autoSchedule assignments from resourceinfo.sqlite and store
# the values in augments
augmentService = directory.augmentService
- augmentRecords = []
- dbPath = os.path.join(config.DataRoot, ResourceInfoDatabase.dbFilename)
- if os.path.exists(dbPath):
- resourceInfoDatabase = ResourceInfoDatabase(config.DataRoot)
- results = resourceInfoDatabase._db_execute(
- "select GUID, AUTOSCHEDULE from RESOURCEINFO"
- )
- for guid, autoSchedule in results:
- record = directory.recordWithGUID(guid)
- if record is not None:
- augmentRecord = (yield augmentService.getAugmentRecord(guid, record.recordType))
- augmentRecord.autoSchedule = autoSchedule
- augmentRecords.append(augmentRecord)
+ if augmentService:
+ augmentRecords = []
+ dbPath = os.path.join(config.DataRoot, ResourceInfoDatabase.dbFilename)
+ if os.path.exists(dbPath):
+ resourceInfoDatabase = ResourceInfoDatabase(config.DataRoot)
+ results = resourceInfoDatabase._db_execute(
+ "select GUID, AUTOSCHEDULE from RESOURCEINFO"
+ )
+ for guid, autoSchedule in results:
+ record = directory.recordWithGUID(guid)
+ if record is not None:
+ augmentRecord = (yield augmentService.getAugmentRecord(guid, record.recordType))
+ augmentRecord.autoSchedule = autoSchedule
+ augmentRecords.append(augmentRecord)
- yield augmentService.addAugmentRecords(augmentRecords)
+ yield augmentService.addAugmentRecords(augmentRecords)
class UpgradeFileSystemFormatService(Service, object):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20111201/50b68197/attachment.html>
More information about the calendarserver-changes
mailing list