00001 /******************************************************************************* 00002 00003 @file MulticastSocket.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version, June 2004 00034 @author Kris 00035 00036 00037 *******************************************************************************/ 00038 00039 module mango.io.MulticastSocket; 00040 00041 private import mango.io.Socket, 00042 mango.io.Buffer, 00043 mango.io.Exception, 00044 mango.io.DatagramSocket; 00045 00046 /****************************************************************************** 00047 00048 Wrapper around multicast style of sockets, to simplify the API a 00049 bit, and to tie them into the IBuffer construct. Note that when used 00050 with a SocketListener you must first join the MulticastSocket to a 00051 group. Do not bind() it yourself, since that is performed by the 00052 join() method. 00053 00054 *******************************************************************************/ 00055 00056 class MulticastSocket : DatagramSocket 00057 { 00058 private InternetAddress groupAddress; 00059 00060 /*********************************************************************** 00061 00062 Enable/disable the receipt of multicast packets send 00063 from the same socket 00064 00065 ***********************************************************************/ 00066 00067 void setLoopback (bool loopback) 00068 { 00069 uint[1] onoff = loopback; 00070 setOption (OptionLevel.IP, Option.IP_MULTICAST_LOOP, onoff); 00071 } 00072 00073 /*********************************************************************** 00074 00075 Join a multicast group. This is necessary only for a 00076 multicast reciever (listener). You may call this for 00077 a send-only socket without harm, but the operation is 00078 completely superfluous. 00079 00080 Note that the socket will be bound to the specified port, 00081 and be listening on the provided class D address. Expect 00082 join() to fail without a network adapter present, or the 00083 NIC is not plugged into a router or switch. 00084 00085 ***********************************************************************/ 00086 00087 void join (InternetAddress groupAddress) 00088 { 00089 this.groupAddress = groupAddress; 00090 00091 setAddressReuse (true); 00092 bind (new InternetAddress(groupAddress.port())); 00093 resumeGroup (); 00094 } 00095 00096 /*********************************************************************** 00097 00098 Remove this socket from the current group. Method join() 00099 is expected to have been invoked previously, otherwise 00100 this is a noop. 00101 00102 ***********************************************************************/ 00103 00104 void pauseGroup () 00105 { 00106 if (groupAddress) 00107 if (! setGroup (groupAddress, Option.IP_DROP_MEMBERSHIP)) 00108 exception ("Unable to leave multicast group."); 00109 } 00110 00111 /*********************************************************************** 00112 00113 Add this socket to the current group again. Method join() 00114 is expected to have been invoked previously, otherwise 00115 this is a noop. 00116 00117 ***********************************************************************/ 00118 00119 void resumeGroup () 00120 { 00121 if (groupAddress) 00122 if (! setGroup (groupAddress, Option.IP_ADD_MEMBERSHIP)) 00123 exception ("Unable to join multicast group."); 00124 } 00125 00126 /*********************************************************************** 00127 00128 Leave a multicast group. This should only be invoked on 00129 sockets that have already joined a multicast group, and 00130 before said socket joins another group. 00131 00132 There does not appear to be a means to unbind the socket 00133 from the port specified during the original join(); thus 00134 we have to create a new underlying socket before join() 00135 will bind() cleanly. 00136 00137 ***********************************************************************/ 00138 00139 void leave () 00140 { 00141 if (groupAddress) 00142 { 00143 pauseGroup (); 00144 groupAddress = null; 00145 00146 // drop the original socket handle 00147 closure(); 00148 00149 // create a new socket for binding during another join(), since 00150 // there doesn't appear to be a means of unbinding 00151 create (Socket.AddressFamily.INET, Socket.Type.DGRAM, Socket.Protocol.IP); 00152 } 00153 } 00154 }