Merge lp:~alfonsosanchezbeato/nuntium/fix-decode-crash into lp:nuntium/packaging

Proposed by Alfonso Sanchez-Beato
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 99
Merged at revision: 99
Proposed branch: lp:~alfonsosanchezbeato/nuntium/fix-decode-crash
Merge into: lp:nuntium/packaging
Diff against target: 430 lines (+156/-63)
6 files modified
cmd/nuntium/mediator.go (+31/-23)
debian/changelog (+9/-0)
mms/decoder.go (+72/-37)
mms/mms.go (+1/-0)
ofono/modem.go (+19/-3)
ofono/push_decode_test.go (+24/-0)
To merge this branch: bzr merge lp:~alfonsosanchezbeato/nuntium/fix-decode-crash
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
Review via email: mp+261847@code.launchpad.net

Commit message

* Fix LP: #1461107 and make PDU decoding more robust
* Fix LP: #1460012 (context opened twice on rx)
* Wait between retries when opening an IP context
* Set ofono's Preferred property when a context is known to work

Description of the change

* Fix LP: #1461107 and make PDU decoding more robust
* Fix LP: #1460012 (context opened twice on rx)
* Wait between retries when opening an IP context
* Set ofono's Preferred property when a context is known to work

To post a comment you must log in.
Revision history for this message
Manuel de la Peña (mandel) wrote :

