| 1 | // Copyright (C) 2019 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 3 | |
| 4 | #include "qcoapconnection_p.h" |
| 5 | |
| 6 | #include <QtCore/qloggingcategory.h> |
| 7 | |
| 8 | QT_BEGIN_NAMESPACE |
| 9 | |
| 10 | Q_LOGGING_CATEGORY(lcCoapConnection, "qt.coap.connection" ) |
| 11 | |
| 12 | /*! |
| 13 | \internal |
| 14 | |
| 15 | \class QCoapConnection |
| 16 | \inmodule QtCoap |
| 17 | |
| 18 | \brief The QCoapConnection class defines an interface for |
| 19 | handling transfers of frames to a server. |
| 20 | |
| 21 | It isolates CoAP clients from the transport in use, so that any |
| 22 | client can be used with any supported transport. |
| 23 | */ |
| 24 | |
| 25 | /*! |
| 26 | \internal |
| 27 | |
| 28 | \enum QCoapConnection::ConnectionState |
| 29 | |
| 30 | This enum specifies the state of the underlying transport. |
| 31 | |
| 32 | \value Unconnected The underlying transport is not yet ready for data transmission. |
| 33 | |
| 34 | \value Bound The underlying transport is ready for data transmission. For example, |
| 35 | if QUdpSocket is used for the transport, this corresponds to |
| 36 | QAbstractSocket::BoundState. |
| 37 | \sa state(), bound() |
| 38 | */ |
| 39 | |
| 40 | /*! |
| 41 | \internal |
| 42 | |
| 43 | \fn void QCoapConnection::error(QAbstractSocket::SocketError error) |
| 44 | |
| 45 | This signal is emitted when a connection error occurs. The \a error |
| 46 | parameter describes the type of error that occurred. |
| 47 | */ |
| 48 | |
| 49 | /*! |
| 50 | \internal |
| 51 | |
| 52 | \fn void QCoapConnection::readyRead(const QByteArray &data, const QHostAddress &sender) |
| 53 | |
| 54 | This signal is emitted when a network reply is available. The \a data |
| 55 | parameter supplies the received data, and the \a sender parameter supplies |
| 56 | the sender address. |
| 57 | */ |
| 58 | |
| 59 | /*! |
| 60 | \internal |
| 61 | |
| 62 | \fn void QCoapConnection::bound() |
| 63 | |
| 64 | This signal is emitted when the underlying transport is ready for data transmission. |
| 65 | Derived implementations must emit this signal whenever they are ready to start |
| 66 | transferring data frames to and from the server. |
| 67 | |
| 68 | \sa bind() |
| 69 | */ |
| 70 | |
| 71 | /*! |
| 72 | \fn void QCoapConnection::securityConfigurationChanged() |
| 73 | |
| 74 | This signal is emitted when the security configuration is changed. |
| 75 | */ |
| 76 | |
| 77 | /*! |
| 78 | \internal |
| 79 | |
| 80 | \fn void QCoapConnection::bind(const QString &host, quint16 port) |
| 81 | |
| 82 | Prepares the underlying transport for data transmission to to the given \a host |
| 83 | address on \a port. Emits the bound() signal when the transport is ready. |
| 84 | |
| 85 | This is a pure virtual method. |
| 86 | |
| 87 | \sa bound(), close() |
| 88 | */ |
| 89 | |
| 90 | /*! |
| 91 | \internal |
| 92 | |
| 93 | \fn void QCoapConnection::close() |
| 94 | |
| 95 | Closes the open sockets and connections to free the underlying transport. |
| 96 | This is a pure virtual method. |
| 97 | |
| 98 | \sa bind() |
| 99 | */ |
| 100 | |
| 101 | /*! |
| 102 | \internal |
| 103 | |
| 104 | \fn void QCoapConnection::writeData(const QByteArray &data, const QString &host, quint16 port) |
| 105 | |
| 106 | Sends the given \a data frame to the host address \a host at port \a port. |
| 107 | |
| 108 | This is a pure virtual method. |
| 109 | */ |
| 110 | |
| 111 | QCoapConnectionPrivate::QCoapConnectionPrivate(QtCoap::SecurityMode security) |
| 112 | : securityMode(security) |
| 113 | , state(QCoapConnection::ConnectionState::Unconnected) |
| 114 | {} |
| 115 | |
| 116 | /*! |
| 117 | Constructs a new CoAP connection for the given \a securityMode and |
| 118 | sets \a parent as its parent. |
| 119 | */ |
| 120 | QCoapConnection::QCoapConnection(QtCoap::SecurityMode securityMode, QObject *parent) |
| 121 | : QCoapConnection(*new QCoapConnectionPrivate(securityMode), parent) |
| 122 | { |
| 123 | } |
| 124 | |
| 125 | /*! |
| 126 | \internal |
| 127 | |
| 128 | Constructs a new new CoAP connection as a child of \a parent, with \a dd |
| 129 | as its \c d_ptr. This constructor must be used when internally subclassing |
| 130 | the QCoapConnection class. |
| 131 | */ |
| 132 | QCoapConnection::QCoapConnection(QObjectPrivate &dd, QObject *parent) |
| 133 | : QObject(dd, parent) |
| 134 | { |
| 135 | connect(sender: this, signal: &QCoapConnection::bound, context: this, |
| 136 | slot: [this]() { |
| 137 | Q_D(QCoapConnection); |
| 138 | d->state = ConnectionState::Bound; |
| 139 | startToSendRequest(); |
| 140 | }); |
| 141 | } |
| 142 | |
| 143 | /*! |
| 144 | \internal |
| 145 | |
| 146 | Releases any resources held by QCoapConnection. |
| 147 | */ |
| 148 | QCoapConnection::~QCoapConnection() |
| 149 | { |
| 150 | } |
| 151 | |
| 152 | /*! |
| 153 | \internal |
| 154 | |
| 155 | Prepares the underlying transport for data transmission and sends the given |
| 156 | \a request frame to the given \a host at the given \a port when the transport |
| 157 | is ready. |
| 158 | |
| 159 | The preparation of the transport is done by calling the pure virtual bind() method, |
| 160 | which needs to be implemented by derived classes. |
| 161 | */ |
| 162 | void |
| 163 | QCoapConnectionPrivate::sendRequest(const QByteArray &request, const QString &host, quint16 port) |
| 164 | { |
| 165 | Q_Q(QCoapConnection); |
| 166 | |
| 167 | CoapFrame frame(request, host, port); |
| 168 | framesToSend.enqueue(t: frame); |
| 169 | |
| 170 | if (state == QCoapConnection::ConnectionState::Unconnected) |
| 171 | q->bind(host, port); |
| 172 | else |
| 173 | q->startToSendRequest(); |
| 174 | } |
| 175 | |
| 176 | /*! |
| 177 | \internal |
| 178 | |
| 179 | Returns \c true if security is used, returns \c false otherwise. |
| 180 | */ |
| 181 | bool QCoapConnection::isSecure() const |
| 182 | { |
| 183 | Q_D(const QCoapConnection); |
| 184 | return d->securityMode != QtCoap::SecurityMode::NoSecurity; |
| 185 | } |
| 186 | |
| 187 | /*! |
| 188 | \internal |
| 189 | |
| 190 | Returns the security mode. |
| 191 | */ |
| 192 | QtCoap::SecurityMode QCoapConnection::securityMode() const |
| 193 | { |
| 194 | Q_D(const QCoapConnection); |
| 195 | return d->securityMode; |
| 196 | } |
| 197 | |
| 198 | /*! |
| 199 | \internal |
| 200 | |
| 201 | Returns the connection state. |
| 202 | */ |
| 203 | QCoapConnection::ConnectionState QCoapConnection::state() const |
| 204 | { |
| 205 | Q_D(const QCoapConnection); |
| 206 | return d->state; |
| 207 | } |
| 208 | |
| 209 | /*! |
| 210 | \internal |
| 211 | |
| 212 | Sends the last stored frame to the server by calling the pure virtual |
| 213 | writeData() method. |
| 214 | */ |
| 215 | void QCoapConnection::startToSendRequest() |
| 216 | { |
| 217 | Q_D(QCoapConnection); |
| 218 | |
| 219 | Q_ASSERT(!d->framesToSend.isEmpty()); |
| 220 | while (!d->framesToSend.isEmpty()) { |
| 221 | const CoapFrame frame = d->framesToSend.dequeue(); |
| 222 | writeData(data: frame.currentPdu, host: frame.host, port: frame.port); |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | /*! |
| 227 | Sets the security configuration parameters from the \a configuration. |
| 228 | The security configuration will be ignored if the QtCoap::NoSecurity mode is |
| 229 | used for connection. |
| 230 | |
| 231 | \note This method must be called before the handshake starts. |
| 232 | */ |
| 233 | void QCoapConnection::setSecurityConfiguration(const QCoapSecurityConfiguration &configuration) |
| 234 | { |
| 235 | Q_D(QCoapConnection); |
| 236 | |
| 237 | if (isSecure()) { |
| 238 | d->securityConfiguration = configuration; |
| 239 | emit securityConfigurationChanged(); |
| 240 | } else { |
| 241 | qCWarning(lcCoapConnection, "Security is disabled, security configuration will be ignored." ); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /*! |
| 246 | \internal |
| 247 | |
| 248 | Returns the security configuration. |
| 249 | */ |
| 250 | QCoapSecurityConfiguration QCoapConnection::securityConfiguration() const |
| 251 | { |
| 252 | Q_D(const QCoapConnection); |
| 253 | return d->securityConfiguration; |
| 254 | } |
| 255 | |
| 256 | /*! |
| 257 | \internal |
| 258 | |
| 259 | Closes the open sockets and connections to free the transport and clears |
| 260 | the connection state. |
| 261 | */ |
| 262 | void QCoapConnection::disconnect() |
| 263 | { |
| 264 | Q_D(QCoapConnection); |
| 265 | |
| 266 | close(); |
| 267 | |
| 268 | d->framesToSend.clear(); |
| 269 | d->state = ConnectionState::Unconnected; |
| 270 | } |
| 271 | |
| 272 | QT_END_NAMESPACE |
| 273 | |