udpsocketpool.cpp
1 //------------------------------------------------------------------------------
2 // udpsocketpool.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2017 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "udpsocketpool.h"
24 
25 #include "refresher/hostport.h"
26 #include <QList>
27 #include <QUdpSocket>
28 
29 DClass<UdpSocketPool>
30 {
31 public:
32  class Asset
33  {
34  public:
35  QUdpSocket *socket;
36  QSet<HostPort> addresses;
37  bool valid;
38 
39  Asset()
40  {
41  socket = new QUdpSocket();
42  valid = socket->bind();
43  }
44 
45  ~Asset()
46  {
47  delete socket;
48  }
49 
50  void addAddress(const HostPort &hostPort)
51  {
52  addresses.insert(hostPort);
53  }
54 
55  bool hasAddress(const HostPort &hostPort) const
56  {
57  return addresses.contains(hostPort);
58  }
59 
60  int size() const
61  {
62  return addresses.size();
63  }
64  };
65 
66  QList<Asset*> pool;
67  int sliceSize;
68 };
69 DPointeredNoCopy(UdpSocketPool)
70 
71 UdpSocketPool::UdpSocketPool(int sliceSize)
72 {
73  d->sliceSize = qMax(1, sliceSize);
74 }
75 
76 UdpSocketPool::~UdpSocketPool()
77 {
78  qDeleteAll(d->pool);
79 }
80 
81 QUdpSocket *UdpSocketPool::acquire(const QHostAddress &address, quint16 port)
82 {
83  HostPort hostPort(address, port);
84  // Return if already acquired.
85  foreach (PrivData<UdpSocketPool>::Asset *asset, d->pool)
86  {
87  if (asset->hasAddress(hostPort))
88  {
89  return asset->socket;
90  }
91  }
92  // Acquire existing.
93  foreach (PrivData<UdpSocketPool>::Asset *asset, d->pool)
94  {
95  if (asset->size() < d->sliceSize)
96  {
97  asset->addAddress(hostPort);
98  return asset->socket;
99  }
100  }
101  // Acquire new.
103  if (asset->valid)
104  {
105  this->connect(asset->socket, SIGNAL(readyRead()), SIGNAL(readyRead()));
106  asset->addAddress(hostPort);
107  d->pool << asset;
108  return asset->socket;
109  }
110  else
111  {
112  delete asset;
113  return NULL;
114  }
115 }
116 
117 QUdpSocket *UdpSocketPool::acquireMasterSocket()
118 {
119  return acquire(QHostAddress("0.0.0.0"), 0);
120 }
121 
122 void UdpSocketPool::releaseAll()
123 {
124  qDeleteAll(d->pool);
125  d->pool.clear();
126 }
127 
128 bool UdpSocketPool::hasPendingDatagrams() const
129 {
130  foreach (PrivData<UdpSocketPool>::Asset *asset, d->pool)
131  {
132  if (asset->socket->hasPendingDatagrams())
133  return true;
134  }
135  return false;
136 }
137 
138 QByteArray UdpSocketPool::readNextDatagram(QHostAddress *address, quint16 *port)
139 {
140  foreach (PrivData<UdpSocketPool>::Asset *asset, d->pool)
141  {
142  QUdpSocket *socket = asset->socket;
143  if (socket->hasPendingDatagrams())
144  {
145  int size = socket->pendingDatagramSize();
146  char *buffer = new char[size];
147  socket->readDatagram(buffer, size, address, port);
148  QByteArray data(buffer, size);
149  delete [] buffer;
150  return data;
151  }
152  }
153  return QByteArray();
154 }
Definition: dptr.h:31