asyncio/ip/
options.rs

1use prelude::{SocketOption, GetSocketOption, SetSocketOption};
2use ffi::*;
3use ip::{IpProtocol, IpAddrV4, IpAddrV6, IpAddr, Tcp};
4
5use std::mem;
6
7fn in_addr_of(addr: IpAddrV4) -> in_addr {
8    unsafe { mem::transmute(addr) }
9}
10
11fn in6_addr_of(addr: IpAddrV6) -> in6_addr {
12    unsafe { mem::transmute_copy(addr.as_bytes()) }
13}
14
15/// Socket option for get/set an IPv6 socket supports IPv6 communication only.
16///
17/// Implements the IPPROTO_IPV6/IP_V6ONLY socket option.
18///
19/// # Examples
20/// Setting the option:
21///
22/// ```
23/// use asyncio::*;
24/// use asyncio::ip::*;
25///
26/// let ctx = &IoContext::new().unwrap();
27/// let soc = TcpListener::new(ctx, Tcp::v6()).unwrap();
28///
29/// soc.set_option(V6Only::new(true)).unwrap();
30/// ```
31///
32/// Getting the option:
33///
34/// ```
35/// use asyncio::*;
36/// use asyncio::ip::*;
37///
38/// let ctx = &IoContext::new().unwrap();
39/// let soc = TcpListener::new(ctx, Tcp::v6()).unwrap();
40///
41/// let opt: V6Only = soc.get_option().unwrap();
42/// let is_set: bool = opt.get();
43/// ```
44#[derive(Default, Clone)]
45pub struct V6Only(i32);
46
47impl V6Only {
48    pub fn new(on: bool) -> V6Only {
49        V6Only(on as i32)
50    }
51
52    pub fn get(&self) -> bool {
53        self.0 != 0
54    }
55
56    pub fn set(&mut self, on: bool) {
57        self.0 = on as i32
58    }
59}
60
61impl<P: IpProtocol> SocketOption<P> for V6Only {
62    type Data = i32;
63
64    fn level(&self, _: &P) -> i32 {
65        IPPROTO_IPV6.i32()
66    }
67
68    fn name(&self, _: &P) -> i32 {
69        IPV6_V6ONLY
70    }
71
72}
73
74impl<P: IpProtocol> GetSocketOption<P> for V6Only {
75    fn data_mut(&mut self) -> &mut Self::Data {
76        &mut self.0
77    }
78}
79
80impl<P: IpProtocol> SetSocketOption<P> for V6Only {
81    fn data(&self) -> &Self::Data {
82        &self.0
83    }
84}
85
86/// Socket option for disabling the Nagle algorithm.
87///
88/// Implements the IPPROTO_TCP/TCP_NODELAY socket option.
89///
90/// # Examples
91/// Setting the option:
92///
93/// ```
94/// use asyncio::*;
95/// use asyncio::ip::*;
96///
97/// let ctx = &IoContext::new().unwrap();
98/// let soc = TcpSocket::new(ctx, Tcp::v4()).unwrap();
99///
100/// soc.set_option(NoDelay::new(true)).unwrap();
101/// ```
102///
103/// Getting the option:
104///
105/// ```
106/// use asyncio::*;
107/// use asyncio::ip::*;
108///
109/// let ctx = &IoContext::new().unwrap();
110/// let soc = TcpSocket::new(ctx, Tcp::v4()).unwrap();
111///
112/// let opt: NoDelay = soc.get_option().unwrap();
113/// let is_set: bool = opt.get();
114/// ```
115#[derive(Default, Clone)]
116pub struct NoDelay(i32);
117
118impl NoDelay {
119    pub fn new(on: bool) -> NoDelay {
120        NoDelay(on as i32)
121    }
122
123    pub fn get(&self) -> bool {
124        self.0 != 0
125    }
126
127    pub fn set(&mut self, on: bool) {
128        self.0 = on as i32
129    }
130}
131
132impl SocketOption<Tcp> for NoDelay {
133    type Data = i32;
134
135    fn level(&self, _: &Tcp) -> i32 {
136        IPPROTO_TCP.i32()
137    }
138
139    fn name(&self, _: &Tcp) -> i32 {
140        TCP_NODELAY
141    }
142}
143
144impl GetSocketOption<Tcp> for NoDelay {
145    fn data_mut(&mut self) -> &mut Self::Data {
146        &mut self.0
147    }
148}
149
150impl SetSocketOption<Tcp> for NoDelay {
151    fn data(&self) -> &Self::Data {
152        &self.0
153    }
154}
155
156/// Socket option for time-to-live associated with outgoing unicast packets.
157///
158/// Implements the IPPROTO_IP/IP_UNICAST_TTL or IPPROTO_IPV6/IPV6_UNICAST_HOPS socket option.
159///
160/// # Examples
161/// Setting the option:
162///
163/// ```
164/// use asyncio::*;
165/// use asyncio::ip::*;
166///
167/// let ctx = &IoContext::new().unwrap();
168/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
169///
170/// soc.set_option(UnicastHops::new(4)).unwrap();
171/// ```
172///
173/// Getting the option:
174///
175/// ```
176/// use asyncio::*;
177/// use asyncio::ip::*;
178///
179/// let ctx = &IoContext::new().unwrap();
180/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
181///
182/// let opt: UnicastHops = soc.get_option().unwrap();
183/// let hops: u8 = opt.get();
184/// ```
185#[derive(Default, Clone)]
186pub struct UnicastHops(i32);
187
188impl UnicastHops {
189    pub fn new(ttl: u8) -> UnicastHops {
190        UnicastHops(ttl as i32)
191    }
192
193    pub fn get(&self) -> u8 {
194        self.0 as u8
195    }
196
197    pub fn set(&mut self, ttl: u8) {
198        self.0 = ttl as i32
199    }
200}
201
202impl<P: IpProtocol> SocketOption<P> for UnicastHops {
203    type Data = i32;
204
205    fn level(&self, pro: &P) -> i32 {
206        if pro.is_v4() {
207            IPPROTO_IP.i32()
208        } else if pro.is_v6() {
209            IPPROTO_IPV6.i32()
210        } else {
211            unreachable!("Invalid ip version")
212        }
213    }
214
215    fn name(&self, pro: &P) -> i32 {
216        if pro.is_v4() {
217            IP_TTL
218        } else if pro.is_v6() {
219            IPV6_UNICAST_HOPS
220        } else {
221            unreachable!("Invalid ip version")
222        }
223    }
224}
225
226impl<P: IpProtocol> GetSocketOption<P> for UnicastHops {
227    fn data_mut(&mut self) -> &mut Self::Data {
228        &mut self.0
229    }
230}
231
232impl<P: IpProtocol> SetSocketOption<P> for UnicastHops {
233    fn data(&self) -> &Self::Data {
234        &self.0
235    }
236}
237
238/// Socket option determining whether outgoing multicast packets will be received on the same socket if it is a member of the multicast group.
239///
240/// Implements the IPPROTO_IP/IP_MULTICAST_LOOP or IPPROTO_IPV6/IPV6_MULTICAST_LOOP socket option.
241///
242/// # Examples
243/// Setting the option:
244///
245/// ```
246/// use asyncio::*;
247/// use asyncio::ip::*;
248///
249/// let ctx = &IoContext::new().unwrap();
250/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
251///
252/// soc.set_option(MulticastEnableLoopback::new(true)).unwrap();
253/// ```
254///
255/// Getting the option:
256///
257/// ```
258/// use asyncio::*;
259/// use asyncio::ip::*;
260///
261/// let ctx = &IoContext::new().unwrap();
262/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
263///
264/// let opt: MulticastEnableLoopback = soc.get_option().unwrap();
265/// let is_set: bool = opt.get();
266/// ```
267#[derive(Default, Clone)]
268pub struct MulticastEnableLoopback(i32);
269
270impl MulticastEnableLoopback {
271    pub fn new(on: bool) -> MulticastEnableLoopback {
272        MulticastEnableLoopback(on as i32)
273    }
274
275    pub fn get(&self) -> bool {
276        self.0 != 0
277    }
278
279    pub fn set(&mut self, on: bool) {
280        self.0 = on as i32
281    }
282}
283
284impl<P: IpProtocol> SocketOption<P> for MulticastEnableLoopback {
285    type Data = i32;
286
287    fn level(&self, pro: &P) -> i32 {
288        if pro.is_v4() {
289            IPPROTO_IP.i32()
290        } else if pro.is_v6() {
291            IPPROTO_IPV6.i32()
292        } else {
293            unreachable!("Invalid ip version")
294        }
295    }
296
297    fn name(&self, pro: &P) -> i32 {
298        if pro.is_v4() {
299            IP_MULTICAST_LOOP
300        } else if pro.is_v6() {
301            IPV6_MULTICAST_LOOP
302        } else {
303            unreachable!("Invalid ip version")
304        }
305    }
306}
307
308impl<P: IpProtocol> GetSocketOption<P> for MulticastEnableLoopback {
309    fn data_mut(&mut self) -> &mut Self::Data {
310        &mut self.0
311    }
312}
313
314impl<P: IpProtocol> SetSocketOption<P> for MulticastEnableLoopback {
315    fn data(&self) -> &Self::Data {
316        &self.0
317    }
318}
319
320/// Socket option for time-to-live associated with outgoing multicast packets.
321///
322/// Implements the IPPROTO_IP/IP_MULTICAST_TTL or IPPROTO_IPV6/IPV6_MULTICAST_HOPS socket option.
323///
324/// # Examples
325/// Setting the option:
326///
327/// ```
328/// use asyncio::*;
329/// use asyncio::ip::*;
330///
331/// let ctx = &IoContext::new().unwrap();
332/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
333///
334/// soc.set_option(MulticastHops::new(4)).unwrap();
335/// ```
336///
337/// Getting the option:
338///
339/// ```
340/// use asyncio::*;
341/// use asyncio::ip::*;
342///
343/// let ctx = &IoContext::new().unwrap();
344/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
345///
346/// let opt: MulticastHops = soc.get_option().unwrap();
347/// let hops: u8 = opt.get();
348/// ```
349#[derive(Default, Clone)]
350pub struct MulticastHops(i32);
351
352impl MulticastHops {
353    pub fn new(ttl: u8) -> MulticastHops {
354        MulticastHops(ttl as i32)
355    }
356
357    pub fn get(&self) -> u8 {
358        self.0 as u8
359    }
360
361    pub fn set(&mut self, ttl: u8) {
362        self.0 = ttl as i32
363    }
364}
365
366impl<P: IpProtocol> SocketOption<P> for MulticastHops {
367    type Data = i32;
368
369    fn level(&self, pro: &P) -> i32 {
370        if pro.is_v4() {
371            IPPROTO_IP.i32()
372        } else if pro.is_v6() {
373            IPPROTO_IPV6.i32()
374        } else {
375            unreachable!("Invalid ip version")
376        }
377    }
378
379    fn name(&self, pro: &P) -> i32 {
380        if pro.is_v4() {
381            IP_MULTICAST_TTL
382        } else if pro.is_v6() {
383            IPV6_MULTICAST_HOPS
384        } else {
385            unreachable!("Invalid ip version")
386        }
387    }
388}
389
390impl<P: IpProtocol> GetSocketOption<P> for MulticastHops {
391    fn data_mut(&mut self) -> &mut Self::Data {
392        &mut self.0
393    }
394}
395
396impl<P: IpProtocol> SetSocketOption<P> for MulticastHops {
397    fn data(&self) -> &Self::Data {
398        &self.0
399    }
400}
401
402#[derive(Clone)]
403enum Mreq {
404    V4(ip_mreq),
405    V6(ipv6_mreq),
406}
407
408/// Socket option to join a multicast group on a specified interface.
409///
410/// Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP or IPPROTO_IPV6/IPV6_JOIN_GROUP socket option.
411///
412/// # Examples
413/// Setting the option:
414///
415/// ```
416/// use asyncio::*;
417/// use asyncio::ip::*;
418///
419/// let ctx = &IoContext::new().unwrap();
420/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
421///
422/// soc.set_option(MulticastJoinGroup::new(IpAddr::V4(IpAddrV4::new(225,0,0,1)))).unwrap();
423/// ```
424#[derive(Clone)]
425pub struct MulticastJoinGroup(Mreq);
426
427impl MulticastJoinGroup {
428    pub fn new(multicast: IpAddr) -> MulticastJoinGroup {
429        match multicast {
430            IpAddr::V4(multicast) => Self::from_v4(multicast, IpAddrV4::any()),
431            IpAddr::V6(multicast) => {
432                let scope_id = multicast.get_scope_id();
433                Self::from_v6(multicast, scope_id)
434            }
435        }
436    }
437
438    pub fn from_v4(multicast: IpAddrV4, interface: IpAddrV4) -> MulticastJoinGroup {
439        MulticastJoinGroup(Mreq::V4(ip_mreq {
440            imr_multiaddr: in_addr_of(multicast),
441            imr_interface: in_addr_of(interface),
442        }))
443    }
444
445    pub fn from_v6(multicast: IpAddrV6, scope_id: u32) -> MulticastJoinGroup {
446        MulticastJoinGroup(Mreq::V6(ipv6_mreq {
447            ipv6mr_multiaddr: in6_addr_of(multicast),
448            ipv6mr_interface: scope_id,
449        }))
450    }
451}
452
453impl<P: IpProtocol> SocketOption<P> for MulticastJoinGroup {
454    type Data = ();
455
456    fn level(&self, pro: &P) -> i32 {
457        if pro.is_v4() {
458            IPPROTO_IP.i32()
459        } else if pro.is_v6() {
460            IPPROTO_IPV6.i32()
461        } else {
462            unreachable!("Invalid ip version")
463        }
464    }
465
466    fn name(&self, pro: &P) -> i32 {
467        if pro.is_v4() {
468            IP_ADD_MEMBERSHIP
469        } else if pro.is_v6() {
470            IPV6_JOIN_GROUP
471        } else {
472            unreachable!("Invalid ip version")
473        }
474    }
475}
476
477impl<P: IpProtocol> SetSocketOption<P> for MulticastJoinGroup {
478    fn data(&self) -> &Self::Data {
479        match &self.0 {
480            &Mreq::V4(ref mreq) => unsafe { mem::transmute(mreq) },
481            &Mreq::V6(ref mreq) => unsafe { mem::transmute(mreq) },
482        }
483    }
484
485    fn size(&self) -> usize {
486        match &self.0 {
487            &Mreq::V4(ref mreq) => mem::size_of_val(mreq),
488            &Mreq::V6(ref mreq) => mem::size_of_val(mreq),
489        }
490    }
491}
492
493/// Socket option to leave a multicast group on a specified interface.
494///
495/// Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP or IPPROTO_IPV6/IPV6_LEAVE_GROUP socket option.
496///
497/// # Examples
498/// Setting the option:
499///
500/// ```
501/// use asyncio::*;
502/// use asyncio::ip::*;
503///
504/// let ctx = &IoContext::new().unwrap();
505/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
506///
507/// soc.set_option(MulticastLeaveGroup::new(IpAddr::V4(IpAddrV4::new(225,0,0,1))));
508/// ```
509#[derive(Clone)]
510pub struct MulticastLeaveGroup(Mreq);
511
512impl MulticastLeaveGroup {
513    pub fn new(multicast: IpAddr) -> MulticastLeaveGroup {
514        match multicast {
515            IpAddr::V4(multicast) => Self::from_v4(multicast, IpAddrV4::any()),
516            IpAddr::V6(multicast) => {
517                let scope_id = multicast.get_scope_id();
518                Self::from_v6(multicast, scope_id)
519            }
520        }
521    }
522
523    pub fn from_v4(multicast: IpAddrV4, interface: IpAddrV4) -> MulticastLeaveGroup {
524        MulticastLeaveGroup(Mreq::V4(ip_mreq {
525            imr_multiaddr: in_addr_of(multicast),
526            imr_interface: in_addr_of(interface),
527        }))
528    }
529
530    pub fn from_v6(multicast: IpAddrV6, scope_id: u32) -> MulticastLeaveGroup {
531        MulticastLeaveGroup(Mreq::V6(ipv6_mreq {
532            ipv6mr_multiaddr: in6_addr_of(multicast),
533            ipv6mr_interface: scope_id,
534        }))
535    }
536}
537
538impl<P: IpProtocol> SocketOption<P> for MulticastLeaveGroup {
539    type Data = ();
540
541    fn level(&self, pro: &P) -> i32 {
542        if pro == &P::v4() {
543            IPPROTO_IP.i32()
544        } else if pro.is_v6() {
545            IPPROTO_IPV6.i32()
546        } else {
547            unreachable!("Invalid ip version")
548        }
549    }
550
551    fn name(&self, pro: &P) -> i32 {
552        if pro.is_v4() {
553            IP_DROP_MEMBERSHIP
554        } else if pro.is_v6() {
555            IPV6_LEAVE_GROUP
556        } else {
557            unreachable!("Invalid ip version")
558        }
559    }
560}
561
562impl<P: IpProtocol> SetSocketOption<P> for MulticastLeaveGroup {
563    fn data(&self) -> &Self::Data {
564        match &self.0 {
565            &Mreq::V4(ref mreq) => unsafe { mem::transmute(mreq) },
566            &Mreq::V6(ref mreq) => unsafe { mem::transmute(mreq) },
567        }
568    }
569
570    fn size(&self) -> usize {
571        match &self.0 {
572            &Mreq::V4(ref mreq) => mem::size_of_val(mreq),
573            &Mreq::V6(ref mreq) => mem::size_of_val(mreq),
574        }
575    }
576}
577
578#[derive(Clone)]
579enum Iface {
580    V4(in_addr),
581    V6(u32),
582}
583
584/// Socket option for local interface to use for outgoing multicast packets.
585///
586/// Implements the IPPROTO_IP/IP_MULTICAST_IF socket option.
587///
588/// # Examples
589/// Setting the option:
590///
591/// ```
592/// use asyncio::*;
593/// use asyncio::ip::*;
594///
595/// let ctx = &IoContext::new().unwrap();
596/// let soc = UdpSocket::new(ctx, Udp::v4()).unwrap();
597///
598/// soc.set_option(OutboundInterface::new(IpAddr::V4(IpAddrV4::new(1,2,3,4))));
599/// ```
600#[derive(Clone)]
601pub struct OutboundInterface(Iface);
602
603impl OutboundInterface {
604    pub fn new(interface: IpAddr) -> OutboundInterface {
605        match interface {
606            IpAddr::V4(interface) => Self::from_v4(interface),
607            IpAddr::V6(interface) => Self::from_v6(interface),
608        }
609    }
610
611    pub fn from_v4(interface: IpAddrV4) -> OutboundInterface {
612        OutboundInterface(Iface::V4(in_addr_of(interface)))
613    }
614
615    pub fn from_v6(interface: IpAddrV6) -> OutboundInterface {
616        OutboundInterface(Iface::V6(interface.get_scope_id()))
617    }
618}
619
620impl<P: IpProtocol> SocketOption<P> for OutboundInterface {
621    type Data = u32;
622
623    fn level(&self, pro: &P) -> i32 {
624        if pro.is_v4() {
625            IPPROTO_IP.i32()
626        } else if pro.is_v6() {
627            IPPROTO_IPV6.i32()
628        } else {
629            unreachable!("Invalid ip version")
630        }
631    }
632
633    fn name(&self, pro: &P) -> i32 {
634        if pro.is_v4() {
635            IP_MULTICAST_IF
636        } else if pro.is_v6() {
637            IPV6_MULTICAST_IF
638        } else {
639            unreachable!("Invalid ip version")
640        }
641    }
642}
643
644impl<P: IpProtocol> SetSocketOption<P> for OutboundInterface {
645    fn data(&self) -> &Self::Data {
646        match &self.0 {
647            &Iface::V4(ref addr) => unsafe { mem::transmute(addr) },
648            &Iface::V6(ref scope_id) => &scope_id,
649        }
650    }
651}
652
653#[test]
654fn test_outbound_interface() {
655    assert_eq!(mem::size_of::<u32>(), mem::size_of::<in_addr>());
656}