Review was already done in github, looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cmd/nuntium/mediator.go'
--- cmd/nuntium/mediator.go 2014-11-06 05:20:46 +0000
+++ cmd/nuntium/mediator.go 2015-06-12 13:14:10 +0000
@@ -38,9 +38,7 @@
38 modem *ofono.Modem38 modem *ofono.Modem
39 telepathyService *telepathy.MMSService39 telepathyService *telepathy.MMSService
40 NewMNotificationInd chan *mms.MNotificationInd40 NewMNotificationInd chan *mms.MNotificationInd
41 NewMNotifyRespInd chan *mms.MNotifyRespInd
42 NewMSendReq chan *mms.MSendReq41 NewMSendReq chan *mms.MSendReq
43 NewMNotifyRespIndFile chan string
44 NewMSendReqFile chan struct{ filePath, uuid string }42 NewMSendReqFile chan struct{ filePath, uuid string }
45 outMessage chan *telepathy.OutgoingMessage43 outMessage chan *telepathy.OutgoingMessage
46 terminate chan bool44 terminate chan bool
@@ -58,8 +56,6 @@
58func NewMediator(modem *ofono.Modem) *Mediator {56func NewMediator(modem *ofono.Modem) *Mediator {
59 mediator := &Mediator{modem: modem}57 mediator := &Mediator{modem: modem}
60 mediator.NewMNotificationInd = make(chan *mms.MNotificationInd)58 mediator.NewMNotificationInd = make(chan *mms.MNotificationInd)
61 mediator.NewMNotifyRespInd = make(chan *mms.MNotifyRespInd)
62 mediator.NewMNotifyRespIndFile = make(chan string)
63 mediator.NewMSendReq = make(chan *mms.MSendReq)59 mediator.NewMSendReq = make(chan *mms.MSendReq)
64 mediator.NewMSendReqFile = make(chan struct{ filePath, uuid string })60 mediator.NewMSendReqFile = make(chan struct{ filePath, uuid string })
65 mediator.outMessage = make(chan *telepathy.OutgoingMessage)61 mediator.outMessage = make(chan *telepathy.OutgoingMessage)
@@ -87,10 +83,6 @@
87 } else {83 } else {
88 go mediator.getMRetrieveConf(mNotificationInd)84 go mediator.getMRetrieveConf(mNotificationInd)
89 }85 }
90 case mNotifyRespInd := <-mediator.NewMNotifyRespInd:
91 go mediator.handleMNotifyRespInd(mNotifyRespInd)
92 case mNotifyRespIndFilePath := <-mediator.NewMNotifyRespIndFile:
93 go mediator.sendMNotifyRespInd(mNotifyRespIndFilePath)
94 case msg := <-mediator.outMessage:86 case msg := <-mediator.outMessage:
95 go mediator.handleOutgoingMessage(msg)87 go mediator.handleOutgoingMessage(msg)
96 case mSendReq := <-mediator.NewMSendReq:88 case mSendReq := <-mediator.NewMSendReq:
@@ -126,8 +118,6 @@
126 close(mediator.NewMNotificationInd)118 close(mediator.NewMNotificationInd)
127 close(mediator.NewMRetrieveConf)119 close(mediator.NewMRetrieveConf)
128 close(mediator.NewMRetrieveConfFile)120 close(mediator.NewMRetrieveConfFile)
129 close(mediator.NewMNotifyRespInd)
130 close(mediator.NewMNotifyRespIndFile)
131 close(mediator.NewMSendReq)121 close(mediator.NewMSendReq)
132 close(mediator.NewMSendReqFile)122 close(mediator.NewMSendReqFile)
133 */123 */
@@ -163,12 +153,14 @@
163 defer mediator.contextLock.Unlock()153 defer mediator.contextLock.Unlock()
164154
165 var proxy ofono.ProxyInfo155 var proxy ofono.ProxyInfo
156 var mmsContext ofono.OfonoContext
166157
167 if mNotificationInd.IsLocal() {158 if mNotificationInd.IsLocal() {
168 log.Print("This is a local test, skipping context activation and proxy settings")159 log.Print("This is a local test, skipping context activation and proxy settings")
169 } else {160 } else {
161 var err error
170 preferredContext, _ := mediator.telepathyService.GetPreferredContext()162 preferredContext, _ := mediator.telepathyService.GetPreferredContext()
171 mmsContext, err := mediator.modem.ActivateMMSContext(preferredContext)163 mmsContext, err = mediator.modem.ActivateMMSContext(preferredContext)
172 if err != nil {164 if err != nil {
173 log.Print("Cannot activate ofono context: ", err)165 log.Print("Cannot activate ofono context: ", err)
174 return166 return
@@ -210,7 +202,12 @@
210 }202 }
211203
212 if !mNotificationInd.IsLocal() {204 if !mNotificationInd.IsLocal() {
213 mediator.NewMNotifyRespInd <- mNotifyRespInd205 // TODO deferred case
206 filePath := mediator.handleMNotifyRespInd(mNotifyRespInd)
207 if filePath == "" {
208 return
209 }
210 mediator.sendMNotifyRespInd(filePath, &mmsContext)
214 } else {211 } else {
215 log.Print("This is a local test, skipping m-notifyresp.ind")212 log.Print("This is a local test, skipping m-notifyresp.ind")
216 }213 }
@@ -246,36 +243,47 @@
246 return mRetrieveConf, nil243 return mRetrieveConf, nil
247}244}
248245
249func (mediator *Mediator) handleMNotifyRespInd(mNotifyRespInd *mms.MNotifyRespInd) {246func (mediator *Mediator) handleMNotifyRespInd(mNotifyRespInd *mms.MNotifyRespInd) string {
250 f, err := storage.CreateResponseFile(mNotifyRespInd.UUID)247 f, err := storage.CreateResponseFile(mNotifyRespInd.UUID)
251 if err != nil {248 if err != nil {
252 log.Print("Unable to create m-notifyresp.ind file for ", mNotifyRespInd.UUID)249 log.Print("Unable to create m-notifyresp.ind file for ", mNotifyRespInd.UUID)
253 return250 return ""
254 }251 }
255 enc := mms.NewEncoder(f)252 enc := mms.NewEncoder(f)
256 if err := enc.Encode(mNotifyRespInd); err != nil {253 if err := enc.Encode(mNotifyRespInd); err != nil {
257 log.Print("Unable to encode m-notifyresp.ind for ", mNotifyRespInd.UUID)254 log.Print("Unable to encode m-notifyresp.ind for ", mNotifyRespInd.UUID)
258 f.Close()255 f.Close()
259 return256 return ""
260 }257 }
261 filePath := f.Name()258 filePath := f.Name()
262 if err := f.Sync(); err != nil {259 if err := f.Sync(); err != nil {
263 log.Print("Error while syncing", f.Name(), ": ", err)260 log.Print("Error while syncing", f.Name(), ": ", err)
264 return261 return ""
265 }262 }
266 if err := f.Close(); err != nil {263 if err := f.Close(); err != nil {
267 log.Print("Error while closing", f.Name(), ": ", err)264 log.Print("Error while closing", f.Name(), ": ", err)
268 return265 return ""
269 }266 }
270 log.Printf("Created %s to handle m-notifyresp.ind for %s", filePath, mNotifyRespInd.UUID)267 log.Printf("Created %s to handle m-notifyresp.ind for %s", filePath, mNotifyRespInd.UUID)
271 mediator.NewMNotifyRespIndFile <- filePath268 return filePath
272}269}
273270
274func (mediator *Mediator) sendMNotifyRespInd(mNotifyRespIndFile string) {271func (mediator *Mediator) sendMNotifyRespInd(filePath string, mmsContext *ofono.OfonoContext) {
275 defer os.Remove(mNotifyRespIndFile)272 defer os.Remove(filePath)
276273
277 if _, err := mediator.uploadFile(mNotifyRespIndFile); err != nil {274 proxy, err := mmsContext.GetProxy()
278 log.Printf("Cannot upload m-notifyresp.ind encoded file %s to message center: %s", mNotifyRespIndFile, err)275 if err != nil {
276 log.Println("Cannot retrieve MMS proxy setting", err)
277 return
278 }
279 msc, err := mmsContext.GetMessageCenter()
280 if err != nil {
281 log.Println("Cannot retrieve MMSC setting", err)
282 return
283 }
284
285 if _, err := mms.Upload(filePath, msc, proxy.Host, int32(proxy.Port)); err != nil {
286 log.Printf("Cannot upload m-notifyresp.ind encoded file %s to message center: %s", filePath, err)
279 }287 }
280}288}
281289
282290
=== modified file 'debian/changelog'
--- debian/changelog 2015-06-04 12:49:28 +0000
+++ debian/changelog 2015-06-12 13:14:10 +0000
@@ -1,3 +1,12 @@
1nuntium (1.4+15.10.20150612-0ubuntu1) UNRELEASED; urgency=medium
2
3 * Fix LP: #1461107 and make PDU decoding more robust
4 * Fix LP: #1460012 (context opened twice on rx)
5 * Wait between retries when opening an IP context
6 * Set ofono's Preferred property when a context is known to work
7
8 -- Alfonso Sanchez-Beato (email Canonical) <alfonso.sanchez-beato@canonical.com> Fri, 12 Jun 2015 14:38:53 +0200
9
1nuntium (1.4+15.10.20150604-0ubuntu1) wily; urgency=medium10nuntium (1.4+15.10.20150604-0ubuntu1) wily; urgency=medium
211
3 [ Alfonso Sanchez-Beato (email Canonical) ]12 [ Alfonso Sanchez-Beato (email Canonical) ]
413
=== modified file 'mms/decoder.go'
--- mms/decoder.go 2015-06-01 06:38:12 +0000
+++ mms/decoder.go 2015-06-12 13:14:10 +0000
@@ -23,6 +23,7 @@
2323
24import (24import (
25 "fmt"25 "fmt"
26 "log"
26 "reflect"27 "reflect"
27)28)
2829
@@ -36,6 +37,24 @@
36 log string37 log string
37}38}
3839
40func (dec *MMSDecoder) setPduField(pdu *reflect.Value, name string, v interface{},
41 setter func(*reflect.Value, interface{})) {
42
43 if name != "" {
44 field := pdu.FieldByName(name)
45 if field.IsValid() {
46 setter(&field, v)
47 dec.log = dec.log + fmt.Sprintf("Setting %s to %s\n", name, v)
48 } else {
49 log.Println("Field", name, "not in decoding structure")
50 }
51 }
52}
53
54func setterString(field *reflect.Value, v interface{}) { field.SetString(v.(string)) }
55func setterUint64(field *reflect.Value, v interface{}) { field.SetUint(v.(uint64)) }
56func setterSlice(field *reflect.Value, v interface{}) { field.SetBytes(v.([]byte)) }
57
39func (dec *MMSDecoder) ReadEncodedString(reflectedPdu *reflect.Value, hdr string) (string, error) {58func (dec *MMSDecoder) ReadEncodedString(reflectedPdu *reflect.Value, hdr string) (string, error) {
40 var length uint6459 var length uint64
41 var err error60 var err error
@@ -192,10 +211,8 @@
192 return "", fmt.Errorf("reached end of data while trying to read string: %s", dec.Data[begin:])211 return "", fmt.Errorf("reached end of data while trying to read string: %s", dec.Data[begin:])
193 }212 }
194 v := string(dec.Data[begin:dec.Offset])213 v := string(dec.Data[begin:dec.Offset])
195 if hdr != "" {214 dec.setPduField(reflectedPdu, hdr, v, setterString)
196 reflectedPdu.FieldByName(hdr).SetString(v)215
197 dec.log = dec.log + fmt.Sprintf("Setting %s to %s\n", hdr, v)
198 }
199 return v, nil216 return v, nil
200}217}
201218
@@ -208,39 +225,24 @@
208 }225 }
209 */226 */
210 v := dec.Data[dec.Offset] & 0x7F227 v := dec.Data[dec.Offset] & 0x7F
211 if hdr != "" {228 dec.setPduField(reflectedPdu, hdr, uint64(v), setterUint64)
212 reflectedPdu.FieldByName(hdr).SetUint(uint64(v))229
213 dec.log = dec.log + fmt.Sprintf("Setting %s to %#x == %d\n", hdr, v, v)
214 }
215 return v, nil230 return v, nil
216}231}
217232
218func (dec *MMSDecoder) ReadByte(reflectedPdu *reflect.Value, hdr string) (byte, error) {233func (dec *MMSDecoder) ReadByte(reflectedPdu *reflect.Value, hdr string) (byte, error) {
219 dec.Offset++234 dec.Offset++
220 v := dec.Data[dec.Offset]235 v := dec.Data[dec.Offset]
221 if hdr != "" {236 dec.setPduField(reflectedPdu, hdr, uint64(v), setterUint64)
222 reflectedPdu.FieldByName(hdr).SetUint(uint64(v))
223 dec.log = dec.log + fmt.Sprintf("Setting %s to %#x == %d\n", hdr, v, v)
224 }
225 return v, nil
226}
227237
228func (dec *MMSDecoder) ReadBytes(reflectedPdu *reflect.Value, hdr string) ([]byte, error) {
229 dec.Offset++
230 v := []byte(dec.Data[dec.Offset:])
231 if hdr != "" {
232 reflectedPdu.FieldByName(hdr).SetBytes(v)
233 dec.log = dec.log + fmt.Sprintf("Setting %s to %#x == %d\n", hdr, v, v)
234 }
235 return v, nil238 return v, nil
236}239}
237240
238func (dec *MMSDecoder) ReadBoundedBytes(reflectedPdu *reflect.Value, hdr string, end int) ([]byte, error) {241func (dec *MMSDecoder) ReadBoundedBytes(reflectedPdu *reflect.Value, hdr string, end int) ([]byte, error) {
239 v := []byte(dec.Data[dec.Offset:end])242 v := []byte(dec.Data[dec.Offset:end])
240 if hdr != "" {243 dec.setPduField(reflectedPdu, hdr, v, setterSlice)
241 reflectedPdu.FieldByName(hdr).SetBytes(v)
242 }
243 dec.Offset = end - 1244 dec.Offset = end - 1
245
244 return v, nil246 return v, nil
245}247}
246248
@@ -257,10 +259,8 @@
257259
258 value = value << 7260 value = value << 7
259 value |= uint64(dec.Data[dec.Offset] & 0x7F)261 value |= uint64(dec.Data[dec.Offset] & 0x7F)
260 if hdr != "" {262 dec.setPduField(reflectedPdu, hdr, value, setterUint64)
261 reflectedPdu.FieldByName(hdr).SetUint(value)263
262 dec.log = dec.log + fmt.Sprintf("Setting %s to %d\n", hdr, value)
263 }
264 return value, nil264 return value, nil
265}265}
266266
@@ -276,10 +276,8 @@
276 default:276 default:
277 v, err = dec.ReadLongInteger(nil, "")277 v, err = dec.ReadLongInteger(nil, "")
278 }278 }
279 if hdr != "" {279 dec.setPduField(reflectedPdu, hdr, v, setterUint64)
280 reflectedPdu.FieldByName(hdr).SetUint(v)280
281 dec.log = dec.log + fmt.Sprintf("Setting %s to %d\n", hdr, v)
282 }
283 return v, err281 return v, err
284}282}
285283
@@ -297,10 +295,8 @@
297 v |= uint64(dec.Data[dec.Offset])295 v |= uint64(dec.Data[dec.Offset])
298 }296 }
299 dec.Offset--297 dec.Offset--
300 if hdr != "" {298 dec.setPduField(reflectedPdu, hdr, v, setterUint64)
301 reflectedPdu.FieldByName(hdr).SetUint(uint64(v))299
302 dec.log = dec.log + fmt.Sprintf("Setting %s to %d\n", hdr, v)
303 }
304 return v, nil300 return v, nil
305}301}
306302
@@ -327,6 +323,44 @@
327 }323 }
328}324}
329325
326func (dec *MMSDecoder) skipFieldValue() error {
327 switch {
328 case dec.Data[dec.Offset+1] < LENGTH_QUOTE:
329 l, err := dec.ReadByte(nil, "")
330 if err != nil {
331 return err
332 }
333 length := int(l)
334 if dec.Offset+length >= len(dec.Data) {
335 return fmt.Errorf("Bad field value length")
336 }
337 dec.Offset += length
338 return nil
339 case dec.Data[dec.Offset+1] == LENGTH_QUOTE:
340 dec.Offset++
341 // TODO These tests should be done in basic read functions
342 if dec.Offset+1 >= len(dec.Data) {
343 return fmt.Errorf("Bad uintvar")
344 }
345 l, err := dec.ReadUintVar(nil, "")
346 if err != nil {
347 return err
348 }
349 length := int(l)
350 if dec.Offset+length >= len(dec.Data) {
351 return fmt.Errorf("Bad field value length")
352 }
353 dec.Offset += length
354 return nil
355 case dec.Data[dec.Offset+1] <= TEXT_MAX:
356 _, err := dec.ReadString(nil, "")
357 return err
358 }
359 // case dec.Data[dec.Offset + 1] > TEXT_MAX
360 _, err := dec.ReadShortInteger(nil, "")
361 return err
362}
363
330func (dec *MMSDecoder) Decode(pdu MMSReader) (err error) {364func (dec *MMSDecoder) Decode(pdu MMSReader) (err error) {
331 reflectedPdu := reflect.ValueOf(pdu).Elem()365 reflectedPdu := reflect.ValueOf(pdu).Elem()
332 moreHdrToRead := true366 moreHdrToRead := true
@@ -444,7 +478,8 @@
444 case DATE:478 case DATE:
445 _, err = dec.ReadLongInteger(&reflectedPdu, "Date")479 _, err = dec.ReadLongInteger(&reflectedPdu, "Date")
446 default:480 default:
447 return fmt.Errorf("Unhandled byte: %#0x\tdec: %d\tdec.Offset: %d ... decoded so far: %s", param, param, dec.Offset)481 log.Printf("Skipping unrecognized header 0x%02x", param)
482 err = dec.skipFieldValue()
448 }483 }
449 if err != nil {484 if err != nil {
450 return err485 return err
451486
=== modified file 'mms/mms.go'
--- mms/mms.go 2015-01-15 15:45:48 +0000
+++ mms/mms.go 2015-06-12 13:14:10 +0000
@@ -224,6 +224,7 @@
224 UUID string224 UUID string
225 Type, Version, Class, DeliveryReport byte225 Type, Version, Class, DeliveryReport byte
226 ReplyCharging, ReplyChargingDeadline byte226 ReplyCharging, ReplyChargingDeadline byte
227 Priority byte
227 ReplyChargingId string228 ReplyChargingId string
228 TransactionId, ContentLocation string229 TransactionId, ContentLocation string
229 From, Subject string230 From, Subject string
230231
=== modified file 'ofono/modem.go'
--- ofono/modem.go 2015-05-20 12:32:08 +0000
+++ ofono/modem.go 2015-06-12 13:14:10 +0000
@@ -40,9 +40,10 @@
40)40)
4141
42const (42const (
43 ofonoAttachInProgressError = "org.ofono.AttachInProgress"43 ofonoAttachInProgressError = "org.ofono.Error.AttachInProgress"
44 ofonoInProgressError = "org.ofono.InProgress"44 ofonoInProgressError = "org.ofono.Error.InProgress"
45 ofonoNotAttachedError = "org.ofono.Error.NotAttached"45 ofonoNotAttachedError = "org.ofono.Error.NotAttached"
46 ofonoFailedError = "org.ofono.Error.Failed"
46)47)
4748
48type OfonoContext struct {49type OfonoContext struct {
@@ -269,8 +270,16 @@
269}270}
270271
271func activationErrorNeedsWait(err error) bool {272func activationErrorNeedsWait(err error) bool {
273 // ofonoFailedError might be due to network issues or to wrong APN configuration.
274 // Retrying would not make sense for the latter, but we cannot distinguish
275 // and any possible delay retrying might cause would happen only the first time
276 // (provided we end up finding the right APN on the list so we save it as
277 // preferred).
272 if dbusErr, ok := err.(*dbus.Error); ok {278 if dbusErr, ok := err.(*dbus.Error); ok {
273 return dbusErr.Name == ofonoInProgressError || dbusErr.Name == ofonoAttachInProgressError || dbusErr.Name == ofonoNotAttachedError279 return dbusErr.Name == ofonoInProgressError ||
280 dbusErr.Name == ofonoAttachInProgressError ||
281 dbusErr.Name == ofonoNotAttachedError ||
282 dbusErr.Name == ofonoFailedError
274 }283 }
275 return false284 return false
276}285}
@@ -286,6 +295,13 @@
286 time.Sleep(2 * time.Second)295 time.Sleep(2 * time.Second)
287 }296 }
288 } else {297 } else {
298 // If it works we set it as preferred in ofono, provided it is not
299 // a combined context.
300 // TODO get rid of nuntium's internal preferred setting
301 if !context.isPreferred() && context.isTypeMMS() {
302 obj.Call(CONNECTION_CONTEXT_INTERFACE, "SetProperty",
303 "Preferred", dbus.Variant{true})
304 }
289 return nil305 return nil
290 }306 }
291 }307 }
292308
=== modified file 'ofono/push_decode_test.go'
--- ofono/push_decode_test.go 2015-05-20 12:32:08 +0000
+++ ofono/push_decode_test.go 2015-06-12 13:14:10 +0000
@@ -199,3 +199,27 @@
199 c.Check(s.pdu.ContentType, Equals, mms.VND_WAP_MMS_MESSAGE)199 c.Check(s.pdu.ContentType, Equals, mms.VND_WAP_MMS_MESSAGE)
200 c.Check(len(s.pdu.Data), Equals, 183)200 c.Check(len(s.pdu.Data), Equals, 183)
201}201}
202
203func (s *PushDecodeTestSuite) TestDecodePlayPoland(c *C) {
204 inputBytes := []byte{
205 0x2e, 0x06, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
206 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x6d,
207 0x6d, 0x73, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x00, 0xaf,
208 0x84, 0x8c, 0x82, 0x98, 0x31, 0x34, 0x34, 0x32, 0x34, 0x30, 0x31, 0x33,
209 0x31, 0x38, 0x40, 0x6d, 0x6d, 0x73, 0x32, 0x00, 0x8d, 0x92, 0x89, 0x18,
210 0x80, 0x2b, 0x34, 0x38, 0x38, 0x38, 0x32, 0x30, 0x34, 0x30, 0x32, 0x32,
211 0x35, 0x2f, 0x54, 0x59, 0x50, 0x45, 0x3d, 0x50, 0x4c, 0x4d, 0x4e, 0x00,
212 0x8f, 0x81, 0x86, 0x80, 0x8a, 0x80, 0x8e, 0x03, 0x03, 0xad, 0x21, 0x88,
213 0x05, 0x81, 0x03, 0x03, 0xf4, 0x80, 0x83, 0x68, 0x74, 0x74, 0x70, 0x3a,
214 0x2f, 0x2f, 0x6d, 0x6d, 0x73, 0x63, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x2e,
215 0x70, 0x6c, 0x2f, 0x3f, 0x69, 0x64, 0x3d, 0x31, 0x34, 0x34, 0x32, 0x34,
216 0x30, 0x31, 0x33, 0x31, 0x38, 0x42, 0x00,
217 }
218 dec := NewDecoder(inputBytes)
219 c.Assert(dec.Decode(s.pdu), IsNil)
220
221 c.Check(int(s.pdu.HeaderLength), Equals, 34)
222 c.Check(int(s.pdu.ApplicationId), Equals, mms.PUSH_APPLICATION_ID)
223 c.Check(s.pdu.ContentType, Equals, mms.VND_WAP_MMS_MESSAGE)
224 c.Check(len(s.pdu.Data), Equals, 102)
225}

Subscribers

People subscribed via source and target branches