@@ -330,3 +330,134 @@ impl DestinationSlot {
330
330
self . dest . get ( )
331
331
}
332
332
}
333
+
334
+ /// Helper structure for parsing the result of a multishot [`opcode::RecvMsg`](crate::opcode::RecvMsg).
335
+ #[ derive( Debug ) ]
336
+ pub struct RecvMsgOut < ' buf > {
337
+ buf : & ' buf [ u8 ] ,
338
+ header : sys:: io_uring_recvmsg_out ,
339
+ /// The fixed length of the name field, in bytes.
340
+ ///
341
+ /// If the incoming name data is larger than this, it gets truncated to this.
342
+ /// If it is smaller, it gets 0-padded to fill the whole field. In either case,
343
+ /// this fixed amount of space is reserved in the result buffer.
344
+ msghdr_name_len : usize ,
345
+ /// The fixed length of the control field, in bytes.
346
+ ///
347
+ /// This follows the same semantics as the field above, but for control data.
348
+ msghdr_control_len : usize ,
349
+ }
350
+
351
+ impl < ' buf > RecvMsgOut < ' buf > {
352
+ const DATA_START : usize = std:: mem:: size_of :: < sys:: io_uring_recvmsg_out > ( ) ;
353
+
354
+ /// Parse the data buffered upon completion of a `RecvMsg` multishot operation.
355
+ ///
356
+ /// `buffer` is the whole buffer previously provided to the ring, while `msghdr`
357
+ /// is the same content provided as input to the corresponding SQE
358
+ /// (only `msg_namelen` and `msg_controllen` fields are relevant).
359
+ pub fn parse ( buffer : & ' buf [ u8 ] , msghdr : & libc:: msghdr ) -> Result < Self , ( ) > {
360
+ if buffer. len ( ) < std:: mem:: size_of :: < sys:: io_uring_recvmsg_out > ( ) {
361
+ return Err ( ( ) ) ;
362
+ }
363
+ // SAFETY: buffer (minimum) length is checked here above.
364
+ let header: sys:: io_uring_recvmsg_out =
365
+ unsafe { std:: ptr:: read_unaligned ( buffer. as_ptr ( ) as _ ) } ;
366
+
367
+ let msghdr_name_len = msghdr. msg_namelen as _ ;
368
+ let msghdr_control_len = msghdr. msg_controllen as _ ;
369
+
370
+ // Check total length upfront, so that all the methods further
371
+ // below can safely use unchecked/saturating math.
372
+ let length_overflow = Some ( Self :: DATA_START )
373
+ . and_then ( |acc| acc. checked_add ( msghdr_name_len) )
374
+ . and_then ( |acc| acc. checked_add ( msghdr_control_len) )
375
+ . and_then ( |acc| acc. checked_add ( header. payloadlen as usize ) )
376
+ . map ( |total_len| total_len > buffer. len ( ) )
377
+ . unwrap_or ( true ) ;
378
+ if length_overflow {
379
+ return Err ( ( ) ) ;
380
+ }
381
+
382
+ Ok ( Self {
383
+ buf : buffer,
384
+ header,
385
+ msghdr_name_len,
386
+ msghdr_control_len,
387
+ } )
388
+ }
389
+
390
+ /// Return the length of the incoming `name` data.
391
+ ///
392
+ /// This may be larger than the size of the content returned by
393
+ /// `name_data()`, if the kernel could not fit all the incoming
394
+ /// data in the provided buffer size. In that case, name data in
395
+ /// the result buffer gets truncated.
396
+ pub fn incoming_name_len ( & self ) -> u32 {
397
+ self . header . namelen
398
+ }
399
+
400
+ /// Return whether the incoming name data was larger than the provided limit/buffer.
401
+ ///
402
+ /// When `true`, data returned by `name_data()` is truncated and
403
+ /// incomplete.
404
+ pub fn is_name_data_truncated ( & self ) -> bool {
405
+ self . header . namelen as usize > self . msghdr_name_len
406
+ }
407
+
408
+ /// Message control data, with the same semantics as `msghdr.msg_control`.
409
+ pub fn name_data ( & self ) -> & [ u8 ] {
410
+ let name_start = Self :: DATA_START ;
411
+ let name_size = usize:: min ( self . header . namelen as usize , self . msghdr_name_len ) ;
412
+ let name_end = name_start. saturating_add ( name_size) ;
413
+ & self . buf [ name_start..name_end]
414
+ }
415
+
416
+ /// Return the length of the incoming `control` data.
417
+ ///
418
+ /// This may be larger than the size of the content returned by
419
+ /// `control_data()`, if the kernel could not fit all the incoming
420
+ /// data in the provided buffer size. In that case, control data in
421
+ /// the result buffer gets truncated.
422
+ pub fn incoming_control_len ( & self ) -> u32 {
423
+ self . header . controllen
424
+ }
425
+
426
+ /// Return whether the incoming control data was larger than the provided limit/buffer.
427
+ ///
428
+ /// When `true`, data returned by `control_data()` is truncated and
429
+ /// incomplete.
430
+ pub fn is_control_data_truncated ( & self ) -> bool {
431
+ self . header . controllen as usize > self . msghdr_control_len
432
+ }
433
+
434
+ /// Message control data, with the same semantics as `msghdr.msg_control`.
435
+ pub fn control_data ( & self ) -> & [ u8 ] {
436
+ let control_start = Self :: DATA_START . saturating_add ( self . msghdr_name_len ) ;
437
+ let control_size = usize:: min ( self . header . controllen as usize , self . msghdr_control_len ) ;
438
+ let control_end = control_start. saturating_add ( control_size) ;
439
+ & self . buf [ control_start..control_end]
440
+ }
441
+
442
+ /// Return whether the incoming payload was larger than the provided limit/buffer.
443
+ ///
444
+ /// When `true`, data returned by `payload_data()` is truncated and
445
+ /// incomplete.
446
+ pub fn is_payload_truncated ( & self ) -> bool {
447
+ self . header . flags & ( libc:: MSG_TRUNC as u32 ) != 0
448
+ }
449
+
450
+ /// Message payload, as buffered by the kernel.
451
+ pub fn payload_data ( & self ) -> & [ u8 ] {
452
+ let payload_start = Self :: DATA_START
453
+ . saturating_add ( self . msghdr_name_len )
454
+ . saturating_add ( self . msghdr_control_len ) ;
455
+ let payload_end = payload_start. saturating_add ( self . header . payloadlen as usize ) ;
456
+ & self . buf [ payload_start..payload_end]
457
+ }
458
+
459
+ /// Message flags, with the same semantics as `msghdr.msg_flags`.
460
+ pub fn flags ( & self ) -> u32 {
461
+ self . header . flags
462
+ }
463
+ }
0 commit comments