4 * Socket and interface bundle code
6 * Portable Windows Library
8 * Copyright (C) 2007 Post Increment
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Post Increment
24 * Contributor(s): ______________________________________.
27 * Revision 1.3 2007/05/28 11:26:50 hfriederich
30 * Revision 1.2 2007/05/22 11:50:57 csoutheren
31 * Further implementation of socket bundle
33 * Revision 1.1 2007/05/21 06:07:17 csoutheren
34 * Add new socket bundle code to be used to OpalUDPListener
38 //////////////////////////////////////////////////
41 #pragma implementation "psockbun.h"
45 #include <ptclib/psockbun.h>
47 PInterfaceBundle::PInterfaceBundle(PINDEX _refreshInterval
)
48 : refreshInterval(_refreshInterval
), updateThread(NULL
)
52 PInterfaceBundle::~PInterfaceBundle()
57 BOOL
PInterfaceBundle::Open()
59 if (updateThread
!= NULL
)
62 PIPSocket::GetInterfaceTable(currentInterfaces
);
67 for (i
= 0; i
< currentInterfaces
.GetSize(); ++i
) {
68 InterfaceEntry
& entry
= currentInterfaces
[i
];
69 OnAddInterface(entry
);
74 updateThread
= new PThreadObj
<PInterfaceBundle
>(*this, &PInterfaceBundle::UpdateThreadMain
);
78 BOOL
PInterfaceBundle::IsOpen()
80 return updateThread
!= NULL
;
84 void PInterfaceBundle::Close()
86 // shutdown the update thread
87 threadRunning
= FALSE
;
88 updateThread
->WaitForTermination();
92 // delete the entries in the interface list
93 while (currentInterfaces
.GetSize() > 0) {
94 InterfaceEntry
& entry
= currentInterfaces
[0];
95 OnRemoveInterface(entry
);
96 currentInterfaces
.RemoveAt(0);
100 void PInterfaceBundle::RefreshInterfaceList()
102 // get a new interface list
103 InterfaceTable newInterfaces
;
104 PIPSocket::GetInterfaceTable(newInterfaces
);
106 PWaitAndSignal
m(mutex
);
108 // if changed, then update the internal list
109 if (!CompareInterfaceLists(currentInterfaces
, newInterfaces
)) {
111 InterfaceTable oldInterfaces
= currentInterfaces
;
112 currentInterfaces
= newInterfaces
;
114 // look for interfaces to add that are in new list that are not in the old list
116 for (i
= 0; i
< newInterfaces
.GetSize(); ++i
) {
117 InterfaceEntry
& newEntry
= newInterfaces
[i
];
118 if (!newEntry
.GetAddress().IsLoopback() && !IsInterfaceInList(newEntry
, oldInterfaces
))
119 OnAddInterface(newEntry
);
122 // look for interfaces to remove that are in old list that are not in the new list
123 for (i
= 0; i
< oldInterfaces
.GetSize(); ++i
) {
124 InterfaceEntry
& oldEntry
= oldInterfaces
[i
];
125 if (!oldEntry
.GetAddress().IsLoopback() && !IsInterfaceInList(oldEntry
, newInterfaces
))
126 OnRemoveInterface(oldEntry
);
131 void PInterfaceBundle::UpdateThreadMain()
133 // check for interface changes every 5 seconds
134 while (threadRunning
) {
135 PThread::Sleep(5000);
136 RefreshInterfaceList();
140 BOOL
PInterfaceBundle::CompareInterfaceLists(const InterfaceTable
& list1
, const InterfaceTable
& list2
)
142 // if the sizes are different, then the list has changed.
143 if (list1
.GetSize() != list2
.GetSize())
146 // ensure every element in list1 is in list2
147 if (!InterfaceListIsSubsetOf(list1
, list2
))
150 // ensure every element in list1 is in list2
151 return InterfaceListIsSubsetOf(list2
, list1
);
154 BOOL
PInterfaceBundle::InterfaceListIsSubsetOf(const InterfaceTable
& subset
, const InterfaceTable
& set
)
157 for (i
= 0; i
< subset
.GetSize(); ++i
) {
158 InterfaceEntry
& entry
= subset
[i
];
159 if (!IsInterfaceInList(entry
, set
))
166 BOOL
PInterfaceBundle::IsInterfaceInList(const InterfaceEntry
& entry
, const InterfaceTable
& list
)
169 for (i
= 0; i
< list
.GetSize(); ++i
) {
170 InterfaceEntry
& listEntry
= list
[i
];
171 if ((entry
.GetName() == listEntry
.GetName()) && (entry
.GetAddress() == listEntry
.GetAddress()))
177 PStringList
PInterfaceBundle::GetInterfaceList(BOOL includeLoopBack
)
182 PWaitAndSignal
m(mutex
);
184 for (i
= 0; i
< currentInterfaces
.GetSize(); ++i
) {
185 InterfaceEntry
& entry
= currentInterfaces
[i
];
186 if (includeLoopBack
|| !entry
.GetAddress().IsLoopback())
187 list
.AppendString(entry
.GetName());
194 BOOL
PInterfaceBundle::GetInterfaceInfo(const PString
& iface
, InterfaceEntry
& info
)
200 PWaitAndSignal
m(mutex
);
202 for (i
= 0; i
< currentInterfaces
.GetSize(); ++i
) {
203 InterfaceEntry
& entry
= currentInterfaces
[i
];
204 if (entry
.GetName() == iface
) {
215 void PInterfaceBundle::OnAddInterface(const InterfaceEntry
&)
219 void PInterfaceBundle::OnRemoveInterface(const InterfaceEntry
&)
223 //////////////////////////////////////////////////
225 PSocketBundle::PSocketBundle(PINDEX refreshInterval
)
226 : PInterfaceBundle(refreshInterval
)
230 //////////////////////////////////////////////////
232 PMultipleSocketBundle::PMultipleSocketBundle(PINDEX _refreshInterval
)
233 : PSocketBundle(_refreshInterval
)
237 PMultipleSocketBundle::~PMultipleSocketBundle()
239 // delete the sockets
243 BOOL
PMultipleSocketBundle::Open(WORD _port
)
250 return PSocketBundle::Open();
253 void PMultipleSocketBundle::OnAddInterface(const InterfaceEntry
& entry
)
255 PUDPSocket
* socket
= new PUDPSocket(port
);
256 if (!socket
->Listen(entry
.GetAddress()))
259 SocketInfo
* info
= new SocketInfo
;
260 info
->socket
= socket
;
261 socketInfoMap
.insert(SocketInfoMap_T::value_type(entry
.GetName(), info
));
262 cout
<< "Interface added : " << entry
.GetName() << endl
;
266 void PMultipleSocketBundle::OnRemoveInterface(const InterfaceEntry
& entry
)
268 cout
<< "Interface removed : " << entry
.GetName() << endl
;
269 SocketInfoMap_T::iterator r
= socketInfoMap
.find(entry
.GetName());
270 if (r
!= socketInfoMap
.end()) {
271 SocketInfo
* info
= r
->second
;
272 socketInfoMap
.erase(r
);
274 info
->removed
= TRUE
;
275 removedSockets
.push_back(info
);
286 BOOL
PMultipleSocketBundle::SendTo(const void * buf
, PINDEX len
,
287 const PUDPSocket::Address
& addr
, WORD port
,
288 const PString
& iface
,
289 PINDEX
& lastWriteCount
)
294 PWaitAndSignal
m(mutex
);
295 SocketInfoMap_T::iterator r
= socketInfoMap
.find(iface
);
296 if (r
== socketInfoMap
.end())
299 SocketInfo
& info
= *(r
->second
);
300 PUDPSocket
& udp
= *info
.socket
;
302 if (!udp
.WriteTo(buf
, len
, addr
, port
))
305 lastWriteCount
= udp
.GetLastWriteCount();
309 BOOL
PMultipleSocketBundle::ReadFrom(void * buf
, PINDEX len
,
310 PIPSocket::Address
& addr
, WORD
& port
,
312 PINDEX
& lastReadCount
)
314 // if interface is not empty, use that specific interface
315 if (!iface
.IsEmpty()) {
318 PWaitAndSignal
m(mutex
);
319 SocketInfoMap_T::iterator r
= socketInfoMap
.find(iface
);
320 if (r
== socketInfoMap
.end())
326 if (!info
->socket
->ReadFrom(buf
, len
, addr
, port
))
330 PWaitAndSignal
m(mutex
);
332 SocketInfoList_T ::iterator r
= ::find(removedSockets
.begin(), removedSockets
.end(), info
);
333 if (r
!= removedSockets
.end())
334 removedSockets
.erase(r
);
339 lastReadCount
= info
->socket
->GetLastReadCount();
346 // if interface is empty, wait on all interfaces
347 // %%TODO - not implemented
351 //////////////////////////////////////////////////
353 PSingleSocketBundle::PSingleSocketBundle(const PString
& _theInterface
, PINDEX _refreshInterval
)
354 : PMultipleSocketBundle(_refreshInterval
), theInterface(_theInterface
)
358 void PSingleSocketBundle::OnAddInterface(const InterfaceEntry
& entry
)
360 if (entry
.GetName() == entry
)
361 PMultipleSocketBundle::OnAddInterface(entry
);
364 void PSingleSocketBundle::OnRemoveInterface(const InterfaceEntry
& entry
)
366 if (entry
.GetName() == entry
)
367 PMultipleSocketBundle::OnRemoveInterface(entry
);