Fix compilation
[pwlib.git] / src / ptclib / psockbun.cxx
blobfe3b843dbb00a1e8a4e67726feaced8f9df254da
1 /*
2 * psockbun.cxx
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
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Post Increment
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.3 2007/05/28 11:26:50 hfriederich
28 * Fix compilation
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 //////////////////////////////////////////////////
40 #ifdef __GNUC__
41 #pragma implementation "psockbun.h"
42 #endif
44 #include <ptlib.h>
45 #include <ptclib/psockbun.h>
47 PInterfaceBundle::PInterfaceBundle(PINDEX _refreshInterval)
48 : refreshInterval(_refreshInterval), updateThread(NULL)
52 PInterfaceBundle::~PInterfaceBundle()
54 Close();
57 BOOL PInterfaceBundle::Open()
59 if (updateThread != NULL)
60 return FALSE;
62 PIPSocket::GetInterfaceTable(currentInterfaces);
64 // add all interfaces
66 PINDEX i;
67 for (i = 0; i < currentInterfaces.GetSize(); ++i) {
68 InterfaceEntry & entry = currentInterfaces[i];
69 OnAddInterface(entry);
73 threadRunning = TRUE;
74 updateThread = new PThreadObj<PInterfaceBundle>(*this, &PInterfaceBundle::UpdateThreadMain);
75 return TRUE;
78 BOOL PInterfaceBundle::IsOpen()
80 return updateThread != NULL;
84 void PInterfaceBundle::Close()
86 // shutdown the update thread
87 threadRunning = FALSE;
88 updateThread->WaitForTermination();
89 delete updateThread;
90 updateThread = NULL;
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
115 PINDEX i;
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())
144 return FALSE;
146 // ensure every element in list1 is in list2
147 if (!InterfaceListIsSubsetOf(list1, list2))
148 return FALSE;
150 // ensure every element in list1 is in list2
151 return InterfaceListIsSubsetOf(list2, list1);
154 BOOL PInterfaceBundle::InterfaceListIsSubsetOf(const InterfaceTable & subset, const InterfaceTable & set)
156 PINDEX i;
157 for (i = 0; i < subset.GetSize(); ++i) {
158 InterfaceEntry & entry = subset[i];
159 if (!IsInterfaceInList(entry, set))
160 return FALSE;
163 return TRUE;
166 BOOL PInterfaceBundle::IsInterfaceInList(const InterfaceEntry & entry, const InterfaceTable & list)
168 PINDEX i;
169 for (i = 0; i < list.GetSize(); ++i) {
170 InterfaceEntry & listEntry = list[i];
171 if ((entry.GetName() == listEntry.GetName()) && (entry.GetAddress() == listEntry.GetAddress()))
172 return TRUE;
174 return FALSE;
177 PStringList PInterfaceBundle::GetInterfaceList(BOOL includeLoopBack)
179 PStringList list;
182 PWaitAndSignal m(mutex);
183 PINDEX i;
184 for (i = 0; i < currentInterfaces.GetSize(); ++i) {
185 InterfaceEntry & entry = currentInterfaces[i];
186 if (includeLoopBack || !entry.GetAddress().IsLoopback())
187 list.AppendString(entry.GetName());
191 return list;
194 BOOL PInterfaceBundle::GetInterfaceInfo(const PString & iface, InterfaceEntry & info)
196 if (iface.IsEmpty())
197 return FALSE;
200 PWaitAndSignal m(mutex);
201 PINDEX i;
202 for (i = 0; i < currentInterfaces.GetSize(); ++i) {
203 InterfaceEntry & entry = currentInterfaces[i];
204 if (entry.GetName() == iface) {
205 info = entry;
206 return TRUE;
211 return FALSE;
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
240 // TODO
243 BOOL PMultipleSocketBundle::Open(WORD _port)
245 if (IsOpen())
246 return FALSE;
248 port = _port;
250 return PSocketBundle::Open();
253 void PMultipleSocketBundle::OnAddInterface(const InterfaceEntry & entry)
255 PUDPSocket * socket = new PUDPSocket(port);
256 if (!socket->Listen(entry.GetAddress()))
257 delete socket;
258 else {
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);
273 if (info->inUse) {
274 info->removed = TRUE;
275 removedSockets.push_back(info);
277 else
279 delete info->socket;
280 delete info;
286 BOOL PMultipleSocketBundle::SendTo(const void * buf, PINDEX len,
287 const PUDPSocket::Address & addr, WORD port,
288 const PString & iface,
289 PINDEX & lastWriteCount)
291 if (iface.IsEmpty())
292 return FALSE;
294 PWaitAndSignal m(mutex);
295 SocketInfoMap_T::iterator r = socketInfoMap.find(iface);
296 if (r == socketInfoMap.end())
297 return FALSE;
299 SocketInfo & info = *(r->second);
300 PUDPSocket & udp = *info.socket;
302 if (!udp.WriteTo(buf, len, addr, port))
303 return FALSE;
305 lastWriteCount = udp.GetLastWriteCount();
306 return TRUE;
309 BOOL PMultipleSocketBundle::ReadFrom(void * buf, PINDEX len,
310 PIPSocket::Address & addr, WORD & port,
311 PString & iface,
312 PINDEX & lastReadCount)
314 // if interface is not empty, use that specific interface
315 if (!iface.IsEmpty()) {
316 SocketInfo * info;
318 PWaitAndSignal m(mutex);
319 SocketInfoMap_T::iterator r = socketInfoMap.find(iface);
320 if (r == socketInfoMap.end())
321 return FALSE;
322 info = r->second;
323 info->inUse = TRUE;
326 if (!info->socket->ReadFrom(buf, len, addr, port))
327 return FALSE;
330 PWaitAndSignal m(mutex);
331 if (info->removed) {
332 SocketInfoList_T ::iterator r = ::find(removedSockets.begin(), removedSockets.end(), info);
333 if (r != removedSockets.end())
334 removedSockets.erase(r);
335 delete info->socket;
336 delete info;
337 return FALSE;
339 lastReadCount = info->socket->GetLastReadCount();
340 info->inUse = FALSE;
343 return TRUE;
346 // if interface is empty, wait on all interfaces
347 // %%TODO - not implemented
348 return FALSE;
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);