Compare commits
No commits in common. 'master' and 'main' have entirely different histories.
@ -1,88 +0,0 @@
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||
# release/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
#*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
.cxx/
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
# lint
|
||||
lint/intermediates/
|
||||
lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
|
||||
.DS_Store
|
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1 +0,0 @@
|
||||
/build
|
@ -1,51 +0,0 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
ndkVersion '22.1.7171670'
|
||||
// ndkVersion '16.1.4479499'
|
||||
buildToolsVersion "29.0.2"
|
||||
defaultConfig {
|
||||
applicationId "moe.key.yao.mqtt.client"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility 1.8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'com.google.guava:guava:28.0-android'
|
||||
|
||||
implementation project(':library')
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
@ -1,24 +0,0 @@
|
||||
package moe.key.yao.mqtt.client
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("moe.key.yao.mqtt.client", appContext.packageName)
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="moe.key.yao.mqtt.client">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -1,115 +0,0 @@
|
||||
package moe.key.yao.mqtt.client
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.common.io.ByteStreams
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import moe.key.yao.mqtt.library.MqttClient
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class MainActivity : AppCompatActivity(), MqttClient.MqttCallback {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
MqttClient.getInstance().setOnMqttCallback(this)
|
||||
initLayout()
|
||||
initPermission()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
MqttClient.getInstance().setOnMqttCallback(null)
|
||||
}
|
||||
|
||||
private fun initLayout() {
|
||||
btn_start.setOnClickListener {
|
||||
startMqttService()
|
||||
}
|
||||
btn_subscribe.setOnClickListener {
|
||||
subscribeTopic()
|
||||
}
|
||||
btn_unsubscribe.setOnClickListener {
|
||||
unsubscribeTopic()
|
||||
}
|
||||
btn_publish.setOnClickListener {
|
||||
publishMessage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initPermission() {
|
||||
val hasPermission: Int = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
if (hasPermission != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun startMqttService() {
|
||||
// copy ca file to sdcard
|
||||
val caFilePath = "${getExternalFilesDir(null)}/ca.crt"
|
||||
val file = File(caFilePath)
|
||||
if (!file.exists()) {
|
||||
file.createNewFile()
|
||||
val inStream = assets.open("ca.crt")
|
||||
val outStream = FileOutputStream(file)
|
||||
ByteStreams.copy(inStream, outStream)
|
||||
inStream.close()
|
||||
outStream.close()
|
||||
}
|
||||
|
||||
// MqttClient.getInstance().start("192.168.1.190", 1883, "mqtt_android_client", false)
|
||||
MqttClient.getInstance().start("192.168.1.190", 8883, "mqtt_android_client", false, caFilePath, "test", "123456")
|
||||
}
|
||||
|
||||
private fun subscribeTopic() {
|
||||
val topic = "/android/test/topicA"
|
||||
MqttClient.getInstance().subscribe(topic)
|
||||
}
|
||||
|
||||
private fun unsubscribeTopic() {
|
||||
val topic = "/android/test/topicA"
|
||||
MqttClient.getInstance().unsubscribe(topic)
|
||||
}
|
||||
|
||||
private fun publishMessage() {
|
||||
val topic = "/android/test/topicA"
|
||||
val message = "test message"
|
||||
MqttClient.getInstance().publish(topic, message)
|
||||
}
|
||||
|
||||
override fun onMessage(topic: String, message: String) {
|
||||
println("on message: $topic | $message")
|
||||
}
|
||||
|
||||
override fun onLog(str: String?) {
|
||||
println("on log: $str")
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == 1) {
|
||||
var flag = false
|
||||
for (i in permissions.indices) {
|
||||
if (permissions[i] == Manifest.permission.READ_EXTERNAL_STORAGE && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
Toast.makeText(this, "获取权限失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#008577"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_start"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="start service"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_subscribe"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="subscribe"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_start"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_unsubscribe"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="unsubscribe"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_subscribe"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_publish"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="publish"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_unsubscribe"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 15 KiB |
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
</resources>
|
@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">mqtt_client_android</string>
|
||||
</resources>
|
@ -1,11 +0,0 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1,17 +0,0 @@
|
||||
package moe.key.yao.mqtt.client
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.61'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
android.enableR8=false
|
@ -1,5 +0,0 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
@ -1,172 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
@ -1,84 +0,0 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@ -1 +0,0 @@
|
||||
/build
|
@ -1,53 +0,0 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
ndkVersion '22.1.7171670'
|
||||
// ndkVersion '16.1.4479499'
|
||||
defaultConfig {
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a'
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk"
|
||||
abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility 1.8
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path file('src/main/jni/Android.mk')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
@ -1,27 +0,0 @@
|
||||
package moe.key.yao.mqtt.library;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("moe.key.yao.mqtt.library.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="moe.key.yao.mqtt.library" />
|
@ -1,104 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# ssl lib
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ssl
|
||||
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libssl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
# crypto lib
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ssl_crypto
|
||||
LOCAL_SRC_FILES := lib/$(TARGET_ARCH_ABI)/libcrypto.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
# build flag
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_CFLAGS += -fexceptions
|
||||
LOCAL_CPPFLAGS += -std=c++11
|
||||
LOCAL_LDLIBS += -llog -landroid
|
||||
|
||||
# include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/openssl/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/uthash/src
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/mosquitto
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/mosquitto/lib
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/mosquitto/lib/cpp
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/jsoncpp/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/jsoncpp/src/lib_json
|
||||
|
||||
# mosquitto lib
|
||||
LOCAL_CFLAGS += -DWITH_SOCKS
|
||||
LOCAL_CFLAGS += -DWITH_EC
|
||||
LOCAL_CFLAGS += -DWITH_UUID
|
||||
LOCAL_CFLAGS += -DWITH_SYS_TREE
|
||||
LOCAL_CFLAGS += -DWITH_MENORY_TRACKING
|
||||
LOCAL_CFLAGS += -DWITH_PERSISTENCE
|
||||
LOCAL_CFLAGS += -DWITH_BRIDGE
|
||||
LOCAL_CFLAGS += -DWITH_THREADING
|
||||
LOCAL_CFLAGS += -DWITH_TLS_PSK
|
||||
LOCAL_CFLAGS += -DWITH_TLS
|
||||
|
||||
LOCAL_SRC_FILES += jsoncpp/src/lib_json/json_reader.cpp
|
||||
LOCAL_SRC_FILES += jsoncpp/src/lib_json/json_valueiterator.inl
|
||||
LOCAL_SRC_FILES += jsoncpp/src/lib_json/json_value.cpp
|
||||
LOCAL_SRC_FILES += jsoncpp/src/lib_json/json_writer.cpp
|
||||
LOCAL_SRC_FILES += jsoncpp/version.in
|
||||
|
||||
LOCAL_SRC_FILES += mosquitto/lib/actions.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/alias_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/callbacks.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/connect.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_auth.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_connack.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_disconnect.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_ping.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_pubackcomp.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_publish.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_pubrec.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_pubrel.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_suback.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/handle_unsuback.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/helpers.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/logging_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/loop.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/memory_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/messages_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/mosquitto.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/net_mosq_ocsp.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/net_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/options.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/packet_datatypes.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/packet_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/property_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/read_handle.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/send_connect.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/send_disconnect.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/send_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/send_publish.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/send_subscribe.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/send_unsubscribe.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/socks_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/srv_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/thread_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/time_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/tls_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/utf8_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/util_mosq.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/util_topic.c
|
||||
LOCAL_SRC_FILES += mosquitto/lib/will_mosq.c
|
||||
|
||||
LOCAL_SRC_FILES += mosquitto_wrapper.cpp
|
||||
LOCAL_SRC_FILES += JNIEnvHandler.cpp
|
||||
LOCAL_SRC_FILES += MqttClient.cpp
|
||||
LOCAL_SRC_FILES += RespJson.cpp
|
||||
|
||||
# link lib
|
||||
LOCAL_STATIC_LIBRARIES := ssl ssl_crypto
|
||||
|
||||
# module name
|
||||
LOCAL_MODULE := mqtt
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
@ -1,5 +0,0 @@
|
||||
APP_OPTIM := release
|
||||
APP_ABI := armeabi-v7a x86 arm64-v8a
|
||||
APP_STL := c++_static
|
||||
APP_PLATFORM := android-23
|
||||
APP_PIE := false
|
@ -1,117 +0,0 @@
|
||||
//
|
||||
// Created by Key.Yao on 2020-02-20.
|
||||
//
|
||||
|
||||
#include "JNIEnvHandler.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct ThreadMessage {
|
||||
ThreadMessage(int i, void* m, bool flag) {
|
||||
what = i;
|
||||
msg = m;
|
||||
exit = flag;
|
||||
}
|
||||
int what;
|
||||
void* msg;
|
||||
bool exit;
|
||||
};
|
||||
|
||||
JNIEnvHandler::JNIEnvHandler(const char *threadName) {
|
||||
_threadName = threadName;
|
||||
_thread = nullptr;
|
||||
_exitFlag = false;
|
||||
_vm = nullptr;
|
||||
_callback = nullptr;
|
||||
}
|
||||
|
||||
JNIEnvHandler::~JNIEnvHandler() {
|
||||
_thread = nullptr;
|
||||
_callback = nullptr;
|
||||
_instance = nullptr;
|
||||
_vm = nullptr;
|
||||
}
|
||||
|
||||
bool JNIEnvHandler::init(JavaVM *vm, jobject instance, handleMessage callback) {
|
||||
if (!_thread) {
|
||||
_thread = new thread(&JNIEnvHandler::process, this);
|
||||
}
|
||||
_vm = vm;
|
||||
_instance = instance;
|
||||
_callback = callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
void JNIEnvHandler::exit() {
|
||||
if (!_thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *msg = new ThreadMessage(-1, nullptr, true);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(_mutex);
|
||||
_queue.push(msg);
|
||||
_cv.notify_one();
|
||||
}
|
||||
|
||||
_thread->join();
|
||||
delete _thread;
|
||||
_thread = nullptr;
|
||||
_exitFlag = true;
|
||||
}
|
||||
|
||||
std::thread::id JNIEnvHandler::getThreadId() {
|
||||
return _thread->get_id();
|
||||
}
|
||||
|
||||
void JNIEnvHandler::post(int what, void *obj) {
|
||||
auto *msg = new ThreadMessage(what, obj, false);
|
||||
unique_lock<mutex> lock(_mutex);
|
||||
_queue.push(msg);
|
||||
_cv.notify_one();
|
||||
}
|
||||
|
||||
void JNIEnvHandler::process() {
|
||||
_exitFlag = false;
|
||||
|
||||
JNIEnv *env = nullptr;
|
||||
if (_vm) {
|
||||
_vm->AttachCurrentThread(&env, nullptr);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
ThreadMessage *msg = nullptr;
|
||||
{
|
||||
unique_lock<mutex> lock(_mutex);
|
||||
while (_queue.empty()) {
|
||||
_cv.wait(lock);
|
||||
}
|
||||
|
||||
if (_queue.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
msg = _queue.front();
|
||||
_queue.pop();
|
||||
|
||||
}
|
||||
|
||||
if (msg->exit) {
|
||||
delete msg;
|
||||
break;
|
||||
}
|
||||
|
||||
if (env && _instance) {
|
||||
_callback(msg->what, msg->msg, env, _instance);
|
||||
}
|
||||
|
||||
delete msg;
|
||||
}
|
||||
|
||||
env->DeleteGlobalRef(_instance);
|
||||
|
||||
if (_vm) {
|
||||
_vm->DetachCurrentThread();
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
//
|
||||
// Created by Key.Yao on 2020-02-20.
|
||||
//
|
||||
|
||||
#ifndef MQTT_CLIENT_ANDROID_JNIENVHANDLER_H
|
||||
#define MQTT_CLIENT_ANDROID_JNIENVHANDLER_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
|
||||
typedef void(*handleMessage)(int what, void* obj, JNIEnv *env, jobject instance);
|
||||
|
||||
struct ThreadMessage;
|
||||
|
||||
class JNIEnvHandler {
|
||||
|
||||
public:
|
||||
JNIEnvHandler(const char* threadName);
|
||||
|
||||
~JNIEnvHandler();
|
||||
|
||||
bool init(JavaVM *vm, jobject instance, handleMessage callback);
|
||||
|
||||
void exit();
|
||||
|
||||
std::thread::id getThreadId();
|
||||
|
||||
void post(int what, void *obj = nullptr);
|
||||
|
||||
|
||||
private:
|
||||
JNIEnvHandler(const JNIEnvHandler&);
|
||||
JNIEnvHandler&operator=(const JNIEnvHandler&);
|
||||
|
||||
void process();
|
||||
|
||||
JavaVM *_vm;
|
||||
jobject _instance;
|
||||
std::thread *_thread;
|
||||
std::queue<ThreadMessage*> _queue;
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _cv;
|
||||
std::atomic<bool> _exitFlag;
|
||||
handleMessage _callback;
|
||||
const char* _threadName;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //MQTT_CLIENT_ANDROID_JNIENVHANDLER_H
|
@ -1,635 +0,0 @@
|
||||
//
|
||||
// Created by Key.Yao on 2020-02-20.
|
||||
//
|
||||
|
||||
#include "MqttClient.h"
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "mosquitto_wrapper.h"
|
||||
#include "JNIEnvHandler.h"
|
||||
|
||||
#define ALOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "MqttClientJNI", __VA_ARGS__))
|
||||
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(A) (void)(A)
|
||||
#endif
|
||||
|
||||
#ifndef NELEM
|
||||
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
|
||||
#endif
|
||||
|
||||
#ifndef MQTTCLIENT_JNICALL
|
||||
#define MQTTCLIENT_JNICALL
|
||||
#endif
|
||||
|
||||
#define TYPE_ON_MESSAGE 1
|
||||
#define TYPE_ON_CONNECT 2
|
||||
#define TYPE_ON_CONNECT_WITH_FLAG 3
|
||||
#define TYPE_ON_DISCONNECT 4
|
||||
#define TYPE_ON_PUBLISH 5
|
||||
#define TYPE_ON_SUBSCRIBE 6
|
||||
#define TYPE_ON_UNSUBSCRIBE 7
|
||||
#define TYPE_ON_LOG 8
|
||||
|
||||
using namespace std;
|
||||
using namespace mqttclient;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// thread callback method define
|
||||
void* mqtt_thread(void *p);
|
||||
void* mqtt_reconnect_thread(void *p);
|
||||
|
||||
// mosquitto callback method define
|
||||
void mqtt_on_message(void *instance, const struct mosquitto_message *message);
|
||||
void mqtt_on_connect(void *instance, int rc);
|
||||
void mqtt_on_connect_with_flag(void *instance, int rc, int flags);
|
||||
void mqtt_on_disconnect(void *instance, int rc);
|
||||
void mqtt_on_publish(void *instance, int rc);
|
||||
void mqtt_on_subscribe(void *instance, int mid, int qos_count, const int *granted_qos);
|
||||
void mqtt_on_unsubscribe(void *instance, int rc);
|
||||
void mqtt_on_log(void *instance, int level, const char *str);
|
||||
|
||||
// callback to java define
|
||||
void callback2Java(int what, void* obj, JNIEnv *env, jobject instance);
|
||||
|
||||
// jni method define
|
||||
jlong MQTTCLIENT_JNICALL mqtt_native_init(JNIEnv *env, jobject instance, jstring hostString, jint portInt, jstring uuidString, jboolean clearSession, jboolean isTLS, jstring caFilePathString, jstring usernameString, jstring passwordString);
|
||||
void MQTTCLIENT_JNICALL mqtt_native_start(JNIEnv *env, jobject instance, jlong ptr);
|
||||
void MQTTCLIENT_JNICALL mqtt_native_reconnect(JNIEnv *env, jobject instance, jlong ptr);
|
||||
void MQTTCLIENT_JNICALL mqtt_native_subscribe(JNIEnv *env, jobject instance, jlong ptr, jobjectArray topicJArray, jintArray qosJArray);
|
||||
void MQTTCLIENT_JNICALL mqtt_native_unsubscribe(JNIEnv *env, jobject instance, jlong ptr, jobjectArray topicJArray);
|
||||
void MQTTCLIENT_JNICALL mqtt_native_publish(JNIEnv *env, jobject instance, jlong ptr, jstring topicString, jstring messageString, jint qosInt);
|
||||
JNINativeMethod mqtt_methods[] = {
|
||||
{
|
||||
"_init",
|
||||
"(Ljava/lang/String;ILjava/lang/String;ZZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
|
||||
(void*) mqtt_native_init
|
||||
},
|
||||
{
|
||||
"_start",
|
||||
"(J)V",
|
||||
(void*) mqtt_native_start
|
||||
},
|
||||
{
|
||||
"_reconnect",
|
||||
"(J)V",
|
||||
(void*) mqtt_native_reconnect
|
||||
},
|
||||
{
|
||||
"_subscribe",
|
||||
"(J[Ljava/lang/String;[I)V",
|
||||
(void*) mqtt_native_subscribe
|
||||
},
|
||||
{
|
||||
"_unsubscribe",
|
||||
"(J[Ljava/lang/String;)V",
|
||||
(void*) mqtt_native_unsubscribe
|
||||
},
|
||||
{
|
||||
"_publish",
|
||||
"(JLjava/lang/String;Ljava/lang/String;I)V",
|
||||
(void*) mqtt_native_publish
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class ExtraData {
|
||||
public:
|
||||
string *host = nullptr;
|
||||
int port = 0;
|
||||
JNIEnvHandler *handler = nullptr;
|
||||
JavaVM *javaVM = nullptr;
|
||||
bool exitFlag = false;
|
||||
bool running = false;
|
||||
pthread_mutex_t mutexReconnect;
|
||||
};
|
||||
|
||||
class MqttMsg {
|
||||
public:
|
||||
string *topic = nullptr;
|
||||
string *payload = nullptr;
|
||||
};
|
||||
|
||||
class MqttConnectFlag {
|
||||
public:
|
||||
int flags = 0;
|
||||
};
|
||||
|
||||
class MqttLog {
|
||||
public:
|
||||
string *str = nullptr;
|
||||
int level = 0;
|
||||
};
|
||||
|
||||
static JavaVM *mVM;
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
UNUSED(reserved);
|
||||
|
||||
mVM = vm;
|
||||
JNIEnv *env = nullptr;
|
||||
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
jclass clazz = env->FindClass("moe/key/yao/mqtt/library/MqttClient");
|
||||
if (clazz == nullptr) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
if (env->RegisterNatives(clazz, mqtt_methods, NELEM(mqtt_methods)) < 0) {
|
||||
env->DeleteLocalRef(clazz);
|
||||
return JNI_ERR;
|
||||
} else {
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
|
||||
// lib init
|
||||
mqttclient::lib_init();
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
UNUSED(vm);
|
||||
UNUSED(reserved);
|
||||
|
||||
// lib clean up
|
||||
mqttclient::lib_cleanup();
|
||||
}
|
||||
|
||||
|
||||
// jni method
|
||||
jlong MQTTCLIENT_JNICALL mqtt_native_init(JNIEnv *env, jobject instance, jstring hostString, jint portInt, jstring uuidString, jboolean clearSession, jboolean isTLS, jstring caFilePathString, jstring usernameString, jstring passwordString) {
|
||||
const char *host = env->GetStringUTFChars(hostString, nullptr);
|
||||
const char *uuid = env->GetStringUTFChars(uuidString, nullptr);
|
||||
const char *caFilePath = env->GetStringUTFChars(caFilePathString, nullptr);
|
||||
const char *username = env->GetStringUTFChars(usernameString, nullptr);
|
||||
const char *password = env->GetStringUTFChars(passwordString, nullptr);
|
||||
|
||||
bool sessionFlag = clearSession != 0;
|
||||
auto *mosq = new mosquitto_wrapper(uuid, sessionFlag);
|
||||
|
||||
mosq->on_connect_callback = mqtt_on_connect;
|
||||
mosq->on_connect_with_flag_callback = mqtt_on_connect_with_flag;
|
||||
mosq->on_disconnect_callback = mqtt_on_disconnect;
|
||||
mosq->on_publish_callback = mqtt_on_publish;
|
||||
mosq->on_message_callback = mqtt_on_message;
|
||||
mosq->on_subscribe_callback = mqtt_on_subscribe;
|
||||
mosq->on_unsubscribe_callback = mqtt_on_unsubscribe;
|
||||
mosq->on_log_callback = mqtt_on_log;
|
||||
|
||||
|
||||
if (isTLS) {
|
||||
mosq->tls_insecure_set(true);
|
||||
mosq->tls_opts_set(1, "tlsv1", nullptr);
|
||||
if (strlen(caFilePath) != 0) {
|
||||
mosq->tls_set(caFilePath);
|
||||
}
|
||||
if (strlen(username) != 0 && strlen(password) != 0) {
|
||||
mosq->username_pw_set(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
auto *extra = new ExtraData();
|
||||
|
||||
extra->host = new string(host);
|
||||
extra->port = portInt;
|
||||
extra->javaVM = mVM;
|
||||
|
||||
extra->handler = new JNIEnvHandler("callback");
|
||||
extra->handler->init(mVM, env->NewGlobalRef(instance), callback2Java);
|
||||
|
||||
pthread_mutex_init(&extra->mutexReconnect, nullptr);
|
||||
|
||||
mosq->extra = extra;
|
||||
|
||||
env->ReleaseStringUTFChars(hostString, host);
|
||||
env->ReleaseStringUTFChars(caFilePathString, caFilePath);
|
||||
env->ReleaseStringUTFChars(uuidString, uuid);
|
||||
|
||||
return reinterpret_cast<jlong>(mosq);
|
||||
}
|
||||
|
||||
void MQTTCLIENT_JNICALL mqtt_native_start(JNIEnv *env, jobject instance, jlong ptr) {
|
||||
UNUSED(env);
|
||||
UNUSED(instance);
|
||||
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(ptr);
|
||||
if (!mosq) {
|
||||
return;
|
||||
}
|
||||
auto *extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->running) {
|
||||
pthread_t tid;
|
||||
pthread_create(&tid, nullptr, mqtt_thread, mosq);
|
||||
pthread_detach(tid);
|
||||
} else {
|
||||
// running
|
||||
ALOG("mqtt thread running");
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTCLIENT_JNICALL mqtt_native_reconnect(JNIEnv *env, jobject instance, jlong ptr) {
|
||||
UNUSED(env);
|
||||
UNUSED(instance);
|
||||
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(ptr);
|
||||
if (!mosq) {
|
||||
return;
|
||||
}
|
||||
pthread_t tid;
|
||||
pthread_create(&tid, nullptr, mqtt_reconnect_thread, mosq);
|
||||
pthread_detach(tid);
|
||||
}
|
||||
|
||||
void MQTTCLIENT_JNICALL mqtt_native_subscribe(JNIEnv *env, jobject instance, jlong ptr, jobjectArray topicJArray, jintArray qosJArray) {
|
||||
UNUSED(instance);
|
||||
|
||||
jint arrayLen = env->GetArrayLength(topicJArray);
|
||||
jint* qosList = env->GetIntArrayElements(qosJArray, nullptr);
|
||||
string *topics[arrayLen];
|
||||
|
||||
for (int i = 0; i < arrayLen; i++) {
|
||||
auto itemString = (jstring) env->GetObjectArrayElement(topicJArray, i);
|
||||
const char *item = env->GetStringUTFChars(itemString, nullptr);
|
||||
topics[i] = new string(item);
|
||||
env->ReleaseStringUTFChars(itemString, item);
|
||||
}
|
||||
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(ptr);
|
||||
for (int i = 0 ; i < arrayLen; i ++) {
|
||||
int mid;
|
||||
mosq->subscribe(&mid, topics[i]->c_str(), qosList[i]);
|
||||
delete topics[i];
|
||||
topics[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTCLIENT_JNICALL mqtt_native_unsubscribe(JNIEnv *env, jobject instance, jlong ptr, jobjectArray topicJArray) {
|
||||
UNUSED(instance);
|
||||
|
||||
jint arrayLen = env->GetArrayLength(topicJArray);
|
||||
string *topics[arrayLen];
|
||||
|
||||
for (int i = 0; i < arrayLen; i++) {
|
||||
auto itemString = (jstring) env->GetObjectArrayElement(topicJArray, i);
|
||||
const char *item = env->GetStringUTFChars(itemString, nullptr);
|
||||
topics[i] = new string(item);
|
||||
env->ReleaseStringUTFChars(itemString, item);
|
||||
}
|
||||
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(ptr);
|
||||
for (int i = 0 ; i < arrayLen; i ++) {
|
||||
int mid;
|
||||
mosq->unsubscribe(&mid, topics[i]->c_str());
|
||||
delete topics[i];
|
||||
topics[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTCLIENT_JNICALL mqtt_native_publish(JNIEnv *env, jobject instance, jlong ptr, jstring topicString, jstring messageString, jint qosInt) {
|
||||
UNUSED(instance);
|
||||
|
||||
const char *topic = env->GetStringUTFChars(topicString, nullptr);
|
||||
const char *message = env->GetStringUTFChars(messageString, nullptr);
|
||||
|
||||
// publish
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(ptr);
|
||||
mosq->publish(nullptr, topic, (int) strlen(message), message, qosInt);
|
||||
|
||||
// release string
|
||||
env->ReleaseStringUTFChars(topicString, topic);
|
||||
env->ReleaseStringUTFChars(messageString, message);
|
||||
}
|
||||
|
||||
// thread callback method
|
||||
void* mqtt_thread(void *p) {
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(p);
|
||||
if (!mosq) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv *env;
|
||||
extra->javaVM->AttachCurrentThread(&env, nullptr);
|
||||
|
||||
extra->running = true;
|
||||
|
||||
mosq->connect(extra->host->c_str(), extra->port);
|
||||
|
||||
while (true) {
|
||||
int rc = mosq->loop();
|
||||
if (extra->exitFlag) {
|
||||
break;
|
||||
}
|
||||
if (rc != MOSQ_ERR_SUCCESS) {
|
||||
// error
|
||||
const char *errorMsg = mqttclient::strerror(rc);
|
||||
ALOG("mqtt connect error ========>> %s", errorMsg);
|
||||
}
|
||||
if (rc) {
|
||||
sleep(10);
|
||||
mosq->reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
extra->javaVM->DetachCurrentThread();
|
||||
|
||||
extra->running = false;
|
||||
|
||||
pthread_mutex_destroy(&extra->mutexReconnect);
|
||||
|
||||
extra->javaVM = nullptr;
|
||||
delete extra->host;
|
||||
|
||||
extra->handler->exit();
|
||||
delete extra->handler;
|
||||
extra->handler = nullptr;
|
||||
|
||||
delete extra;
|
||||
mosq->extra = nullptr;
|
||||
|
||||
delete mosq;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* mqtt_reconnect_thread(void *p) {
|
||||
auto *mosq = reinterpret_cast<mosquitto_wrapper*>(p);
|
||||
if (!mosq) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return nullptr;
|
||||
}
|
||||
pthread_mutex_lock(&extra->mutexReconnect);
|
||||
mosq->disconnect();
|
||||
pthread_mutex_unlock(&extra->mutexReconnect);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// mosquitto callback method define
|
||||
void mqtt_on_message(void *instance, const struct mosquitto_message *message) {
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto msg = new MqttMsg();
|
||||
msg->topic = new string(message->topic);
|
||||
msg->payload = new string(reinterpret_cast<char*>(message->payload));
|
||||
|
||||
extra->handler->post(TYPE_ON_MESSAGE, msg);
|
||||
}
|
||||
|
||||
void mqtt_on_connect(void *instance, int rc) {
|
||||
UNUSED(rc);
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
extra->handler->post(TYPE_ON_CONNECT);
|
||||
}
|
||||
|
||||
void mqtt_on_connect_with_flag(void *instance, int rc, int flags) {
|
||||
UNUSED(rc);
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
auto connectFlag = new MqttConnectFlag();
|
||||
connectFlag->flags = flags;
|
||||
extra->handler->post(TYPE_ON_CONNECT_WITH_FLAG, connectFlag);
|
||||
}
|
||||
|
||||
void mqtt_on_disconnect(void *instance, int rc) {
|
||||
UNUSED(rc);
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
extra->handler->post(TYPE_ON_DISCONNECT);
|
||||
}
|
||||
|
||||
void mqtt_on_publish(void *instance, int rc) {
|
||||
UNUSED(rc);
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
extra->handler->post(TYPE_ON_PUBLISH);
|
||||
}
|
||||
|
||||
void mqtt_on_subscribe(void *instance, int mid, int qos_count, const int *granted_qos) {
|
||||
UNUSED(mid);
|
||||
UNUSED(qos_count);
|
||||
UNUSED(granted_qos);
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
extra->handler->post(TYPE_ON_SUBSCRIBE);
|
||||
}
|
||||
|
||||
void mqtt_on_unsubscribe(void *instance, int rc) {
|
||||
UNUSED(rc);
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
extra->handler->post(TYPE_ON_UNSUBSCRIBE);
|
||||
}
|
||||
|
||||
void mqtt_on_log(void *instance, int level, const char *str) {
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
auto mosq = reinterpret_cast<mosquitto_wrapper*>(instance);
|
||||
if (!mosq->extra) {
|
||||
return;
|
||||
}
|
||||
auto extra = reinterpret_cast<ExtraData*>(mosq->extra);
|
||||
if (!extra) {
|
||||
return;
|
||||
}
|
||||
if (!extra->handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto log = new MqttLog();
|
||||
log->level = level;
|
||||
log->str = new string(str);
|
||||
extra->handler->post(TYPE_ON_LOG, log);
|
||||
}
|
||||
|
||||
|
||||
// callback to java
|
||||
void callback2Java(int what, void* obj, JNIEnv *env, jobject instance) {
|
||||
auto clazz = env->GetObjectClass(instance);
|
||||
jmethodID methodId = nullptr;
|
||||
|
||||
switch (what) {
|
||||
case TYPE_ON_MESSAGE: {
|
||||
if (!obj) {
|
||||
break;
|
||||
}
|
||||
methodId = env->GetMethodID(clazz, "onMessage", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
auto msg = reinterpret_cast<MqttMsg*>(obj);
|
||||
jstring topicString = env->NewStringUTF(msg->topic->c_str());
|
||||
jstring payloadString = env->NewStringUTF(msg->payload->c_str());
|
||||
env->CallVoidMethod(instance, methodId, topicString, payloadString);
|
||||
env->DeleteLocalRef(topicString);
|
||||
env->DeleteLocalRef(payloadString);
|
||||
delete msg->topic;
|
||||
delete msg->payload;
|
||||
delete msg;
|
||||
break;
|
||||
};
|
||||
case TYPE_ON_CONNECT: {
|
||||
methodId = env->GetMethodID(clazz, "onConnect", "()V");
|
||||
env->CallVoidMethod(instance, methodId);
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_CONNECT_WITH_FLAG: {
|
||||
methodId = env->GetMethodID(clazz, "onConnectWithFlag", "(I)V");
|
||||
auto log = reinterpret_cast<MqttConnectFlag*>(obj);
|
||||
int flags = log->flags;
|
||||
env->CallVoidMethod(instance, methodId, flags);
|
||||
delete log;
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_DISCONNECT: {
|
||||
methodId = env->GetMethodID(clazz, "onDisconnect", "()V");
|
||||
env->CallVoidMethod(instance, methodId);
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_PUBLISH: {
|
||||
methodId = env->GetMethodID(clazz, "onPublish", "()V");
|
||||
env->CallVoidMethod(instance, methodId);
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_SUBSCRIBE: {
|
||||
methodId = env->GetMethodID(clazz, "onSubscribe", "()V");
|
||||
env->CallVoidMethod(instance, methodId);
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_UNSUBSCRIBE: {
|
||||
methodId = env->GetMethodID(clazz, "onUnsubscribe", "()V");
|
||||
env->CallVoidMethod(instance, methodId);
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_LOG: {
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
methodId = env->GetMethodID(clazz, "onLog", "(ILjava/lang/String;)V");
|
||||
auto log = reinterpret_cast<MqttLog*>(obj);
|
||||
jstring msgString = env->NewStringUTF(log->str->c_str());
|
||||
env->CallVoidMethod(instance, methodId, log->level, msgString);
|
||||
env->DeleteLocalRef(msgString);
|
||||
delete log->str;
|
||||
delete log;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
//
|
||||
// Created by Key.Yao on 2020-02-20.
|
||||
//
|
||||
|
||||
#ifndef MQTT_CLIENT_ANDROID_MQTTCLIENT_H
|
||||
#define MQTT_CLIENT_ANDROID_MQTTCLIENT_H
|
||||
|
||||
|
||||
class MqttClient {
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //MQTT_CLIENT_ANDROID_MQTTCLIENT_H
|
@ -1,331 +0,0 @@
|
||||
#include <RespJson.h>
|
||||
|
||||
bool RespJson::RespManage(char* str, string jsonStr)
|
||||
{
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
string serviceId;
|
||||
if (reader.parse(str, root))
|
||||
{
|
||||
serviceId = root["serviceId"].asString();
|
||||
}
|
||||
if(serviceId == "platformupgradeDevices" || serviceId == "platformLsuueConfigureFile" || serviceId == "getDeviceLogFile"
|
||||
|| serviceId == "getDeviceData" || serviceId == "setDeviceTime" || serviceId == "setTransOnlineMonitConfig"
|
||||
|| serviceId == "setFunctionConfiguration" || serviceId == "setIcingOnlineAlarmMonitConfig" || serviceId == "setPhotoParams"
|
||||
|| serviceId == "SetAcceptCameraPhoto" || serviceId == "setCaptureTimesTaskParameter" || serviceId == "actionRestart"
|
||||
|| serviceId == "cameraRemoteControl" || serviceId == "manualCapturePicture" || serviceId == "setMicroMeteorologicalAlarm")
|
||||
{
|
||||
jsonStr = CommonResp(str);
|
||||
}else if(serviceId == "getDeviceLogList")
|
||||
{
|
||||
// getDeviceLogListResp
|
||||
}
|
||||
// else if...
|
||||
}
|
||||
|
||||
string RespJson::CommonResp(char* str)
|
||||
{
|
||||
Json::Reader reader;
|
||||
Json::Value root;
|
||||
int mid;
|
||||
if (reader.parse(str, root))
|
||||
{
|
||||
mid = root["mid"].asInt();
|
||||
}
|
||||
string jsonStr;
|
||||
CommonJSON(jsonStr, 0, 0, mid);
|
||||
return jsonStr;
|
||||
}
|
||||
|
||||
bool RespJson::CommonJSON(string jsonStr, int resultCode, int errcode, int mid)
|
||||
{
|
||||
/*通用响应JSON*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["resultCode"] = resultCode;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getDeviceLogListJSON(string jsonStr,DeviceLogList_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*查询终端设备日志列表*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["resultCode"] = bodyData.resultCode;
|
||||
body["fileCount"] = bodyData.fileCount;
|
||||
Json::Value List;
|
||||
for(int i = 0; i < bodyData.fileCount; i++)
|
||||
{
|
||||
Json::Value ListData;
|
||||
ListData["fileType"] = bodyData.fileList[i].fileType;
|
||||
ListData["fileName"] = bodyData.fileList[i].fileName;
|
||||
ListData["time"] = static_cast<Json::Int64>(bodyData.fileList[i].time);
|
||||
ListData["fileSize"] = bodyData.fileList[i].fileSize;
|
||||
List.append(ListData);
|
||||
}
|
||||
body["fileList"] = List;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getDeviceTimeJSON(string jsonStr,DeviceTime_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*平台端查询终端设备的系统时间*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["timingType"] = bodyData.timingType;
|
||||
body["currentTime"] = static_cast<Json::Int64>(bodyData.currentTime);
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getTransOnlineMonitConfigJSON(string jsonStr,TransOnlineMonitConfig_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*获取输电在线监测终端的运行状态参数*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["heartbeatInterval"] = bodyData.heartbeatInterval;
|
||||
body["sampleInterval"] = bodyData.sampleInterval;
|
||||
body["sleepDuration"] = bodyData.sleepDuration;
|
||||
body["onlineInterval"] = bodyData.onlineInterval;
|
||||
Json::Value List;
|
||||
for(int i = 0; i < 29; i++)
|
||||
{
|
||||
Json::Value ListData;
|
||||
ListData["day"] = bodyData.restartTime[i].day;
|
||||
ListData["hour"] = bodyData.restartTime[i].hour;
|
||||
ListData["minute"] = bodyData.restartTime[i].minute;
|
||||
List.append(ListData);
|
||||
}
|
||||
body["restartTime"] = List;
|
||||
body["ipAddr"] = bodyData.ipAddr;
|
||||
body["port"] = bodyData.port;
|
||||
body["httpIp"] = bodyData.httpIp;
|
||||
body["httpPort"] = bodyData.httpPort;
|
||||
body["PwrMode"] = bodyData.PwrMode;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getFunctionConfigurationJSON(string jsonStr,FunctionConfiguration_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*获取装置功能配置*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
Json::Value List;
|
||||
Json::Value ListData;
|
||||
ListData["function"] = bodyData.function;
|
||||
ListData["mode"] = bodyData.mode;
|
||||
List.append(ListData);
|
||||
body["configure"] = List;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getIcingOnlineAlarmMonitConfigJSON(string jsonStr,IcingOnlineAlarmMonitConfig_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*获取设置覆冰在线监测终端的告警阈*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["resultCode"] = bodyData.resultCode;
|
||||
body["fileCount"] = bodyData.interval;
|
||||
body["PullAAlarmThreshold"] = bodyData.PullAAlarmThreshold;
|
||||
body["windAlarmThreshold"] = bodyData.windAlarmThreshold;
|
||||
body["rainAlarmThreshold"] = bodyData.rainAlarmThreshold;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getPhotoParamsJSON(string jsonStr,PhotoParams_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*平台端查询终端设备图片配置信息*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["channel"] = bodyData.channel;
|
||||
body["color"] = bodyData.color;
|
||||
body["brightness"] = bodyData.brightness;
|
||||
body["contrast"] = bodyData.contrast;
|
||||
body["saturation"] = bodyData.saturation;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getCaptureTimesTaskInformationJSON(string jsonStr,CaptureTimesTask_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*平台端查询终端设备定时抓拍任务信息*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["channel"] = bodyData.channel;
|
||||
body["color"] = bodyData.groupNumber;
|
||||
Json::Value array;
|
||||
body["paramArray"] = array;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getDeviceSolarPowerPropertiesJSON(string jsonStr,DeviceSolarPower_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*查询设备太阳能电池板状态数据*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["batteryNumber"] = bodyData.batteryNumber;
|
||||
body["time"] = static_cast<Json::Int64>(bodyData.time);
|
||||
body["solarPanelVoltage"] = bodyData.solarPanelVoltage;
|
||||
body["solarPanelCurrent"] = bodyData.solarPanelCurrent;
|
||||
body["batteryVoltage"] = bodyData.batteryVoltage;
|
||||
body["batteryCurrent"] = bodyData.batteryCurrent;
|
||||
body["loadVoltage"] = bodyData.loadVoltage;
|
||||
body["loadCurrent"] = bodyData.loadCurrent;
|
||||
body["remainingBatteryPower"] = bodyData.remainingBatteryPower;
|
||||
body["batteryTemperature"] = bodyData.batteryTemperature;
|
||||
body["batteryChargeStatus"] = bodyData.batteryChargeStatus;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getWeatherMonitoringJSON(string jsonStr,Weather_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*查询终端微气象数据*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["resultCode"] = bodyData.resultCode;
|
||||
body["fileCount"] = bodyData.packageNum;
|
||||
Json::Value List;
|
||||
for(int i = 0; i < bodyData.packageNum; i++)
|
||||
{
|
||||
Json::Value ListData;
|
||||
ListData["time"] = static_cast<Json::Int64>(bodyData.fileList[i].time);
|
||||
ListData["Temperature"] = bodyData.fileList[i].Temperature;
|
||||
ListData["humidity"] = bodyData.fileList[i].humidity;
|
||||
ListData["airPressure"] = bodyData.fileList[i].airPressure;
|
||||
ListData["instanWindSpeed"] = bodyData.fileList[i].instanWindSpeed;
|
||||
ListData["aveWindSspeed1"] = bodyData.fileList[i].aveWindSspeed1;
|
||||
ListData["aveWindSspeed10"] = bodyData.fileList[i].aveWindSspeed10;
|
||||
ListData["maxWindSpeed10"] = bodyData.fileList[i].maxWindSpeed10;
|
||||
ListData["aveMaxWindSpeed10"] = bodyData.fileList[i].aveMaxWindSpeed10;
|
||||
ListData["extremeWindSpeed"] = bodyData.fileList[i].extremeWindSpeed;
|
||||
ListData["instanWindDirection"] = bodyData.fileList[i].instanWindDirection;
|
||||
ListData["aveWindDirection1"] = bodyData.fileList[i].aveWindDirection1;
|
||||
ListData["aveWindDirection10"] = bodyData.fileList[i].aveWindDirection10;
|
||||
ListData["extremeWindDirection"] = bodyData.fileList[i].extremeWindDirection;
|
||||
ListData["radiationIntensity"] = bodyData.fileList[i].radiationIntensity;
|
||||
ListData["precipitation1"] = bodyData.fileList[i].precipitation1;
|
||||
ListData["precipitation6"] = bodyData.fileList[i].precipitation6;
|
||||
ListData["precipitation12"] = bodyData.fileList[i].precipitation12;
|
||||
ListData["precipitation24"] = bodyData.fileList[i].precipitation24;
|
||||
List.append(ListData);
|
||||
}
|
||||
body["dataList"] = List;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getPullAndAngleMonitoringJSON(string jsonStr,PullAndAngle_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*查询终端拉力倾角监测*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["resultCode"] = bodyData.resultCode;
|
||||
body["type"] = bodyData.type;
|
||||
body["number"] = bodyData.number;
|
||||
Json::Value List;
|
||||
for(int i = 0; i < bodyData.number; i++)
|
||||
{
|
||||
Json::Value ListData;
|
||||
ListData["time"] = static_cast<Json::Int64>(bodyData.fileList[i].time);
|
||||
ListData["maxPull"] = bodyData.fileList[i].maxPull;
|
||||
ListData["fileName"] = bodyData.fileList[i].maxPullOblique;
|
||||
ListData["maxPullOblique"] = bodyData.fileList[i].maxPullWind;
|
||||
ListData["equalIceThickness"] = bodyData.fileList[i].equalIceThickness;
|
||||
List.append(ListData);
|
||||
}
|
||||
body["dataList"] = List;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RespJson::getMicroMeteorologicalAlarmJSON(string jsonStr,Alarm_JSON bodyData, int errcode, int mid)
|
||||
{
|
||||
/*查询终端设备的微气象告警阈值*/
|
||||
Json::Value root;
|
||||
Json::Value body;
|
||||
body["level"] = bodyData.level;
|
||||
body["interval"] = bodyData.interval;
|
||||
body["windSpeedAlarm"] = bodyData.windSpeedAlarm;
|
||||
body["precipitationAlarm"] = bodyData.precipitationAlarm;
|
||||
root["body"] = body;
|
||||
root["errcode"] = errcode;
|
||||
root["mid"] = mid;
|
||||
root["msgType"] = "deviceRsp";
|
||||
|
||||
Json::StyledWriter writer;
|
||||
jsonStr = writer.write(root);
|
||||
return true;
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
#ifndef MQTT_CLIENT_ANDROID_RESPJSON_H
|
||||
#define MQTT_CLIENT_ANDROID_RESPJSON_H
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef struct DeviceLogList_JSON
|
||||
{
|
||||
int resultCode;
|
||||
int fileCount;
|
||||
struct file_List
|
||||
{
|
||||
int fileType;
|
||||
string fileName;
|
||||
time_t time;
|
||||
int fileSize;
|
||||
}fileList[1];
|
||||
};
|
||||
|
||||
typedef struct DeviceTime_JSON
|
||||
{
|
||||
int timingType;
|
||||
time_t currentTime;
|
||||
};
|
||||
|
||||
typedef struct TransOnlineMonitConfig_JSON
|
||||
{
|
||||
int heartbeatInterval;
|
||||
int sampleInterval;
|
||||
int sleepDuration;
|
||||
int onlineInterval;
|
||||
struct restart_Time
|
||||
{
|
||||
int day;
|
||||
int hour;
|
||||
int minute;
|
||||
}restartTime[29];
|
||||
string ipAddr;
|
||||
int port;
|
||||
string httpIp;
|
||||
int httpPort;
|
||||
int PwrMode;
|
||||
};
|
||||
typedef struct FunctionConfiguration_JSON
|
||||
{
|
||||
string function;
|
||||
int mode;
|
||||
};
|
||||
typedef struct IcingOnlineAlarmMonitConfig_JSON
|
||||
{
|
||||
int resultCode;
|
||||
int interval;
|
||||
float PullAAlarmThreshold;
|
||||
float windAlarmThreshold;
|
||||
float rainAlarmThreshold;
|
||||
};
|
||||
typedef struct PhotoParams_JSON
|
||||
{
|
||||
int channel;
|
||||
int color;
|
||||
int brightness;
|
||||
int contrast;
|
||||
int saturation;
|
||||
};
|
||||
typedef struct CaptureTimesTask_JSON
|
||||
{
|
||||
int channel;
|
||||
int groupNumber;
|
||||
};
|
||||
typedef struct DeviceSolarPower_JSON
|
||||
{
|
||||
int batteryNumber;
|
||||
time_t time;
|
||||
float solarPanelVoltage;
|
||||
float solarPanelCurrent;
|
||||
float batteryVoltage;
|
||||
float batteryCurrent;
|
||||
float loadVoltage;
|
||||
float loadCurrent;
|
||||
int remainingBatteryPower;
|
||||
float batteryTemperature;
|
||||
int batteryChargeStatus;
|
||||
};
|
||||
typedef struct Weather_JSON
|
||||
{
|
||||
int resultCode;
|
||||
int packageNum;
|
||||
struct file_List
|
||||
{
|
||||
time_t time;
|
||||
float Temperature;
|
||||
float humidity;
|
||||
float airPressure;
|
||||
float instanWindSpeed;
|
||||
float aveWindSspeed1;
|
||||
float aveWindSspeed10;
|
||||
float maxWindSpeed10;
|
||||
float aveMaxWindSpeed10;
|
||||
float extremeWindSpeed;
|
||||
float instanWindDirection;
|
||||
float aveWindDirection1;
|
||||
float aveWindDirection10;
|
||||
float extremeWindDirection;
|
||||
float radiationIntensity;
|
||||
float precipitation1;
|
||||
float precipitation6;
|
||||
float precipitation12;
|
||||
float precipitation24;
|
||||
}fileList[1];
|
||||
};
|
||||
typedef struct PullAndAngle_JSON
|
||||
{
|
||||
int resultCode;
|
||||
int type;
|
||||
int number;
|
||||
struct file_List
|
||||
{
|
||||
time_t time;
|
||||
float maxPull;
|
||||
float maxPullOblique;
|
||||
float maxPullWind;
|
||||
float equalIceThickness;
|
||||
}fileList[1];
|
||||
};
|
||||
typedef struct Alarm_JSON
|
||||
{
|
||||
int level;
|
||||
int interval;
|
||||
float windSpeedAlarm;
|
||||
float precipitationAlarm;
|
||||
};
|
||||
|
||||
class RespJson {
|
||||
bool RespManage(char* str, string jsonStr);
|
||||
string CommonResp(char* str);
|
||||
|
||||
|
||||
bool CommonJSON(string jsonStr, int resultCode, int errcode, int mid);
|
||||
bool getDeviceLogListJSON(string jsonStr,DeviceLogList_JSON bodyData, int errcode, int mid);
|
||||
bool getDeviceTimeJSON(string jsonStr,DeviceTime_JSON bodyData, int errcode, int mid);
|
||||
bool getTransOnlineMonitConfigJSON(string jsonStr,TransOnlineMonitConfig_JSON bodyData, int errcode, int mid);
|
||||
bool getFunctionConfigurationJSON(string jsonStr,FunctionConfiguration_JSON bodyData, int errcode, int mid);
|
||||
bool getIcingOnlineAlarmMonitConfigJSON(string jsonStr,IcingOnlineAlarmMonitConfig_JSON bodyData, int errcode, int mid);
|
||||
bool getPhotoParamsJSON(string jsonStr,PhotoParams_JSON bodyData, int errcode, int mid);
|
||||
bool getCaptureTimesTaskInformationJSON(string jsonStr,CaptureTimesTask_JSON bodyData, int errcode, int mid);
|
||||
bool getDeviceSolarPowerPropertiesJSON(string jsonStr,DeviceSolarPower_JSON bodyData, int errcode, int mid);
|
||||
bool getWeatherMonitoringJSON(string jsonStr,Weather_JSON bodyData, int errcode, int mid);
|
||||
bool getPullAndAngleMonitoringJSON(string jsonStr,PullAndAngle_JSON bodyData, int errcode, int mid);
|
||||
bool getMicroMeteorologicalAlarmJSON(string jsonStr,Alarm_JSON bodyData, int errcode, int mid);
|
||||
};
|
||||
|
||||
#endif //MQTT_CLIENT_ANDROID_RESPJSON_H
|
@ -1,89 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
||||
#define JSON_ALLOCATOR_H_INCLUDED
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
|
||||
namespace Json {
|
||||
template <typename T> class SecureAllocator {
|
||||
public:
|
||||
// Type definitions
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
/**
|
||||
* Allocate memory for N items using the standard allocator.
|
||||
*/
|
||||
pointer allocate(size_type n) {
|
||||
// allocate using "global operator new"
|
||||
return static_cast<pointer>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
*/
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an item in-place at pointer P.
|
||||
*/
|
||||
template <typename... Args> void construct(pointer p, Args&&... args) {
|
||||
// construct using "placement new" and "perfect forwarding"
|
||||
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
size_type max_size() const { return size_t(-1) / sizeof(T); }
|
||||
|
||||
pointer address(reference x) const { return std::addressof(x); }
|
||||
|
||||
const_pointer address(const_reference x) const { return std::addressof(x); }
|
||||
|
||||
/**
|
||||
* Destroy an item in-place at pointer P.
|
||||
*/
|
||||
void destroy(pointer p) {
|
||||
// destroy using "explicit destructor"
|
||||
p->~T();
|
||||
}
|
||||
|
||||
// Boilerplate
|
||||
SecureAllocator() {}
|
||||
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
||||
template <typename U> struct rebind { using other = SecureAllocator<U>; };
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // JSON_ALLOCATOR_H_INCLUDED
|
@ -1,61 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_ASSERTIONS_H_INCLUDED
|
||||
#define JSON_ASSERTIONS_H_INCLUDED
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
/** It should not be possible for a maliciously designed file to
|
||||
* cause an abort() or seg-fault, so these macros are used only
|
||||
* for pre-condition violations and internal logic errors.
|
||||
*/
|
||||
#if JSON_USE_EXCEPTION
|
||||
|
||||
// @todo <= add detail about condition in exception
|
||||
#define JSON_ASSERT(condition) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
Json::throwLogicError("assert json failed"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define JSON_FAIL_MESSAGE(message) \
|
||||
do { \
|
||||
OStringStream oss; \
|
||||
oss << message; \
|
||||
Json::throwLogicError(oss.str()); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
#else // JSON_USE_EXCEPTION
|
||||
|
||||
#define JSON_ASSERT(condition) assert(condition)
|
||||
|
||||
// The call to assert() will show the failure message in debug builds. In
|
||||
// release builds we abort, for a core-dump or debugger.
|
||||
#define JSON_FAIL_MESSAGE(message) \
|
||||
{ \
|
||||
OStringStream oss; \
|
||||
oss << message; \
|
||||
assert(false && oss.str().c_str()); \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define JSON_ASSERT_MESSAGE(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
JSON_FAIL_MESSAGE(message); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // JSON_ASSERTIONS_H_INCLUDED
|
@ -1,150 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
#define JSON_CONFIG_H_INCLUDED
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||
// assertion macros. The default is to use exceptions.
|
||||
#ifndef JSON_USE_EXCEPTION
|
||||
#define JSON_USE_EXCEPTION 1
|
||||
#endif
|
||||
|
||||
// Temporary, tracked for removal with issue #982.
|
||||
#ifndef JSON_USE_NULLREF
|
||||
#define JSON_USE_NULLREF 1
|
||||
#endif
|
||||
|
||||
/// If defined, indicates that the source file is amalgamated
|
||||
/// to prevent private header inclusion.
|
||||
/// Remarks: it is automatically defined in the generated amalgamated header.
|
||||
// #define JSON_IS_AMALGAMATION
|
||||
|
||||
// Export macros for DLL visibility
|
||||
#if defined(JSON_DLL_BUILD)
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define JSON_API __declspec(dllexport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define JSON_API __attribute__((visibility("default")))
|
||||
#endif // if defined(_MSC_VER)
|
||||
|
||||
#elif defined(JSON_DLL)
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define JSON_API __declspec(dllimport)
|
||||
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||
#endif // if defined(_MSC_VER)
|
||||
#endif // ifdef JSON_DLL_BUILD
|
||||
|
||||
#if !defined(JSON_API)
|
||||
#define JSON_API
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#error \
|
||||
"ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
// As recommended at
|
||||
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
|
||||
extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
|
||||
const char* format, ...);
|
||||
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
|
||||
#else
|
||||
#define jsoncpp_snprintf std::snprintf
|
||||
#endif
|
||||
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
|
||||
// integer
|
||||
// Storages, and 64 bits integer support is disabled.
|
||||
// #define JSON_NO_INT64 1
|
||||
|
||||
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
|
||||
// C++11 should be used directly in JSONCPP.
|
||||
#define JSONCPP_OVERRIDE override
|
||||
|
||||
#ifdef __clang__
|
||||
#if __has_extension(attribute_deprecated_with_message)
|
||||
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#endif
|
||||
#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
|
||||
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
||||
#endif // GNUC version
|
||||
#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates
|
||||
// MSVC)
|
||||
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||
#endif // __clang__ || __GNUC__ || _MSC_VER
|
||||
|
||||
#if !defined(JSONCPP_DEPRECATED)
|
||||
#define JSONCPP_DEPRECATED(message)
|
||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
|
||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||
#endif
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
#include "allocator.h"
|
||||
#include "version.h"
|
||||
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
using Int = int;
|
||||
using UInt = unsigned int;
|
||||
#if defined(JSON_NO_INT64)
|
||||
using LargestInt = int;
|
||||
using LargestUInt = unsigned int;
|
||||
#undef JSON_HAS_INT64
|
||||
#else // if defined(JSON_NO_INT64)
|
||||
// For Microsoft Visual use specific types as long long is not supported
|
||||
#if defined(_MSC_VER) // Microsoft Visual Studio
|
||||
using Int64 = __int64;
|
||||
using UInt64 = unsigned __int64;
|
||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
using Int64 = int64_t;
|
||||
using UInt64 = uint64_t;
|
||||
#endif // if defined(_MSC_VER)
|
||||
using LargestInt = Int64;
|
||||
using LargestUInt = UInt64;
|
||||
#define JSON_HAS_INT64
|
||||
#endif // if defined(JSON_NO_INT64)
|
||||
|
||||
template <typename T>
|
||||
using Allocator =
|
||||
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
|
||||
std::allocator<T>>::type;
|
||||
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
||||
using IStringStream =
|
||||
std::basic_istringstream<String::value_type, String::traits_type,
|
||||
String::allocator_type>;
|
||||
using OStringStream =
|
||||
std::basic_ostringstream<String::value_type, String::traits_type,
|
||||
String::allocator_type>;
|
||||
using IStream = std::istream;
|
||||
using OStream = std::ostream;
|
||||
} // namespace Json
|
||||
|
||||
// Legacy names (formerly macros).
|
||||
using JSONCPP_STRING = Json::String;
|
||||
using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
|
||||
using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
|
||||
using JSONCPP_ISTREAM = Json::IStream;
|
||||
using JSONCPP_OSTREAM = Json::OStream;
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||
#define JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
// writer.h
|
||||
class StreamWriter;
|
||||
class StreamWriterBuilder;
|
||||
class Writer;
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
class StyledStreamWriter;
|
||||
|
||||
// reader.h
|
||||
class Reader;
|
||||
class CharReader;
|
||||
class CharReaderBuilder;
|
||||
|
||||
// json_features.h
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
using ArrayIndex = unsigned int;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
@ -1,15 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_JSON_H_INCLUDED
|
||||
#define JSON_JSON_H_INCLUDED
|
||||
|
||||
#include "config.h"
|
||||
#include "json_features.h"
|
||||
#include "reader.h"
|
||||
#include "value.h"
|
||||
#include "writer.h"
|
||||
|
||||
#endif // JSON_JSON_H_INCLUDED
|
@ -1,62 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_FEATURES_H_INCLUDED
|
||||
#define JSON_FEATURES_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "forwards.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Configuration passed to reader and writer.
|
||||
* This configuration object can be used to force the Reader or Writer
|
||||
* to behave in a standard conforming way.
|
||||
*/
|
||||
class JSON_API Features {
|
||||
public:
|
||||
/** \brief A configuration that allows all features and assumes all strings
|
||||
* are UTF-8.
|
||||
* - C & C++ comments are allowed
|
||||
* - Root object can be any JSON value
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features all();
|
||||
|
||||
/** \brief A configuration that is strictly compatible with the JSON
|
||||
* specification.
|
||||
* - Comments are forbidden.
|
||||
* - Root object must be either an array or an object value.
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features strictMode();
|
||||
|
||||
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||
*/
|
||||
Features();
|
||||
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_{true};
|
||||
|
||||
/// \c true if root must be either an array or an object value. Default: \c
|
||||
/// false.
|
||||
bool strictRoot_{false};
|
||||
|
||||
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
||||
bool allowDroppedNullPlaceholders_{false};
|
||||
|
||||
/// \c true if numeric object key are allowed. Default: \c false.
|
||||
bool allowNumericKeys_{false};
|
||||
};
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // JSON_FEATURES_H_INCLUDED
|
@ -1,406 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_READER_H_INCLUDED
|
||||
#define JSON_READER_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "json_features.h"
|
||||
#include "value.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <deque>
|
||||
#include <iosfwd>
|
||||
#include <istream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
||||
* Value.
|
||||
*
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
|
||||
class JSON_API Reader {
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
|
||||
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||
*
|
||||
* The offsets give the [start, limit) range of bytes within the text. Note
|
||||
* that this is bytes, not codepoints.
|
||||
*/
|
||||
struct StructuredError {
|
||||
ptrdiff_t offset_start;
|
||||
ptrdiff_t offset_limit;
|
||||
String message;
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
Reader(const Features& features);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
* document.
|
||||
*
|
||||
* \param document UTF-8 encoded string containing the document
|
||||
* to read.
|
||||
* \param[out] root Contains the root value of the document if it
|
||||
* was successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing
|
||||
* them back during serialization, \c false to
|
||||
* discard comments. This parameter is ignored
|
||||
* if Features::allowComments_ is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
* error occurred.
|
||||
*/
|
||||
bool parse(const std::string& document, Value& root,
|
||||
bool collectComments = true);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
* document.
|
||||
*
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded
|
||||
* string of the document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string
|
||||
* of the document to read. Must be >= beginDoc.
|
||||
* \param[out] root Contains the root value of the document if it
|
||||
* was successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing
|
||||
* them back during serialization, \c false to
|
||||
* discard comments. This parameter is ignored
|
||||
* if Features::allowComments_ is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
* error occurred.
|
||||
*/
|
||||
bool parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
bool collectComments = true);
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
bool parse(IStream& is, Value& root, bool collectComments = true);
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed
|
||||
* document.
|
||||
*
|
||||
* \return Formatted error message with the list of errors with their
|
||||
* location in the parsed document. An empty string is returned if no error
|
||||
* occurred during parsing.
|
||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
|
||||
String getFormatedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed
|
||||
* document.
|
||||
*
|
||||
* \return Formatted error message with the list of errors with their
|
||||
* location in the parsed document. An empty string is returned if no error
|
||||
* occurred during parsing.
|
||||
*/
|
||||
String getFormattedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a vector of structured errors encountered while parsing.
|
||||
*
|
||||
* \return A (possibly empty) vector of StructuredError objects. Currently
|
||||
* only one error can be returned, but the caller should tolerate multiple
|
||||
* errors. This can occur if the parser recovers from a non-fatal parse
|
||||
* error and then encounters additional errors.
|
||||
*/
|
||||
std::vector<StructuredError> getStructuredErrors() const;
|
||||
|
||||
/** \brief Add a semantic error message.
|
||||
*
|
||||
* \param value JSON Value location associated with the error
|
||||
* \param message The error message.
|
||||
* \return \c true if the error was successfully added, \c false if the Value
|
||||
* offset exceeds the document size.
|
||||
*/
|
||||
bool pushError(const Value& value, const String& message);
|
||||
|
||||
/** \brief Add a semantic error message with extra context.
|
||||
*
|
||||
* \param value JSON Value location associated with the error
|
||||
* \param message The error message.
|
||||
* \param extra Additional JSON Value location to contextualize the error
|
||||
* \return \c true if the error was successfully added, \c false if either
|
||||
* Value offset exceeds the document size.
|
||||
*/
|
||||
bool pushError(const Value& value, const String& message, const Value& extra);
|
||||
|
||||
/** \brief Return whether there are any errors.
|
||||
*
|
||||
* \return \c true if there are no errors to report \c false if errors have
|
||||
* occurred.
|
||||
*/
|
||||
bool good() const;
|
||||
|
||||
private:
|
||||
enum TokenType {
|
||||
tokenEndOfStream = 0,
|
||||
tokenObjectBegin,
|
||||
tokenObjectEnd,
|
||||
tokenArrayBegin,
|
||||
tokenArrayEnd,
|
||||
tokenString,
|
||||
tokenNumber,
|
||||
tokenTrue,
|
||||
tokenFalse,
|
||||
tokenNull,
|
||||
tokenArraySeparator,
|
||||
tokenMemberSeparator,
|
||||
tokenComment,
|
||||
tokenError
|
||||
};
|
||||
|
||||
class Token {
|
||||
public:
|
||||
TokenType type_;
|
||||
Location start_;
|
||||
Location end_;
|
||||
};
|
||||
|
||||
class ErrorInfo {
|
||||
public:
|
||||
Token token_;
|
||||
String message_;
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
using Errors = std::deque<ErrorInfo>;
|
||||
|
||||
bool readToken(Token& token);
|
||||
void skipSpaces();
|
||||
bool match(const Char* pattern, int patternLength);
|
||||
bool readComment();
|
||||
bool readCStyleComment();
|
||||
bool readCppStyleComment();
|
||||
bool readString();
|
||||
void readNumber();
|
||||
bool readValue();
|
||||
bool readObject(Token& token);
|
||||
bool readArray(Token& token);
|
||||
bool decodeNumber(Token& token);
|
||||
bool decodeNumber(Token& token, Value& decoded);
|
||||
bool decodeString(Token& token);
|
||||
bool decodeString(Token& token, String& decoded);
|
||||
bool decodeDouble(Token& token);
|
||||
bool decodeDouble(Token& token, Value& decoded);
|
||||
bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
|
||||
unsigned int& unicode);
|
||||
bool decodeUnicodeEscapeSequence(Token& token, Location& current,
|
||||
Location end, unsigned int& unicode);
|
||||
bool addError(const String& message, Token& token, Location extra = nullptr);
|
||||
bool recoverFromError(TokenType skipUntilToken);
|
||||
bool addErrorAndRecover(const String& message, Token& token,
|
||||
TokenType skipUntilToken);
|
||||
void skipUntilSpace();
|
||||
Value& currentValue();
|
||||
Char getNextChar();
|
||||
void getLocationLineAndColumn(Location location, int& line,
|
||||
int& column) const;
|
||||
String getLocationLineAndColumn(Location location) const;
|
||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||
void skipCommentTokens(Token& token);
|
||||
|
||||
static bool containsNewLine(Location begin, Location end);
|
||||
static String normalizeEOL(Location begin, Location end);
|
||||
|
||||
using Nodes = std::stack<Value*>;
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
String document_;
|
||||
Location begin_{};
|
||||
Location end_{};
|
||||
Location current_{};
|
||||
Location lastValueEnd_{};
|
||||
Value* lastValue_{};
|
||||
String commentsBefore_;
|
||||
Features features_;
|
||||
bool collectComments_{};
|
||||
}; // Reader
|
||||
|
||||
/** Interface for reading JSON from a char array.
|
||||
*/
|
||||
class JSON_API CharReader {
|
||||
public:
|
||||
virtual ~CharReader() = default;
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
* document. The document must be a UTF-8 encoded string containing the
|
||||
* document to read.
|
||||
*
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string
|
||||
* of the document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||
* document to read. Must be >= beginDoc.
|
||||
* \param[out] root Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param[out] errs Formatted error messages (if not NULL) a user
|
||||
* friendly string that lists errors in the parsed
|
||||
* document.
|
||||
* \return \c true if the document was successfully parsed, \c false if an
|
||||
* error occurred.
|
||||
*/
|
||||
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||
String* errs) = 0;
|
||||
|
||||
class JSON_API Factory {
|
||||
public:
|
||||
virtual ~Factory() = default;
|
||||
/** \brief Allocate a CharReader via operator new().
|
||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||
*/
|
||||
virtual CharReader* newCharReader() const = 0;
|
||||
}; // Factory
|
||||
}; // CharReader
|
||||
|
||||
/** \brief Build a CharReader implementation.
|
||||
*
|
||||
* Usage:
|
||||
* \code
|
||||
* using namespace Json;
|
||||
* CharReaderBuilder builder;
|
||||
* builder["collectComments"] = false;
|
||||
* Value value;
|
||||
* String errs;
|
||||
* bool ok = parseFromStream(builder, std::cin, &value, &errs);
|
||||
* \endcode
|
||||
*/
|
||||
class JSON_API CharReaderBuilder : public CharReader::Factory {
|
||||
public:
|
||||
// Note: We use a Json::Value so that we can add data-members to this class
|
||||
// without a major version bump.
|
||||
/** Configuration of this builder.
|
||||
* These are case-sensitive.
|
||||
* Available settings (case-sensitive):
|
||||
* - `"collectComments": false or true`
|
||||
* - true to collect comment and allow writing them back during
|
||||
* serialization, false to discard comments. This parameter is ignored
|
||||
* if allowComments is false.
|
||||
* - `"allowComments": false or true`
|
||||
* - true if comments are allowed.
|
||||
* - `"allowTrailingCommas": false or true`
|
||||
* - true if trailing commas in objects and arrays are allowed.
|
||||
* - `"strictRoot": false or true`
|
||||
* - true if root must be either an array or an object value
|
||||
* - `"allowDroppedNullPlaceholders": false or true`
|
||||
* - true if dropped null placeholders are allowed. (See
|
||||
* StreamWriterBuilder.)
|
||||
* - `"allowNumericKeys": false or true`
|
||||
* - true if numeric object keys are allowed.
|
||||
* - `"allowSingleQuotes": false or true`
|
||||
* - true if '' are allowed for strings (both keys and values)
|
||||
* - `"stackLimit": integer`
|
||||
* - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
|
||||
* exception.
|
||||
* - This is a security issue (seg-faults caused by deeply nested JSON), so
|
||||
* the default is low.
|
||||
* - `"failIfExtra": false or true`
|
||||
* - If true, `parse()` returns false when extra non-whitespace trails the
|
||||
* JSON value in the input string.
|
||||
* - `"rejectDupKeys": false or true`
|
||||
* - If true, `parse()` returns false when a key is duplicated within an
|
||||
* object.
|
||||
* - `"allowSpecialFloats": false or true`
|
||||
* - If true, special float values (NaNs and infinities) are allowed and
|
||||
* their values are lossfree restorable.
|
||||
* - `"skipBom": false or true`
|
||||
* - If true, if the input starts with the Unicode byte order mark (BOM),
|
||||
* it is skipped.
|
||||
*
|
||||
* You can examine 'settings_` yourself to see the defaults. You can also
|
||||
* write and read them just like any JSON Value.
|
||||
* \sa setDefaults()
|
||||
*/
|
||||
Json::Value settings_;
|
||||
|
||||
CharReaderBuilder();
|
||||
~CharReaderBuilder() override;
|
||||
|
||||
CharReader* newCharReader() const override;
|
||||
|
||||
/** \return true if 'settings' are legal and consistent;
|
||||
* otherwise, indicate bad settings via 'invalid'.
|
||||
*/
|
||||
bool validate(Json::Value* invalid) const;
|
||||
|
||||
/** A simple way to update a specific setting.
|
||||
*/
|
||||
Value& operator[](const String& key);
|
||||
|
||||
/** Called by ctor, but you can use this to reset settings_.
|
||||
* \pre 'settings' != NULL (but Json::null is fine)
|
||||
* \remark Defaults:
|
||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
|
||||
*/
|
||||
static void setDefaults(Json::Value* settings);
|
||||
/** Same as old Features::strictMode().
|
||||
* \pre 'settings' != NULL (but Json::null is fine)
|
||||
* \remark Defaults:
|
||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
|
||||
*/
|
||||
static void strictMode(Json::Value* settings);
|
||||
};
|
||||
|
||||
/** Consume entire stream and use its begin/end.
|
||||
* Someday we might have a real StreamReader, but for now this
|
||||
* is convenient.
|
||||
*/
|
||||
bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
|
||||
String* errs);
|
||||
|
||||
/** \brief Read from 'sin' into 'root'.
|
||||
*
|
||||
* Always keep comments from the input JSON.
|
||||
*
|
||||
* This can be used to read a file into a particular sub-object.
|
||||
* For example:
|
||||
* \code
|
||||
* Json::Value root;
|
||||
* cin >> root["dir"]["file"];
|
||||
* cout << root;
|
||||
* \endcode
|
||||
* Result:
|
||||
* \verbatim
|
||||
* {
|
||||
* "dir": {
|
||||
* "file": {
|
||||
* // The input stream JSON would be nested here.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* \endverbatim
|
||||
* \throw std::exception on parse error.
|
||||
* \see Json::operator<<()
|
||||
*/
|
||||
JSON_API IStream& operator>>(IStream&, Value&);
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#endif // JSON_READER_H_INCLUDED
|
@ -1,936 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_H_INCLUDED
|
||||
#define JSON_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "forwards.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
// Conditional NORETURN attribute on the throw functions would:
|
||||
// a) suppress false positives from static code analysis
|
||||
// b) possibly improve optimization opportunities.
|
||||
#if !defined(JSONCPP_NORETURN)
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1800
|
||||
#define JSONCPP_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define JSONCPP_NORETURN [[noreturn]]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Support for '= delete' with template declarations was a late addition
|
||||
// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
|
||||
// even though these declare themselves to be c++11 compilers.
|
||||
#if !defined(JSONCPP_TEMPLATE_DELETE)
|
||||
#if defined(__clang__) && defined(__apple_build_version__)
|
||||
#if __apple_build_version__ <= 8000042
|
||||
#define JSONCPP_TEMPLATE_DELETE
|
||||
#endif
|
||||
#elif defined(__clang__)
|
||||
#if __clang_major__ == 3 && __clang_minor__ <= 8
|
||||
#define JSONCPP_TEMPLATE_DELETE
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(JSONCPP_TEMPLATE_DELETE)
|
||||
#define JSONCPP_TEMPLATE_DELETE = delete
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251 4275)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
|
||||
/** \brief JSON (JavaScript Object Notation).
|
||||
*/
|
||||
namespace Json {
|
||||
|
||||
#if JSON_USE_EXCEPTION
|
||||
/** Base class for all exceptions we throw.
|
||||
*
|
||||
* We use nothing but these internally. Of course, STL can throw others.
|
||||
*/
|
||||
class JSON_API Exception : public std::exception {
|
||||
public:
|
||||
Exception(String msg);
|
||||
~Exception() noexcept override;
|
||||
char const* what() const noexcept override;
|
||||
|
||||
protected:
|
||||
String msg_;
|
||||
};
|
||||
|
||||
/** Exceptions which the user cannot easily avoid.
|
||||
*
|
||||
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
|
||||
*
|
||||
* \remark derived from Json::Exception
|
||||
*/
|
||||
class JSON_API RuntimeError : public Exception {
|
||||
public:
|
||||
RuntimeError(String const& msg);
|
||||
};
|
||||
|
||||
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
|
||||
*
|
||||
* These are precondition-violations (user bugs) and internal errors (our bugs).
|
||||
*
|
||||
* \remark derived from Json::Exception
|
||||
*/
|
||||
class JSON_API LogicError : public Exception {
|
||||
public:
|
||||
LogicError(String const& msg);
|
||||
};
|
||||
#endif
|
||||
|
||||
/// used internally
|
||||
JSONCPP_NORETURN void throwRuntimeError(String const& msg);
|
||||
/// used internally
|
||||
JSONCPP_NORETURN void throwLogicError(String const& msg);
|
||||
|
||||
/** \brief Type of the value held by a Value object.
|
||||
*/
|
||||
enum ValueType {
|
||||
nullValue = 0, ///< 'null' value
|
||||
intValue, ///< signed integer value
|
||||
uintValue, ///< unsigned integer value
|
||||
realValue, ///< double value
|
||||
stringValue, ///< UTF-8 string value
|
||||
booleanValue, ///< bool value
|
||||
arrayValue, ///< array value (ordered list)
|
||||
objectValue ///< object value (collection of name/value pairs).
|
||||
};
|
||||
|
||||
enum CommentPlacement {
|
||||
commentBefore = 0, ///< a comment placed on the line before a value
|
||||
commentAfterOnSameLine, ///< a comment just after a value on the same line
|
||||
commentAfter, ///< a comment on the line after a value (only make sense for
|
||||
/// root value)
|
||||
numberOfCommentPlacement
|
||||
};
|
||||
|
||||
/** \brief Type of precision for formatting of real values.
|
||||
*/
|
||||
enum PrecisionType {
|
||||
significantDigits = 0, ///< we set max number of significant digits in string
|
||||
decimalPlaces ///< we set max number of digits after "." in string
|
||||
};
|
||||
|
||||
/** \brief Lightweight wrapper to tag static string.
|
||||
*
|
||||
* Value constructor and objectValue member assignment takes advantage of the
|
||||
* StaticString and avoid the cost of string duplication when storing the
|
||||
* string or the member name.
|
||||
*
|
||||
* Example of usage:
|
||||
* \code
|
||||
* Json::Value aValue( StaticString("some text") );
|
||||
* Json::Value object;
|
||||
* static const StaticString code("code");
|
||||
* object[code] = 1234;
|
||||
* \endcode
|
||||
*/
|
||||
class JSON_API StaticString {
|
||||
public:
|
||||
explicit StaticString(const char* czstring) : c_str_(czstring) {}
|
||||
|
||||
operator const char*() const { return c_str_; }
|
||||
|
||||
const char* c_str() const { return c_str_; }
|
||||
|
||||
private:
|
||||
const char* c_str_;
|
||||
};
|
||||
|
||||
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
|
||||
*
|
||||
* This class is a discriminated union wrapper that can represents a:
|
||||
* - signed integer [range: Value::minInt - Value::maxInt]
|
||||
* - unsigned integer (range: 0 - Value::maxUInt)
|
||||
* - double
|
||||
* - UTF-8 string
|
||||
* - boolean
|
||||
* - 'null'
|
||||
* - an ordered list of Value
|
||||
* - collection of name/value pairs (javascript object)
|
||||
*
|
||||
* The type of the held value is represented by a #ValueType and
|
||||
* can be obtained using type().
|
||||
*
|
||||
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
|
||||
* methods.
|
||||
* Non-const methods will automatically create the a #nullValue element
|
||||
* if it does not exist.
|
||||
* The sequence of an #arrayValue will be automatically resized and initialized
|
||||
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
|
||||
*
|
||||
* The get() methods can be used to obtain default value in the case the
|
||||
* required element does not exist.
|
||||
*
|
||||
* It is possible to iterate over the list of member keys of an object using
|
||||
* the getMemberNames() method.
|
||||
*
|
||||
* \note #Value string-length fit in size_t, but keys must be < 2^30.
|
||||
* (The reason is an implementation detail.) A #CharReader will raise an
|
||||
* exception if a bound is exceeded to avoid security holes in your app,
|
||||
* but the Value API does *not* check bounds. That is the responsibility
|
||||
* of the caller.
|
||||
*/
|
||||
class JSON_API Value {
|
||||
friend class ValueIteratorBase;
|
||||
|
||||
public:
|
||||
using Members = std::vector<String>;
|
||||
using iterator = ValueIterator;
|
||||
using const_iterator = ValueConstIterator;
|
||||
using UInt = Json::UInt;
|
||||
using Int = Json::Int;
|
||||
#if defined(JSON_HAS_INT64)
|
||||
using UInt64 = Json::UInt64;
|
||||
using Int64 = Json::Int64;
|
||||
#endif // defined(JSON_HAS_INT64)
|
||||
using LargestInt = Json::LargestInt;
|
||||
using LargestUInt = Json::LargestUInt;
|
||||
using ArrayIndex = Json::ArrayIndex;
|
||||
|
||||
// Required for boost integration, e. g. BOOST_TEST
|
||||
using value_type = std::string;
|
||||
|
||||
#if JSON_USE_NULLREF
|
||||
// Binary compatibility kludges, do not use.
|
||||
static const Value& null;
|
||||
static const Value& nullRef;
|
||||
#endif
|
||||
|
||||
// null and nullRef are deprecated, use this instead.
|
||||
static Value const& nullSingleton();
|
||||
|
||||
/// Minimum signed integer value that can be stored in a Json::Value.
|
||||
static constexpr LargestInt minLargestInt =
|
||||
LargestInt(~(LargestUInt(-1) / 2));
|
||||
/// Maximum signed integer value that can be stored in a Json::Value.
|
||||
static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
||||
/// Maximum unsigned integer value that can be stored in a Json::Value.
|
||||
static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);
|
||||
|
||||
/// Minimum signed int value that can be stored in a Json::Value.
|
||||
static constexpr Int minInt = Int(~(UInt(-1) / 2));
|
||||
/// Maximum signed int value that can be stored in a Json::Value.
|
||||
static constexpr Int maxInt = Int(UInt(-1) / 2);
|
||||
/// Maximum unsigned int value that can be stored in a Json::Value.
|
||||
static constexpr UInt maxUInt = UInt(-1);
|
||||
|
||||
#if defined(JSON_HAS_INT64)
|
||||
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
|
||||
static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
|
||||
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
|
||||
static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
|
||||
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
|
||||
static constexpr UInt64 maxUInt64 = UInt64(-1);
|
||||
#endif // defined(JSON_HAS_INT64)
|
||||
/// Default precision for real value for string representation.
|
||||
static constexpr UInt defaultRealPrecision = 17;
|
||||
// The constant is hard-coded because some compiler have trouble
|
||||
// converting Value::maxUInt64 to a double correctly (AIX/xlC).
|
||||
// Assumes that UInt64 is a 64 bits integer.
|
||||
static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
|
||||
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
|
||||
// when using gcc and clang backend compilers. CZString
|
||||
// cannot be defined as private. See issue #486
|
||||
#ifdef __NVCC__
|
||||
public:
|
||||
#else
|
||||
private:
|
||||
#endif
|
||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
class CZString {
|
||||
public:
|
||||
enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
|
||||
CZString(ArrayIndex index);
|
||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
CZString(CZString&& other) noexcept;
|
||||
~CZString();
|
||||
CZString& operator=(const CZString& other);
|
||||
CZString& operator=(CZString&& other) noexcept;
|
||||
|
||||
bool operator<(CZString const& other) const;
|
||||
bool operator==(CZString const& other) const;
|
||||
ArrayIndex index() const;
|
||||
// const char* c_str() const; ///< \deprecated
|
||||
char const* data() const;
|
||||
unsigned length() const;
|
||||
bool isStaticString() const;
|
||||
|
||||
private:
|
||||
void swap(CZString& other);
|
||||
|
||||
struct StringStorage {
|
||||
unsigned policy_ : 2;
|
||||
unsigned length_ : 30; // 1GB max
|
||||
};
|
||||
|
||||
char const* cstr_; // actually, a prefixed string, unless policy is noDup
|
||||
union {
|
||||
ArrayIndex index_;
|
||||
StringStorage storage_;
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
typedef std::map<CZString, Value> ObjectValues;
|
||||
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Create a default Value of the given type.
|
||||
*
|
||||
* This is a very useful constructor.
|
||||
* To create an empty array, pass arrayValue.
|
||||
* To create an empty object, pass objectValue.
|
||||
* Another Value can then be set to this one by assignment.
|
||||
* This is useful since clear() and resize() will not alter types.
|
||||
*
|
||||
* Examples:
|
||||
* \code
|
||||
* Json::Value null_value; // null
|
||||
* Json::Value arr_value(Json::arrayValue); // []
|
||||
* Json::Value obj_value(Json::objectValue); // {}
|
||||
* \endcode
|
||||
*/
|
||||
Value(ValueType type = nullValue);
|
||||
Value(Int value);
|
||||
Value(UInt value);
|
||||
#if defined(JSON_HAS_INT64)
|
||||
Value(Int64 value);
|
||||
Value(UInt64 value);
|
||||
#endif // if defined(JSON_HAS_INT64)
|
||||
Value(double value);
|
||||
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
|
||||
Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
|
||||
/**
|
||||
* \brief Constructs a value from a static string.
|
||||
*
|
||||
* Like other value string constructor but do not duplicate the string for
|
||||
* internal storage. The given string must remain alive after the call to
|
||||
* this constructor.
|
||||
*
|
||||
* \note This works only for null-terminated strings. (We cannot change the
|
||||
* size of this class, so we have nowhere to store the length, which might be
|
||||
* computed later for various operations.)
|
||||
*
|
||||
* Example of usage:
|
||||
* \code
|
||||
* static StaticString foo("some text");
|
||||
* Json::Value aValue(foo);
|
||||
* \endcode
|
||||
*/
|
||||
Value(const StaticString& value);
|
||||
Value(const String& value);
|
||||
Value(bool value);
|
||||
Value(std::nullptr_t ptr) = delete;
|
||||
Value(const Value& other);
|
||||
Value(Value&& other) noexcept;
|
||||
~Value();
|
||||
|
||||
/// \note Overwrite existing comments. To preserve comments, use
|
||||
/// #swapPayload().
|
||||
Value& operator=(const Value& other);
|
||||
Value& operator=(Value&& other) noexcept;
|
||||
|
||||
/// Swap everything.
|
||||
void swap(Value& other);
|
||||
/// Swap values but leave comments and source offsets in place.
|
||||
void swapPayload(Value& other);
|
||||
|
||||
/// copy everything.
|
||||
void copy(const Value& other);
|
||||
/// copy values but leave comments and source offsets in place.
|
||||
void copyPayload(const Value& other);
|
||||
|
||||
ValueType type() const;
|
||||
|
||||
/// Compare payload only, not comments etc.
|
||||
bool operator<(const Value& other) const;
|
||||
bool operator<=(const Value& other) const;
|
||||
bool operator>=(const Value& other) const;
|
||||
bool operator>(const Value& other) const;
|
||||
bool operator==(const Value& other) const;
|
||||
bool operator!=(const Value& other) const;
|
||||
int compare(const Value& other) const;
|
||||
|
||||
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
unsigned getCStringLength() const; // Allows you to understand the length of
|
||||
// the CString
|
||||
#endif
|
||||
String asString() const; ///< Embedded zeroes are possible.
|
||||
/** Get raw char* of string-value.
|
||||
* \return false if !string. (Seg-fault if str or end are NULL.)
|
||||
*/
|
||||
bool getString(char const** begin, char const** end) const;
|
||||
Int asInt() const;
|
||||
UInt asUInt() const;
|
||||
#if defined(JSON_HAS_INT64)
|
||||
Int64 asInt64() const;
|
||||
UInt64 asUInt64() const;
|
||||
#endif // if defined(JSON_HAS_INT64)
|
||||
LargestInt asLargestInt() const;
|
||||
LargestUInt asLargestUInt() const;
|
||||
float asFloat() const;
|
||||
double asDouble() const;
|
||||
bool asBool() const;
|
||||
|
||||
bool isNull() const;
|
||||
bool isBool() const;
|
||||
bool isInt() const;
|
||||
bool isInt64() const;
|
||||
bool isUInt() const;
|
||||
bool isUInt64() const;
|
||||
bool isIntegral() const;
|
||||
bool isDouble() const;
|
||||
bool isNumeric() const;
|
||||
bool isString() const;
|
||||
bool isArray() const;
|
||||
bool isObject() const;
|
||||
|
||||
/// The `as<T>` and `is<T>` member function templates and specializations.
|
||||
template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
|
||||
template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;
|
||||
|
||||
bool isConvertibleTo(ValueType other) const;
|
||||
|
||||
/// Number of values in array or object
|
||||
ArrayIndex size() const;
|
||||
|
||||
/// \brief Return true if empty array, empty object, or null;
|
||||
/// otherwise, false.
|
||||
bool empty() const;
|
||||
|
||||
/// Return !isNull()
|
||||
explicit operator bool() const;
|
||||
|
||||
/// Remove all object members and array elements.
|
||||
/// \pre type() is arrayValue, objectValue, or nullValue
|
||||
/// \post type() is unchanged
|
||||
void clear();
|
||||
|
||||
/// Resize the array to newSize elements.
|
||||
/// New elements are initialized to null.
|
||||
/// May only be called on nullValue or arrayValue.
|
||||
/// \pre type() is arrayValue or nullValue
|
||||
/// \post type() is arrayValue
|
||||
void resize(ArrayIndex newSize);
|
||||
|
||||
///@{
|
||||
/// Access an array element (zero based index). If the array contains less
|
||||
/// than index element, then null value are inserted in the array so that
|
||||
/// its size is index+1.
|
||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||
/// this from the operator[] which takes a string.)
|
||||
Value& operator[](ArrayIndex index);
|
||||
Value& operator[](int index);
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/// Access an array element (zero based index).
|
||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||
/// this from the operator[] which takes a string.)
|
||||
const Value& operator[](ArrayIndex index) const;
|
||||
const Value& operator[](int index) const;
|
||||
///@}
|
||||
|
||||
/// If the array contains at least index+1 elements, returns the element
|
||||
/// value, otherwise returns defaultValue.
|
||||
Value get(ArrayIndex index, const Value& defaultValue) const;
|
||||
/// Return true if index < size().
|
||||
bool isValidIndex(ArrayIndex index) const;
|
||||
/// \brief Append value to array at the end.
|
||||
///
|
||||
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
|
||||
Value& append(const Value& value);
|
||||
Value& append(Value&& value);
|
||||
|
||||
/// \brief Insert value in array at specific index
|
||||
bool insert(ArrayIndex index, const Value& newValue);
|
||||
bool insert(ArrayIndex index, Value&& newValue);
|
||||
|
||||
/// Access an object value by name, create a null member if it does not exist.
|
||||
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
|
||||
/// Exceeding that will cause an exception.
|
||||
Value& operator[](const char* key);
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
const Value& operator[](const char* key) const;
|
||||
/// Access an object value by name, create a null member if it does not exist.
|
||||
/// \param key may contain embedded nulls.
|
||||
Value& operator[](const String& key);
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
/// \param key may contain embedded nulls.
|
||||
const Value& operator[](const String& key) const;
|
||||
/** \brief Access an object value by name, create a null member if it does not
|
||||
* exist.
|
||||
*
|
||||
* If the object has no entry for that name, then the member name used to
|
||||
* store the new entry is not duplicated.
|
||||
* Example of use:
|
||||
* \code
|
||||
* Json::Value object;
|
||||
* static const StaticString code("code");
|
||||
* object[code] = 1234;
|
||||
* \endcode
|
||||
*/
|
||||
Value& operator[](const StaticString& key);
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
/// \note deep copy
|
||||
Value get(const char* key, const Value& defaultValue) const;
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
/// \note deep copy
|
||||
/// \note key may contain embedded nulls.
|
||||
Value get(const char* begin, const char* end,
|
||||
const Value& defaultValue) const;
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
/// \note deep copy
|
||||
/// \param key may contain embedded nulls.
|
||||
Value get(const String& key, const Value& defaultValue) const;
|
||||
/// Most general and efficient version of isMember()const, get()const,
|
||||
/// and operator[]const
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||
Value const* find(char const* begin, char const* end) const;
|
||||
/// Most general and efficient version of object-mutators.
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
||||
Value* demand(char const* begin, char const* end);
|
||||
/// \brief Remove and return the named member.
|
||||
///
|
||||
/// Do nothing if it did not exist.
|
||||
/// \pre type() is objectValue or nullValue
|
||||
/// \post type() is unchanged
|
||||
void removeMember(const char* key);
|
||||
/// Same as removeMember(const char*)
|
||||
/// \param key may contain embedded nulls.
|
||||
void removeMember(const String& key);
|
||||
/// Same as removeMember(const char* begin, const char* end, Value* removed),
|
||||
/// but 'key' is null-terminated.
|
||||
bool removeMember(const char* key, Value* removed);
|
||||
/** \brief Remove the named map member.
|
||||
*
|
||||
* Update 'removed' iff removed.
|
||||
* \param key may contain embedded nulls.
|
||||
* \return true iff removed (no exceptions)
|
||||
*/
|
||||
bool removeMember(String const& key, Value* removed);
|
||||
/// Same as removeMember(String const& key, Value* removed)
|
||||
bool removeMember(const char* begin, const char* end, Value* removed);
|
||||
/** \brief Remove the indexed array element.
|
||||
*
|
||||
* O(n) expensive operations.
|
||||
* Update 'removed' iff removed.
|
||||
* \return true if removed (no exceptions)
|
||||
*/
|
||||
bool removeIndex(ArrayIndex index, Value* removed);
|
||||
|
||||
/// Return true if the object has a member named key.
|
||||
/// \note 'key' must be null-terminated.
|
||||
bool isMember(const char* key) const;
|
||||
/// Return true if the object has a member named key.
|
||||
/// \param key may contain embedded nulls.
|
||||
bool isMember(const String& key) const;
|
||||
/// Same as isMember(String const& key)const
|
||||
bool isMember(const char* begin, const char* end) const;
|
||||
|
||||
/// \brief Return a list of the member names.
|
||||
///
|
||||
/// If null, return an empty list.
|
||||
/// \pre type() is objectValue or nullValue
|
||||
/// \post if type() was nullValue, it remains nullValue
|
||||
Members getMemberNames() const;
|
||||
|
||||
/// \deprecated Always pass len.
|
||||
JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
|
||||
void setComment(const char* comment, CommentPlacement placement) {
|
||||
setComment(String(comment, strlen(comment)), placement);
|
||||
}
|
||||
/// Comments must be //... or /* ... */
|
||||
void setComment(const char* comment, size_t len, CommentPlacement placement) {
|
||||
setComment(String(comment, len), placement);
|
||||
}
|
||||
/// Comments must be //... or /* ... */
|
||||
void setComment(String comment, CommentPlacement placement);
|
||||
bool hasComment(CommentPlacement placement) const;
|
||||
/// Include delimiters and embedded newlines.
|
||||
String getComment(CommentPlacement placement) const;
|
||||
|
||||
String toStyledString() const;
|
||||
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
// Accessors for the [start, limit) range of bytes within the JSON text from
|
||||
// which this value was parsed, if any.
|
||||
void setOffsetStart(ptrdiff_t start);
|
||||
void setOffsetLimit(ptrdiff_t limit);
|
||||
ptrdiff_t getOffsetStart() const;
|
||||
ptrdiff_t getOffsetLimit() const;
|
||||
|
||||
private:
|
||||
void setType(ValueType v) {
|
||||
bits_.value_type_ = static_cast<unsigned char>(v);
|
||||
}
|
||||
bool isAllocated() const { return bits_.allocated_; }
|
||||
void setIsAllocated(bool v) { bits_.allocated_ = v; }
|
||||
|
||||
void initBasic(ValueType type, bool allocated = false);
|
||||
void dupPayload(const Value& other);
|
||||
void releasePayload();
|
||||
void dupMeta(const Value& other);
|
||||
|
||||
Value& resolveReference(const char* key);
|
||||
Value& resolveReference(const char* key, const char* end);
|
||||
|
||||
// struct MemberNamesTransform
|
||||
//{
|
||||
// typedef const char *result_type;
|
||||
// const char *operator()( const CZString &name ) const
|
||||
// {
|
||||
// return name.c_str();
|
||||
// }
|
||||
//};
|
||||
|
||||
union ValueHolder {
|
||||
LargestInt int_;
|
||||
LargestUInt uint_;
|
||||
double real_;
|
||||
bool bool_;
|
||||
char* string_; // if allocated_, ptr to { unsigned, char[] }.
|
||||
ObjectValues* map_;
|
||||
} value_;
|
||||
|
||||
struct {
|
||||
// Really a ValueType, but types should agree for bitfield packing.
|
||||
unsigned int value_type_ : 8;
|
||||
// Unless allocated_, string_ must be null-terminated.
|
||||
unsigned int allocated_ : 1;
|
||||
} bits_;
|
||||
|
||||
class Comments {
|
||||
public:
|
||||
Comments() = default;
|
||||
Comments(const Comments& that);
|
||||
Comments(Comments&& that) noexcept;
|
||||
Comments& operator=(const Comments& that);
|
||||
Comments& operator=(Comments&& that) noexcept;
|
||||
bool has(CommentPlacement slot) const;
|
||||
String get(CommentPlacement slot) const;
|
||||
void set(CommentPlacement slot, String comment);
|
||||
|
||||
private:
|
||||
using Array = std::array<String, numberOfCommentPlacement>;
|
||||
std::unique_ptr<Array> ptr_;
|
||||
};
|
||||
Comments comments_;
|
||||
|
||||
// [start, limit) byte offsets in the source JSON text from which this Value
|
||||
// was extracted.
|
||||
ptrdiff_t start_;
|
||||
ptrdiff_t limit_;
|
||||
};
|
||||
|
||||
template <> inline bool Value::as<bool>() const { return asBool(); }
|
||||
template <> inline bool Value::is<bool>() const { return isBool(); }
|
||||
|
||||
template <> inline Int Value::as<Int>() const { return asInt(); }
|
||||
template <> inline bool Value::is<Int>() const { return isInt(); }
|
||||
|
||||
template <> inline UInt Value::as<UInt>() const { return asUInt(); }
|
||||
template <> inline bool Value::is<UInt>() const { return isUInt(); }
|
||||
|
||||
#if defined(JSON_HAS_INT64)
|
||||
template <> inline Int64 Value::as<Int64>() const { return asInt64(); }
|
||||
template <> inline bool Value::is<Int64>() const { return isInt64(); }
|
||||
|
||||
template <> inline UInt64 Value::as<UInt64>() const { return asUInt64(); }
|
||||
template <> inline bool Value::is<UInt64>() const { return isUInt64(); }
|
||||
#endif
|
||||
|
||||
template <> inline double Value::as<double>() const { return asDouble(); }
|
||||
template <> inline bool Value::is<double>() const { return isDouble(); }
|
||||
|
||||
template <> inline String Value::as<String>() const { return asString(); }
|
||||
template <> inline bool Value::is<String>() const { return isString(); }
|
||||
|
||||
/// These `as` specializations are type conversions, and do not have a
|
||||
/// corresponding `is`.
|
||||
template <> inline float Value::as<float>() const { return asFloat(); }
|
||||
template <> inline const char* Value::as<const char*>() const {
|
||||
return asCString();
|
||||
}
|
||||
|
||||
/** \brief Experimental and untested: represents an element of the "path" to
|
||||
* access a node.
|
||||
*/
|
||||
class JSON_API PathArgument {
|
||||
public:
|
||||
friend class Path;
|
||||
|
||||
PathArgument();
|
||||
PathArgument(ArrayIndex index);
|
||||
PathArgument(const char* key);
|
||||
PathArgument(String key);
|
||||
|
||||
private:
|
||||
enum Kind { kindNone = 0, kindIndex, kindKey };
|
||||
String key_;
|
||||
ArrayIndex index_{};
|
||||
Kind kind_{kindNone};
|
||||
};
|
||||
|
||||
/** \brief Experimental and untested: represents a "path" to access a node.
|
||||
*
|
||||
* Syntax:
|
||||
* - "." => root node
|
||||
* - ".[n]" => elements at index 'n' of root node (an array value)
|
||||
* - ".name" => member named 'name' of root node (an object value)
|
||||
* - ".name1.name2.name3"
|
||||
* - ".[0][1][2].name1[3]"
|
||||
* - ".%" => member name is provided as parameter
|
||||
* - ".[%]" => index is provided as parameter
|
||||
*/
|
||||
class JSON_API Path {
|
||||
public:
|
||||
Path(const String& path, const PathArgument& a1 = PathArgument(),
|
||||
const PathArgument& a2 = PathArgument(),
|
||||
const PathArgument& a3 = PathArgument(),
|
||||
const PathArgument& a4 = PathArgument(),
|
||||
const PathArgument& a5 = PathArgument());
|
||||
|
||||
const Value& resolve(const Value& root) const;
|
||||
Value resolve(const Value& root, const Value& defaultValue) const;
|
||||
/// Creates the "path" to access the specified node and returns a reference on
|
||||
/// the node.
|
||||
Value& make(Value& root) const;
|
||||
|
||||
private:
|
||||
using InArgs = std::vector<const PathArgument*>;
|
||||
using Args = std::vector<PathArgument>;
|
||||
|
||||
void makePath(const String& path, const InArgs& in);
|
||||
void addPathInArg(const String& path, const InArgs& in,
|
||||
InArgs::const_iterator& itInArg, PathArgument::Kind kind);
|
||||
static void invalidPath(const String& path, int location);
|
||||
|
||||
Args args_;
|
||||
};
|
||||
|
||||
/** \brief base class for Value iterators.
|
||||
*
|
||||
*/
|
||||
class JSON_API ValueIteratorBase {
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using SelfType = ValueIteratorBase;
|
||||
|
||||
bool operator==(const SelfType& other) const { return isEqual(other); }
|
||||
|
||||
bool operator!=(const SelfType& other) const { return !isEqual(other); }
|
||||
|
||||
difference_type operator-(const SelfType& other) const {
|
||||
return other.computeDistance(*this);
|
||||
}
|
||||
|
||||
/// Return either the index or the member name of the referenced value as a
|
||||
/// Value.
|
||||
Value key() const;
|
||||
|
||||
/// Return the index of the referenced Value, or -1 if it is not an
|
||||
/// arrayValue.
|
||||
UInt index() const;
|
||||
|
||||
/// Return the member name of the referenced Value, or "" if it is not an
|
||||
/// objectValue.
|
||||
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
|
||||
String name() const;
|
||||
|
||||
/// Return the member name of the referenced Value. "" if it is not an
|
||||
/// objectValue.
|
||||
/// \deprecated This cannot be used for UTF-8 strings, since there can be
|
||||
/// embedded nulls.
|
||||
JSONCPP_DEPRECATED("Use `key = name();` instead.")
|
||||
char const* memberName() const;
|
||||
/// Return the member name of the referenced Value, or NULL if it is not an
|
||||
/// objectValue.
|
||||
/// \note Better version than memberName(). Allows embedded nulls.
|
||||
char const* memberName(char const** end) const;
|
||||
|
||||
protected:
|
||||
/*! Internal utility functions to assist with implementing
|
||||
* other iterator functions. The const and non-const versions
|
||||
* of the "deref" protected methods expose the protected
|
||||
* current_ member variable in a way that can often be
|
||||
* optimized away by the compiler.
|
||||
*/
|
||||
const Value& deref() const;
|
||||
Value& deref();
|
||||
|
||||
void increment();
|
||||
|
||||
void decrement();
|
||||
|
||||
difference_type computeDistance(const SelfType& other) const;
|
||||
|
||||
bool isEqual(const SelfType& other) const;
|
||||
|
||||
void copy(const SelfType& other);
|
||||
|
||||
private:
|
||||
Value::ObjectValues::iterator current_;
|
||||
// Indicates that iterator is for a null value.
|
||||
bool isNull_{true};
|
||||
|
||||
public:
|
||||
// For some reason, BORLAND needs these at the end, rather
|
||||
// than earlier. No idea why.
|
||||
ValueIteratorBase();
|
||||
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||
};
|
||||
|
||||
/** \brief const iterator for object and array value.
|
||||
*
|
||||
*/
|
||||
class JSON_API ValueConstIterator : public ValueIteratorBase {
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
using value_type = const Value;
|
||||
// typedef unsigned int size_t;
|
||||
// typedef int difference_type;
|
||||
using reference = const Value&;
|
||||
using pointer = const Value*;
|
||||
using SelfType = ValueConstIterator;
|
||||
|
||||
ValueConstIterator();
|
||||
ValueConstIterator(ValueIterator const& other);
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||
|
||||
public:
|
||||
SelfType& operator=(const ValueIteratorBase& other);
|
||||
|
||||
SelfType operator++(int) {
|
||||
SelfType temp(*this);
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType operator--(int) {
|
||||
SelfType temp(*this);
|
||||
--*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType& operator--() {
|
||||
decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator++() {
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator*() const { return deref(); }
|
||||
|
||||
pointer operator->() const { return &deref(); }
|
||||
};
|
||||
|
||||
/** \brief Iterator for object and array value.
|
||||
*/
|
||||
class JSON_API ValueIterator : public ValueIteratorBase {
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
using value_type = Value;
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using reference = Value&;
|
||||
using pointer = Value*;
|
||||
using SelfType = ValueIterator;
|
||||
|
||||
ValueIterator();
|
||||
explicit ValueIterator(const ValueConstIterator& other);
|
||||
ValueIterator(const ValueIterator& other);
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
||||
|
||||
public:
|
||||
SelfType& operator=(const SelfType& other);
|
||||
|
||||
SelfType operator++(int) {
|
||||
SelfType temp(*this);
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType operator--(int) {
|
||||
SelfType temp(*this);
|
||||
--*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
SelfType& operator--() {
|
||||
decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator++() {
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! The return value of non-const iterators can be
|
||||
* changed, so the these functions are not const
|
||||
* because the returned references/pointers can be used
|
||||
* to change state of the base class.
|
||||
*/
|
||||
reference operator*() const { return const_cast<reference>(deref()); }
|
||||
pointer operator->() const { return const_cast<pointer>(&deref()); }
|
||||
};
|
||||
|
||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#endif // JSON_H_INCLUDED
|
@ -1,28 +0,0 @@
|
||||
#ifndef JSON_VERSION_H_INCLUDED
|
||||
#define JSON_VERSION_H_INCLUDED
|
||||
|
||||
// Note: version must be updated in three places when doing a release. This
|
||||
// annoying process ensures that amalgamate, CMake, and meson all report the
|
||||
// correct version.
|
||||
// 1. /meson.build
|
||||
// 2. /include/json/version.h
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
(JSONCPP_VERSION_PATCH << 8))
|
||||
|
||||
#ifdef JSONCPP_USING_SECURE_MEMORY
|
||||
#undef JSONCPP_USING_SECURE_MEMORY
|
||||
#endif
|
||||
#define JSONCPP_USING_SECURE_MEMORY 0
|
||||
// If non-zero, the library zeroes any memory that it has allocated before
|
||||
// it frees its memory.
|
||||
|
||||
#endif // JSON_VERSION_H_INCLUDED
|
@ -1,370 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_WRITER_H_INCLUDED
|
||||
#define JSON_WRITER_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "value.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
|
||||
namespace Json {
|
||||
|
||||
class Value;
|
||||
|
||||
/**
|
||||
*
|
||||
* Usage:
|
||||
* \code
|
||||
* using namespace Json;
|
||||
* void writeToStdout(StreamWriter::Factory const& factory, Value const& value)
|
||||
* { std::unique_ptr<StreamWriter> const writer( factory.newStreamWriter());
|
||||
* writer->write(value, &std::cout);
|
||||
* std::cout << std::endl; // add lf and flush
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
class JSON_API StreamWriter {
|
||||
protected:
|
||||
OStream* sout_; // not owned; will not delete
|
||||
public:
|
||||
StreamWriter();
|
||||
virtual ~StreamWriter();
|
||||
/** Write Value into document as configured in sub-class.
|
||||
* Do not take ownership of sout, but maintain a reference during function.
|
||||
* \pre sout != NULL
|
||||
* \return zero on success (For now, we always return zero, so check the
|
||||
* stream instead.) \throw std::exception possibly, depending on
|
||||
* configuration
|
||||
*/
|
||||
virtual int write(Value const& root, OStream* sout) = 0;
|
||||
|
||||
/** \brief A simple abstract factory.
|
||||
*/
|
||||
class JSON_API Factory {
|
||||
public:
|
||||
virtual ~Factory();
|
||||
/** \brief Allocate a CharReader via operator new().
|
||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||
*/
|
||||
virtual StreamWriter* newStreamWriter() const = 0;
|
||||
}; // Factory
|
||||
}; // StreamWriter
|
||||
|
||||
/** \brief Write into stringstream, then return string, for convenience.
|
||||
* A StreamWriter will be created from the factory, used, and then deleted.
|
||||
*/
|
||||
String JSON_API writeString(StreamWriter::Factory const& factory,
|
||||
Value const& root);
|
||||
|
||||
/** \brief Build a StreamWriter implementation.
|
||||
|
||||
* Usage:
|
||||
* \code
|
||||
* using namespace Json;
|
||||
* Value value = ...;
|
||||
* StreamWriterBuilder builder;
|
||||
* builder["commentStyle"] = "None";
|
||||
* builder["indentation"] = " "; // or whatever you like
|
||||
* std::unique_ptr<Json::StreamWriter> writer(
|
||||
* builder.newStreamWriter());
|
||||
* writer->write(value, &std::cout);
|
||||
* std::cout << std::endl; // add lf and flush
|
||||
* \endcode
|
||||
*/
|
||||
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
|
||||
public:
|
||||
// Note: We use a Json::Value so that we can add data-members to this class
|
||||
// without a major version bump.
|
||||
/** Configuration of this builder.
|
||||
* Available settings (case-sensitive):
|
||||
* - "commentStyle": "None" or "All"
|
||||
* - "indentation": "<anything>".
|
||||
* - Setting this to an empty string also omits newline characters.
|
||||
* - "enableYAMLCompatibility": false or true
|
||||
* - slightly change the whitespace around colons
|
||||
* - "dropNullPlaceholders": false or true
|
||||
* - Drop the "null" string from the writer's output for nullValues.
|
||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
||||
* fed to a browser's JavaScript, it makes for smaller output and the
|
||||
* browser can handle the output just fine.
|
||||
* - "useSpecialFloats": false or true
|
||||
* - If true, outputs non-finite floating point values in the following way:
|
||||
* NaN values as "NaN", positive infinity as "Infinity", and negative
|
||||
* infinity as "-Infinity".
|
||||
* - "precision": int
|
||||
* - Number of precision digits for formatting of real values.
|
||||
* - "precisionType": "significant"(default) or "decimal"
|
||||
* - Type of precision for formatting of real values.
|
||||
* - "emitUTF8": false or true
|
||||
* - If true, outputs raw UTF8 strings instead of escaping them.
|
||||
|
||||
* You can examine 'settings_` yourself
|
||||
* to see the defaults. You can also write and read them just like any
|
||||
* JSON Value.
|
||||
* \sa setDefaults()
|
||||
*/
|
||||
Json::Value settings_;
|
||||
|
||||
StreamWriterBuilder();
|
||||
~StreamWriterBuilder() override;
|
||||
|
||||
/**
|
||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||
*/
|
||||
StreamWriter* newStreamWriter() const override;
|
||||
|
||||
/** \return true if 'settings' are legal and consistent;
|
||||
* otherwise, indicate bad settings via 'invalid'.
|
||||
*/
|
||||
bool validate(Json::Value* invalid) const;
|
||||
/** A simple way to update a specific setting.
|
||||
*/
|
||||
Value& operator[](const String& key);
|
||||
|
||||
/** Called by ctor, but you can use this to reset settings_.
|
||||
* \pre 'settings' != NULL (but Json::null is fine)
|
||||
* \remark Defaults:
|
||||
* \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
|
||||
*/
|
||||
static void setDefaults(Json::Value* settings);
|
||||
};
|
||||
|
||||
/** \brief Abstract class for writers.
|
||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||
*/
|
||||
class JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
virtual String write(const Value& root) = 0;
|
||||
};
|
||||
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
|
||||
*without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human'
|
||||
*consumption,
|
||||
* but may be useful to support feature such as RPC where bandwidth is limited.
|
||||
* \sa Reader, Value
|
||||
* \deprecated Use StreamWriterBuilder.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSON_API FastWriter
|
||||
: public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
~FastWriter() override = default;
|
||||
|
||||
void enableYAMLCompatibility();
|
||||
|
||||
/** \brief Drop the "null" string from the writer's output for nullValues.
|
||||
* Strictly speaking, this is not valid JSON. But when the output is being
|
||||
* fed to a browser's JavaScript, it makes for smaller output and the
|
||||
* browser can handle the output just fine.
|
||||
*/
|
||||
void dropNullPlaceholders();
|
||||
|
||||
void omitEndingLineFeed();
|
||||
|
||||
public: // overridden from Writer
|
||||
String write(const Value& root) override;
|
||||
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
|
||||
String document_;
|
||||
bool yamlCompatibilityEnabled_{false};
|
||||
bool dropNullPlaceholders_{false};
|
||||
bool omitEndingLineFeed_{false};
|
||||
};
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
*human friendly way.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per
|
||||
*line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value
|
||||
*types,
|
||||
* and all the values fit on one lines, then print the array on a single
|
||||
*line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputted according to their
|
||||
*#CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
* \deprecated Use StreamWriterBuilder.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSON_API
|
||||
StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
~StyledWriter() override = default;
|
||||
|
||||
public: // overridden from Writer
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param root Value to serialize.
|
||||
* \return String containing the JSON document that represents the root value.
|
||||
*/
|
||||
String write(const Value& root) override;
|
||||
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
void writeArrayValue(const Value& value);
|
||||
bool isMultilineArray(const Value& value);
|
||||
void pushValue(const String& value);
|
||||
void writeIndent();
|
||||
void writeWithIndent(const String& value);
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue(const Value& root);
|
||||
void writeCommentAfterValueOnSameLine(const Value& root);
|
||||
static bool hasCommentForValue(const Value& value);
|
||||
static String normalizeEOL(const String& text);
|
||||
|
||||
using ChildValues = std::vector<String>;
|
||||
|
||||
ChildValues childValues_;
|
||||
String document_;
|
||||
String indentString_;
|
||||
unsigned int rightMargin_{74};
|
||||
unsigned int indentSize_{3};
|
||||
bool addChildValues_{false};
|
||||
};
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||
human friendly way,
|
||||
to a stream rather than to a string.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per
|
||||
line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value
|
||||
types,
|
||||
* and all the values fit on one lines, then print the array on a single
|
||||
line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputted according to their
|
||||
#CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
* \deprecated Use StreamWriterBuilder.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSON_API
|
||||
StyledStreamWriter {
|
||||
public:
|
||||
/**
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
*/
|
||||
StyledStreamWriter(String indentation = "\t");
|
||||
~StyledStreamWriter() = default;
|
||||
|
||||
public:
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||
* \param root Value to serialize.
|
||||
* \note There is no point in deriving from Writer, since write() should not
|
||||
* return a value.
|
||||
*/
|
||||
void write(OStream& out, const Value& root);
|
||||
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
void writeArrayValue(const Value& value);
|
||||
bool isMultilineArray(const Value& value);
|
||||
void pushValue(const String& value);
|
||||
void writeIndent();
|
||||
void writeWithIndent(const String& value);
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue(const Value& root);
|
||||
void writeCommentAfterValueOnSameLine(const Value& root);
|
||||
static bool hasCommentForValue(const Value& value);
|
||||
static String normalizeEOL(const String& text);
|
||||
|
||||
using ChildValues = std::vector<String>;
|
||||
|
||||
ChildValues childValues_;
|
||||
OStream* document_;
|
||||
String indentString_;
|
||||
unsigned int rightMargin_{74};
|
||||
String indentation_;
|
||||
bool addChildValues_ : 1;
|
||||
bool indented_ : 1;
|
||||
};
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#if defined(JSON_HAS_INT64)
|
||||
String JSON_API valueToString(Int value);
|
||||
String JSON_API valueToString(UInt value);
|
||||
#endif // if defined(JSON_HAS_INT64)
|
||||
String JSON_API valueToString(LargestInt value);
|
||||
String JSON_API valueToString(LargestUInt value);
|
||||
String JSON_API valueToString(
|
||||
double value, unsigned int precision = Value::defaultRealPrecision,
|
||||
PrecisionType precisionType = PrecisionType::significantDigits);
|
||||
String JSON_API valueToString(bool value);
|
||||
String JSON_API valueToQuotedString(const char* value);
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
JSON_API OStream& operator<<(OStream&, const Value& root);
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(pop)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#endif // JSON_WRITER_H_INCLUDED
|
@ -1,138 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <json/config.h>
|
||||
#endif
|
||||
|
||||
// Also support old flag NO_LOCALE_SUPPORT
|
||||
#ifdef NO_LOCALE_SUPPORT
|
||||
#define JSONCPP_NO_LOCALE_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifndef JSONCPP_NO_LOCALE_SUPPORT
|
||||
#include <clocale>
|
||||
#endif
|
||||
|
||||
/* This header provides common string manipulation support, such as UTF-8,
|
||||
* portable conversion from/to string...
|
||||
*
|
||||
* It is an internal header that must not be exposed.
|
||||
*/
|
||||
|
||||
namespace Json {
|
||||
static inline char getDecimalPoint() {
|
||||
#ifdef JSONCPP_NO_LOCALE_SUPPORT
|
||||
return '\0';
|
||||
#else
|
||||
struct lconv* lc = localeconv();
|
||||
return lc ? *(lc->decimal_point) : '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Converts a unicode code-point to UTF-8.
|
||||
static inline String codePointToUTF8(unsigned int cp) {
|
||||
String result;
|
||||
|
||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||
|
||||
if (cp <= 0x7f) {
|
||||
result.resize(1);
|
||||
result[0] = static_cast<char>(cp);
|
||||
} else if (cp <= 0x7FF) {
|
||||
result.resize(2);
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||
} else if (cp <= 0xFFFF) {
|
||||
result.resize(3);
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
|
||||
} else if (cp <= 0x10FFFF) {
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum {
|
||||
/// Constant that specify the size of the buffer that must be passed to
|
||||
/// uintToString.
|
||||
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
|
||||
};
|
||||
|
||||
// Defines a char buffer for use with uintToString().
|
||||
using UIntToStringBuffer = char[uintToStringBufferSize];
|
||||
|
||||
/** Converts an unsigned integer to string.
|
||||
* @param value Unsigned integer to convert to string
|
||||
* @param current Input/Output string buffer.
|
||||
* Must have at least uintToStringBufferSize chars free.
|
||||
*/
|
||||
static inline void uintToString(LargestUInt value, char*& current) {
|
||||
*--current = 0;
|
||||
do {
|
||||
*--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
|
||||
value /= 10;
|
||||
} while (value != 0);
|
||||
}
|
||||
|
||||
/** Change ',' to '.' everywhere in buffer.
|
||||
*
|
||||
* We had a sophisticated way, but it did not work in WinCE.
|
||||
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
|
||||
*/
|
||||
template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
|
||||
for (; begin != end; ++begin) {
|
||||
if (*begin == ',') {
|
||||
*begin = '.';
|
||||
}
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
|
||||
char decimalPoint = getDecimalPoint();
|
||||
if (decimalPoint == '\0' || decimalPoint == '.') {
|
||||
return;
|
||||
}
|
||||
for (; begin != end; ++begin) {
|
||||
if (*begin == '.') {
|
||||
*begin = decimalPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return iterator that would be the new end of the range [begin,end), if we
|
||||
* were to delete zeros in the end of string, but not the last zero before '.'.
|
||||
*/
|
||||
template <typename Iter>
|
||||
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
|
||||
for (; begin != end; --end) {
|
||||
if (*(end - 1) != '0') {
|
||||
return end;
|
||||
}
|
||||
// Don't delete the last zero before the decimal point.
|
||||
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
|
||||
if (precision) {
|
||||
return end;
|
||||
}
|
||||
return end - 2;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
@ -1,156 +0,0 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
// included by json_value.cpp
|
||||
|
||||
namespace Json {
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueIteratorBase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase() : current_() {}
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
: current_(current), isNull_(false) {}
|
||||
|
||||
Value& ValueIteratorBase::deref() { return current_->second; }
|
||||
const Value& ValueIteratorBase::deref() const { return current_->second; }
|
||||
|
||||
void ValueIteratorBase::increment() { ++current_; }
|
||||
|
||||
void ValueIteratorBase::decrement() { --current_; }
|
||||
|
||||
ValueIteratorBase::difference_type
|
||||
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
||||
// Iterator for null value are initialized using the default
|
||||
// constructor, which initialize current_ to the default
|
||||
// std::map::iterator. As begin() and end() are two instance
|
||||
// of the default std::map::iterator, they can not be compared.
|
||||
// To allow this, we handle this comparison specifically.
|
||||
if (isNull_ && other.isNull_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Usage of std::distance is not portable (does not compile with Sun Studio 12
|
||||
// RogueWave STL,
|
||||
// which is the one used by default).
|
||||
// Using a portable hand-made version for non random iterator instead:
|
||||
// return difference_type( std::distance( current_, other.current_ ) );
|
||||
difference_type myDistance = 0;
|
||||
for (Value::ObjectValues::iterator it = current_; it != other.current_;
|
||||
++it) {
|
||||
++myDistance;
|
||||
}
|
||||
return myDistance;
|
||||
}
|
||||
|
||||
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
||||
if (isNull_) {
|
||||
return other.isNull_;
|
||||
}
|
||||
return current_ == other.current_;
|
||||
}
|
||||
|
||||
void ValueIteratorBase::copy(const SelfType& other) {
|
||||
current_ = other.current_;
|
||||
isNull_ = other.isNull_;
|
||||
}
|
||||
|
||||
Value ValueIteratorBase::key() const {
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if (czstring.data()) {
|
||||
if (czstring.isStaticString())
|
||||
return Value(StaticString(czstring.data()));
|
||||
return Value(czstring.data(), czstring.data() + czstring.length());
|
||||
}
|
||||
return Value(czstring.index());
|
||||
}
|
||||
|
||||
UInt ValueIteratorBase::index() const {
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if (!czstring.data())
|
||||
return czstring.index();
|
||||
return Value::UInt(-1);
|
||||
}
|
||||
|
||||
String ValueIteratorBase::name() const {
|
||||
char const* keey;
|
||||
char const* end;
|
||||
keey = memberName(&end);
|
||||
if (!keey)
|
||||
return String();
|
||||
return String(keey, end);
|
||||
}
|
||||
|
||||
char const* ValueIteratorBase::memberName() const {
|
||||
const char* cname = (*current_).first.data();
|
||||
return cname ? cname : "";
|
||||
}
|
||||
|
||||
char const* ValueIteratorBase::memberName(char const** end) const {
|
||||
const char* cname = (*current_).first.data();
|
||||
if (!cname) {
|
||||
*end = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
*end = cname + (*current_).first.length();
|
||||
return cname;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueConstIterator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueConstIterator::ValueConstIterator() = default;
|
||||
|
||||
ValueConstIterator::ValueConstIterator(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
: ValueIteratorBase(current) {}
|
||||
|
||||
ValueConstIterator::ValueConstIterator(ValueIterator const& other)
|
||||
: ValueIteratorBase(other) {}
|
||||
|
||||
ValueConstIterator& ValueConstIterator::
|
||||
operator=(const ValueIteratorBase& other) {
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueIterator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIterator::ValueIterator() = default;
|
||||
|
||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||
: ValueIteratorBase(current) {}
|
||||
|
||||
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||
: ValueIteratorBase(other) {
|
||||
throwRuntimeError("ConstIterator to Iterator should never be allowed.");
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator(const ValueIterator& other) = default;
|
||||
|
||||
ValueIterator& ValueIterator::operator=(const SelfType& other) {
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Json
|
@ -1 +0,0 @@
|
||||
@JSONCPP_VERSION@
|
@ -1,72 +0,0 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
/* ============================================================
|
||||
* Platform options
|
||||
* ============================================================ */
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define __DARWIN_C_SOURCE
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__SYMBIAN32__) || defined(__QNX__)
|
||||
# define _XOPEN_SOURCE 700
|
||||
# define __BSD_VISIBLE 1
|
||||
# define HAVE_NETINET_IN_H
|
||||
#else
|
||||
# define _XOPEN_SOURCE 700
|
||||
# define _DEFAULT_SOURCE 1
|
||||
# define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#define OPENSSL_LOAD_CONF
|
||||
|
||||
/* ============================================================
|
||||
* Compatibility defines
|
||||
* ============================================================ */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
# define snprintf sprintf_s
|
||||
# define EPROTO ECONNABORTED
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
# ifndef strcasecmp
|
||||
# define strcasecmp strcmpi
|
||||
# endif
|
||||
# define strtok_r strtok_s
|
||||
# define strerror_r(e, b, l) strerror_s(b, l, e)
|
||||
#endif
|
||||
|
||||
|
||||
#define uthash_malloc(sz) mosquitto__malloc(sz)
|
||||
#define uthash_free(ptr,sz) mosquitto__free(ptr)
|
||||
|
||||
|
||||
#ifdef WITH_TLS
|
||||
# include <openssl/conf.h>
|
||||
# if defined(WITH_TLS_PSK) && !defined(OPENSSL_NO_PSK)
|
||||
# define FINAL_WITH_TLS_PSK
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __COVERITY__
|
||||
# include <stdint.h>
|
||||
/* These are "wrong", but we don't use them so it doesn't matter */
|
||||
# define _Float32 uint32_t
|
||||
# define _Float32x uint32_t
|
||||
# define _Float64 uint64_t
|
||||
# define _Float64x uint64_t
|
||||
# define _Float128 uint64_t
|
||||
#endif
|
||||
|
||||
#define UNUSED(A) (void)(A)
|
||||
|
||||
/* Android Bionic libpthread implementation doesn't have pthread_cancel */
|
||||
#ifndef ANDROID
|
||||
# define HAVE_PTHREAD_CANCEL
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,274 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
|
||||
int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
|
||||
{
|
||||
return mosquitto_publish_v5(mosq, mid, topic, payloadlen, payload, qos, retain, NULL);
|
||||
}
|
||||
|
||||
int mosquitto_publish_v5(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain, const mosquitto_property *properties)
|
||||
{
|
||||
struct mosquitto_message_all *message;
|
||||
uint16_t local_mid;
|
||||
const mosquitto_property *p;
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property *properties_copy = NULL;
|
||||
mosquitto_property local_property;
|
||||
bool have_topic_alias;
|
||||
int rc;
|
||||
int tlen = 0;
|
||||
uint32_t remaining_length;
|
||||
|
||||
if(!mosq || qos<0 || qos>2) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
if(qos > mosq->maximum_qos) return MOSQ_ERR_QOS_NOT_SUPPORTED;
|
||||
|
||||
if(properties){
|
||||
if(properties->client_generated){
|
||||
outgoing_properties = properties;
|
||||
}else{
|
||||
memcpy(&local_property, properties, sizeof(mosquitto_property));
|
||||
local_property.client_generated = true;
|
||||
local_property.next = NULL;
|
||||
outgoing_properties = &local_property;
|
||||
}
|
||||
rc = mosquitto_property_check_all(CMD_PUBLISH, outgoing_properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
if(!topic || STREMPTY(topic)){
|
||||
if(topic) topic = NULL;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5){
|
||||
p = outgoing_properties;
|
||||
have_topic_alias = false;
|
||||
while(p){
|
||||
if(p->identifier == MQTT_PROP_TOPIC_ALIAS){
|
||||
have_topic_alias = true;
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
if(have_topic_alias == false){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
}else{
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
}else{
|
||||
tlen = strlen(topic);
|
||||
if(mosquitto_validate_utf8(topic, tlen)) return MOSQ_ERR_MALFORMED_UTF8;
|
||||
if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE;
|
||||
if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if(mosq->maximum_packet_size > 0){
|
||||
remaining_length = 1 + 2+tlen + payloadlen + property__get_length_all(outgoing_properties);
|
||||
if(qos > 0){
|
||||
remaining_length++;
|
||||
}
|
||||
if(packet__check_oversize(mosq, remaining_length)){
|
||||
return MOSQ_ERR_OVERSIZE_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
local_mid = mosquitto__mid_generate(mosq);
|
||||
if(mid){
|
||||
*mid = local_mid;
|
||||
}
|
||||
|
||||
if(qos == 0){
|
||||
return send__publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false, outgoing_properties, NULL, 0);
|
||||
}else{
|
||||
if(outgoing_properties){
|
||||
rc = mosquitto_property_copy_all(&properties_copy, outgoing_properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all));
|
||||
if(!message){
|
||||
mosquitto_property_free_all(&properties_copy);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
message->next = NULL;
|
||||
message->timestamp = mosquitto_time();
|
||||
message->msg.mid = local_mid;
|
||||
if(topic){
|
||||
message->msg.topic = mosquitto__strdup(topic);
|
||||
if(!message->msg.topic){
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties_copy);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
if(payloadlen){
|
||||
message->msg.payloadlen = payloadlen;
|
||||
message->msg.payload = mosquitto__malloc(payloadlen*sizeof(uint8_t));
|
||||
if(!message->msg.payload){
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties_copy);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
memcpy(message->msg.payload, payload, payloadlen*sizeof(uint8_t));
|
||||
}else{
|
||||
message->msg.payloadlen = 0;
|
||||
message->msg.payload = NULL;
|
||||
}
|
||||
message->msg.qos = qos;
|
||||
message->msg.retain = retain;
|
||||
message->dup = false;
|
||||
message->properties = properties_copy;
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
message->state = mosq_ms_invalid;
|
||||
message__queue(mosq, message, mosq_md_out);
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
|
||||
{
|
||||
return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_subscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, int qos, int options, const mosquitto_property *properties)
|
||||
{
|
||||
return mosquitto_subscribe_multiple(mosq, mid, 1, (char *const *const)&sub, qos, options, properties);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_subscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, int qos, int options, const mosquitto_property *properties)
|
||||
{
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property local_property;
|
||||
int i;
|
||||
int rc;
|
||||
uint32_t remaining_length = 0;
|
||||
int slen;
|
||||
|
||||
if(!mosq || !sub_count || !sub) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
if(qos < 0 || qos > 2) return MOSQ_ERR_INVAL;
|
||||
if((options & 0x30) == 0x30 || (options & 0xC0) != 0) return MOSQ_ERR_INVAL;
|
||||
if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
|
||||
|
||||
if(properties){
|
||||
if(properties->client_generated){
|
||||
outgoing_properties = properties;
|
||||
}else{
|
||||
memcpy(&local_property, properties, sizeof(mosquitto_property));
|
||||
local_property.client_generated = true;
|
||||
local_property.next = NULL;
|
||||
outgoing_properties = &local_property;
|
||||
}
|
||||
rc = mosquitto_property_check_all(CMD_SUBSCRIBE, outgoing_properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
for(i=0; i<sub_count; i++){
|
||||
if(mosquitto_sub_topic_check(sub[i])) return MOSQ_ERR_INVAL;
|
||||
slen = strlen(sub[i]);
|
||||
if(mosquitto_validate_utf8(sub[i], slen)) return MOSQ_ERR_MALFORMED_UTF8;
|
||||
remaining_length += 2+slen + 1;
|
||||
}
|
||||
|
||||
if(mosq->maximum_packet_size > 0){
|
||||
remaining_length += 2 + property__get_length_all(outgoing_properties);
|
||||
if(packet__check_oversize(mosq, remaining_length)){
|
||||
return MOSQ_ERR_OVERSIZE_PACKET;
|
||||
}
|
||||
}
|
||||
if(mosq->protocol == mosq_p_mqtt311 || mosq->protocol == mosq_p_mqtt31){
|
||||
options = 0;
|
||||
}
|
||||
|
||||
return send__subscribe(mosq, mid, sub_count, sub, qos|options, outgoing_properties);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub)
|
||||
{
|
||||
return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, NULL);
|
||||
}
|
||||
|
||||
int mosquitto_unsubscribe_v5(struct mosquitto *mosq, int *mid, const char *sub, const mosquitto_property *properties)
|
||||
{
|
||||
return mosquitto_unsubscribe_multiple(mosq, mid, 1, (char *const *const)&sub, properties);
|
||||
}
|
||||
|
||||
int mosquitto_unsubscribe_multiple(struct mosquitto *mosq, int *mid, int sub_count, char *const *const sub, const mosquitto_property *properties)
|
||||
{
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property local_property;
|
||||
int rc;
|
||||
int i;
|
||||
uint32_t remaining_length = 0;
|
||||
int slen;
|
||||
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
|
||||
|
||||
if(properties){
|
||||
if(properties->client_generated){
|
||||
outgoing_properties = properties;
|
||||
}else{
|
||||
memcpy(&local_property, properties, sizeof(mosquitto_property));
|
||||
local_property.client_generated = true;
|
||||
local_property.next = NULL;
|
||||
outgoing_properties = &local_property;
|
||||
}
|
||||
rc = mosquitto_property_check_all(CMD_UNSUBSCRIBE, outgoing_properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
for(i=0; i<sub_count; i++){
|
||||
if(mosquitto_sub_topic_check(sub[i])) return MOSQ_ERR_INVAL;
|
||||
slen = strlen(sub[i]);
|
||||
if(mosquitto_validate_utf8(sub[i], slen)) return MOSQ_ERR_MALFORMED_UTF8;
|
||||
remaining_length += 2+slen;
|
||||
}
|
||||
|
||||
if(mosq->maximum_packet_size > 0){
|
||||
remaining_length += 2 + property__get_length_all(outgoing_properties);
|
||||
if(packet__check_oversize(mosq, remaining_length)){
|
||||
return MOSQ_ERR_OVERSIZE_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
return send__unsubscribe(mosq, mid, sub_count, sub, outgoing_properties);
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "alias_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
|
||||
int alias__add(struct mosquitto *mosq, const char *topic, int alias)
|
||||
{
|
||||
int i;
|
||||
struct mosquitto__alias *aliases;
|
||||
|
||||
for(i=0; i<mosq->alias_count; i++){
|
||||
if(mosq->aliases[i].alias == alias){
|
||||
mosquitto__free(mosq->aliases[i].topic);
|
||||
mosq->aliases[i].topic = mosquitto__strdup(topic);
|
||||
if(mosq->aliases[i].topic){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* New alias */
|
||||
aliases = mosquitto__realloc(mosq->aliases, sizeof(struct mosquitto__alias)*(mosq->alias_count+1));
|
||||
if(!aliases) return MOSQ_ERR_NOMEM;
|
||||
|
||||
mosq->aliases = aliases;
|
||||
mosq->aliases[mosq->alias_count].alias = alias;
|
||||
mosq->aliases[mosq->alias_count].topic = mosquitto__strdup(topic);
|
||||
if(!mosq->aliases[mosq->alias_count].topic){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
mosq->alias_count++;
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int alias__find(struct mosquitto *mosq, char **topic, int alias)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<mosq->alias_count; i++){
|
||||
if(mosq->aliases[i].alias == alias){
|
||||
*topic = mosquitto__strdup(mosq->aliases[i].topic);
|
||||
if(*topic){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
|
||||
void alias__free_all(struct mosquitto *mosq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<mosq->alias_count; i++){
|
||||
mosquitto__free(mosq->aliases[i].topic);
|
||||
}
|
||||
mosquitto__free(mosq->aliases);
|
||||
mosq->aliases = NULL;
|
||||
mosq->alias_count = 0;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#ifndef ALIAS_MOSQ_H
|
||||
#define ALIAS_MOSQ_H
|
||||
|
||||
#include "mosquitto_internal.h"
|
||||
|
||||
int alias__add(struct mosquitto *mosq, const char *topic, int alias);
|
||||
int alias__find(struct mosquitto *mosq, char **topic, int alias);
|
||||
void alias__free_all(struct mosquitto *mosq);
|
||||
|
||||
#endif
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
|
||||
|
||||
void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_connect = on_connect;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_connect_with_flags_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_connect_with_flags = on_connect;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_connect_v5_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int, int, const mosquitto_property *))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_connect_v5 = on_connect;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_disconnect = on_disconnect;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_disconnect_v5_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int, const mosquitto_property *))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_disconnect_v5 = on_disconnect;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_publish = on_publish;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_publish_v5_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int, int, const mosquitto_property *props))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_publish_v5 = on_publish;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_message = on_message;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_message_v5_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *, const mosquitto_property *props))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_message_v5 = on_message;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_subscribe = on_subscribe;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_subscribe_v5_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *, const mosquitto_property *props))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_subscribe_v5 = on_subscribe;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_unsubscribe = on_unsubscribe;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_unsubscribe_v5_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int, const mosquitto_property *props))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
mosq->on_unsubscribe_v5 = on_unsubscribe;
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *))
|
||||
{
|
||||
pthread_mutex_lock(&mosq->log_callback_mutex);
|
||||
mosq->on_log = on_log;
|
||||
pthread_mutex_unlock(&mosq->log_callback_mutex);
|
||||
}
|
||||
|
@ -1,296 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "send_mosq.h"
|
||||
#include "socks_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
static char alphanum[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties);
|
||||
static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address);
|
||||
|
||||
|
||||
static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
if(!host || port <= 0) return MOSQ_ERR_INVAL;
|
||||
|
||||
if(mosq->id == NULL && (mosq->protocol == mosq_p_mqtt31 || mosq->protocol == mosq_p_mqtt311)){
|
||||
mosq->id = (char *)mosquitto__calloc(24, sizeof(char));
|
||||
if(!mosq->id){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
mosq->id[0] = 'm';
|
||||
mosq->id[1] = 'o';
|
||||
mosq->id[2] = 's';
|
||||
mosq->id[3] = 'q';
|
||||
mosq->id[4] = '-';
|
||||
|
||||
rc = util__random_bytes(&mosq->id[5], 18);
|
||||
if(rc) return rc;
|
||||
|
||||
for(i=5; i<23; i++){
|
||||
mosq->id[i] = alphanum[(mosq->id[i]&0x7F)%(sizeof(alphanum)-1)];
|
||||
}
|
||||
}
|
||||
|
||||
mosquitto__free(mosq->host);
|
||||
mosq->host = mosquitto__strdup(host);
|
||||
if(!mosq->host) return MOSQ_ERR_NOMEM;
|
||||
mosq->port = port;
|
||||
|
||||
mosquitto__free(mosq->bind_address);
|
||||
if(bind_address){
|
||||
mosq->bind_address = mosquitto__strdup(bind_address);
|
||||
if(!mosq->bind_address) return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
mosq->keepalive = keepalive;
|
||||
mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum;
|
||||
mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum;
|
||||
|
||||
if(mosq->sockpairR != INVALID_SOCKET){
|
||||
COMPAT_CLOSE(mosq->sockpairR);
|
||||
mosq->sockpairR = INVALID_SOCKET;
|
||||
}
|
||||
if(mosq->sockpairW != INVALID_SOCKET){
|
||||
COMPAT_CLOSE(mosq->sockpairW);
|
||||
mosq->sockpairW = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if(net__socketpair(&mosq->sockpairR, &mosq->sockpairW)){
|
||||
log__printf(mosq, MOSQ_LOG_WARNING,
|
||||
"Warning: Unable to open socket pair, outgoing publish commands may be delayed.");
|
||||
}
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive)
|
||||
{
|
||||
return mosquitto_connect_bind(mosq, host, port, keepalive, NULL);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
|
||||
{
|
||||
return mosquitto_connect_bind_v5(mosq, host, port, keepalive, bind_address, NULL);
|
||||
}
|
||||
|
||||
int mosquitto_connect_bind_v5(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address, const mosquitto_property *properties)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if(properties){
|
||||
rc = mosquitto_property_check_all(CMD_CONNECT, properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address);
|
||||
if(rc) return rc;
|
||||
|
||||
mosquitto__set_state(mosq, mosq_cs_new);
|
||||
|
||||
return mosquitto__reconnect(mosq, true, properties);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive)
|
||||
{
|
||||
return mosquitto_connect_bind_async(mosq, host, port, keepalive, NULL);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address)
|
||||
{
|
||||
int rc = mosquitto__connect_init(mosq, host, port, keepalive, bind_address);
|
||||
if(rc) return rc;
|
||||
|
||||
return mosquitto__reconnect(mosq, false, NULL);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_reconnect_async(struct mosquitto *mosq)
|
||||
{
|
||||
return mosquitto__reconnect(mosq, false, NULL);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_reconnect(struct mosquitto *mosq)
|
||||
{
|
||||
return mosquitto__reconnect(mosq, true, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mosquitto_property *properties)
|
||||
{
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property local_property;
|
||||
int rc;
|
||||
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
|
||||
if(properties){
|
||||
if(properties->client_generated){
|
||||
outgoing_properties = properties;
|
||||
}else{
|
||||
memcpy(&local_property, properties, sizeof(mosquitto_property));
|
||||
local_property.client_generated = true;
|
||||
local_property.next = NULL;
|
||||
outgoing_properties = &local_property;
|
||||
}
|
||||
rc = mosquitto_property_check_all(CMD_CONNECT, outgoing_properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mosq->msgtime_mutex);
|
||||
mosq->last_msg_in = mosquitto_time();
|
||||
mosq->next_msg_out = mosq->last_msg_in + mosq->keepalive;
|
||||
pthread_mutex_unlock(&mosq->msgtime_mutex);
|
||||
|
||||
mosq->ping_t = 0;
|
||||
|
||||
packet__cleanup(&mosq->in_packet);
|
||||
|
||||
packet__cleanup_all(mosq);
|
||||
|
||||
message__reconnect_reset(mosq);
|
||||
|
||||
if(mosq->sock != INVALID_SOCKET){
|
||||
net__socket_close(mosq); //close socket
|
||||
}
|
||||
|
||||
#ifdef WITH_SOCKS
|
||||
if(mosq->socks5_host){
|
||||
rc = net__socket_connect(mosq, mosq->socks5_host, mosq->socks5_port, mosq->bind_address, blocking);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
rc = net__socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking);
|
||||
}
|
||||
if(rc>0){
|
||||
mosquitto__set_state(mosq, mosq_cs_connect_pending);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef WITH_SOCKS
|
||||
if(mosq->socks5_host){
|
||||
mosquitto__set_state(mosq, mosq_cs_socks5_new);
|
||||
return socks5__send(mosq);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
mosquitto__set_state(mosq, mosq_cs_connected);
|
||||
rc = send__connect(mosq, mosq->keepalive, mosq->clean_start, outgoing_properties);
|
||||
if(rc){
|
||||
packet__cleanup_all(mosq);
|
||||
net__socket_close(mosq);
|
||||
mosquitto__set_state(mosq, mosq_cs_new);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_disconnect(struct mosquitto *mosq)
|
||||
{
|
||||
return mosquitto_disconnect_v5(mosq, 0, NULL);
|
||||
}
|
||||
|
||||
int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties)
|
||||
{
|
||||
const mosquitto_property *outgoing_properties = NULL;
|
||||
mosquitto_property local_property;
|
||||
int rc;
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED;
|
||||
|
||||
if(properties){
|
||||
if(properties->client_generated){
|
||||
outgoing_properties = properties;
|
||||
}else{
|
||||
memcpy(&local_property, properties, sizeof(mosquitto_property));
|
||||
local_property.client_generated = true;
|
||||
local_property.next = NULL;
|
||||
outgoing_properties = &local_property;
|
||||
}
|
||||
rc = mosquitto_property_check_all(CMD_DISCONNECT, outgoing_properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
mosquitto__set_state(mosq, mosq_cs_disconnected);
|
||||
if(mosq->sock == INVALID_SOCKET){
|
||||
return MOSQ_ERR_NO_CONN;
|
||||
}else{
|
||||
return send__disconnect(mosq, reason_code, outgoing_properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties)
|
||||
{
|
||||
mosquitto__set_state(mosq, mosq_cs_disconnected);
|
||||
net__socket_close(mosq);
|
||||
|
||||
/* Free data and reset values */
|
||||
pthread_mutex_lock(&mosq->out_packet_mutex);
|
||||
mosq->current_out_packet = mosq->out_packet;
|
||||
if(mosq->out_packet){
|
||||
mosq->out_packet = mosq->out_packet->next;
|
||||
if(!mosq->out_packet){
|
||||
mosq->out_packet_last = NULL;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->out_packet_mutex);
|
||||
|
||||
pthread_mutex_lock(&mosq->msgtime_mutex);
|
||||
mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
|
||||
pthread_mutex_unlock(&mosq->msgtime_mutex);
|
||||
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_disconnect){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_disconnect(mosq, mosq->userdata, reason_code);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_disconnect_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_disconnect_v5(mosq, mosq->userdata, reason_code, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
pthread_mutex_unlock(&mosq->current_out_packet_mutex);
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
#ifndef DUMMYPTHREAD_H
|
||||
#define DUMMYPTHREAD_H
|
||||
|
||||
#define pthread_create(A, B, C, D)
|
||||
#define pthread_join(A, B)
|
||||
#define pthread_cancel(A)
|
||||
|
||||
#define pthread_mutex_init(A, B)
|
||||
#define pthread_mutex_destroy(A)
|
||||
#define pthread_mutex_lock(A)
|
||||
#define pthread_mutex_unlock(A)
|
||||
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2018 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logging_mosq.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "property_mosq.h"
|
||||
|
||||
|
||||
int handle__auth(struct mosquitto *mosq)
|
||||
{
|
||||
int rc = 0;
|
||||
uint8_t reason_code;
|
||||
mosquitto_property *properties = NULL;
|
||||
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received AUTH", mosq->id);
|
||||
|
||||
if(mosq->protocol != mosq_p_mqtt5){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
if(packet__read_byte(&mosq->in_packet, &reason_code)) return 1;
|
||||
|
||||
rc = property__read_all(CMD_AUTH, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
mosquitto_property_free_all(&properties); /* FIXME - TEMPORARY UNTIL PROPERTIES PROCESSED */
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "property_mosq.h"
|
||||
#include "read_handle.h"
|
||||
|
||||
static void connack_callback(struct mosquitto *mosq, uint8_t reason_code, uint8_t connect_flags, const mosquitto_property *properties)
|
||||
{
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code);
|
||||
if(reason_code == MQTT_RC_SUCCESS){
|
||||
mosq->reconnects = 0;
|
||||
}
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_connect){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_connect(mosq, mosq->userdata, reason_code);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_connect_with_flags){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_connect_with_flags(mosq, mosq->userdata, reason_code, connect_flags);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_connect_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_connect_v5(mosq, mosq->userdata, reason_code, connect_flags, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
|
||||
|
||||
int handle__connack(struct mosquitto *mosq)
|
||||
{
|
||||
uint8_t connect_flags;
|
||||
uint8_t reason_code;
|
||||
int rc;
|
||||
mosquitto_property *properties = NULL;
|
||||
char *clientid = NULL;
|
||||
|
||||
assert(mosq);
|
||||
rc = packet__read_byte(&mosq->in_packet, &connect_flags);
|
||||
if(rc) return rc;
|
||||
rc = packet__read_byte(&mosq->in_packet, &reason_code);
|
||||
if(rc) return rc;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5){
|
||||
rc = property__read_all(CMD_CONNACK, &mosq->in_packet, &properties);
|
||||
|
||||
if(rc == MOSQ_ERR_PROTOCOL && reason_code == CONNACK_REFUSED_PROTOCOL_VERSION){
|
||||
/* This could occur because we are connecting to a v3.x broker and
|
||||
* it has replied with "unacceptable protocol version", but with a
|
||||
* v3 CONNACK. */
|
||||
|
||||
connack_callback(mosq, MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION, connect_flags, NULL);
|
||||
return rc;
|
||||
}else if(rc){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
mosquitto_property_read_string(properties, MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, &clientid, false);
|
||||
if(clientid){
|
||||
if(mosq->id){
|
||||
/* We've been sent a client identifier but already have one. This
|
||||
* shouldn't happen. */
|
||||
free(clientid);
|
||||
mosquitto_property_free_all(&properties);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}else{
|
||||
mosq->id = clientid;
|
||||
clientid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mosquitto_property_read_byte(properties, MQTT_PROP_MAXIMUM_QOS, &mosq->maximum_qos, false);
|
||||
mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM, &mosq->msgs_out.inflight_maximum, false);
|
||||
mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE, &mosq->keepalive, false);
|
||||
mosquitto_property_read_int32(properties, MQTT_PROP_MAXIMUM_PACKET_SIZE, &mosq->maximum_packet_size, false);
|
||||
|
||||
mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum;
|
||||
|
||||
connack_callback(mosq, reason_code, connect_flags, properties);
|
||||
mosquitto_property_free_all(&properties);
|
||||
|
||||
switch(reason_code){
|
||||
case 0:
|
||||
pthread_mutex_lock(&mosq->state_mutex);
|
||||
if(mosq->state != mosq_cs_disconnecting){
|
||||
mosq->state = mosq_cs_active;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->state_mutex);
|
||||
message__retry_check(mosq);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
return MOSQ_ERR_CONN_REFUSED;
|
||||
default:
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logging_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "property_mosq.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
int handle__disconnect(struct mosquitto *mosq)
|
||||
{
|
||||
int rc;
|
||||
uint8_t reason_code;
|
||||
mosquitto_property *properties = NULL;
|
||||
|
||||
if(!mosq){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
if(mosq->protocol != mosq_p_mqtt5){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
rc = packet__read_byte(&mosq->in_packet, &reason_code);
|
||||
if(rc) return rc;
|
||||
|
||||
if(mosq->in_packet.remaining_length > 2){
|
||||
rc = property__read_all(CMD_DISCONNECT, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
mosquitto_property_free_all(&properties);
|
||||
}
|
||||
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Received DISCONNECT (%d)", reason_code);
|
||||
|
||||
do_client_disconnect(mosq, reason_code, properties);
|
||||
|
||||
mosquitto_property_free_all(&properties);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# include "mosquitto_broker_internal.h"
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "read_handle.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
int handle__pingreq(struct mosquitto *mosq)
|
||||
{
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received PINGREQ from %s", mosq->id);
|
||||
#else
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGREQ", mosq->id);
|
||||
#endif
|
||||
return send__pingresp(mosq);
|
||||
}
|
||||
|
||||
int handle__pingresp(struct mosquitto *mosq)
|
||||
{
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
mosq->ping_t = 0; /* No longer waiting for a PINGRESP. */
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received PINGRESP from %s", mosq->id);
|
||||
#else
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGRESP", mosq->id);
|
||||
#endif
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# include "mosquitto_broker_internal.h"
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "read_handle.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
int handle__pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type)
|
||||
#else
|
||||
int handle__pubackcomp(struct mosquitto *mosq, const char *type)
|
||||
#endif
|
||||
{
|
||||
uint8_t reason_code = 0;
|
||||
uint16_t mid;
|
||||
int rc;
|
||||
mosquitto_property *properties = NULL;
|
||||
int qos;
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
util__increment_send_quota(mosq);
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
|
||||
rc = packet__read_uint16(&mosq->in_packet, &mid);
|
||||
if(rc) return rc;
|
||||
qos = type[3] == 'A'?1:2; /* pubAck or pubComp */
|
||||
if(mid == 0) return MOSQ_ERR_PROTOCOL;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
|
||||
rc = packet__read_byte(&mosq->in_packet, &reason_code);
|
||||
if(rc) return rc;
|
||||
|
||||
if(mosq->in_packet.remaining_length > 3){
|
||||
rc = property__read_all(CMD_PUBACK, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d, RC:%d)", type, mosq->id, mid, reason_code);
|
||||
|
||||
/* Immediately free, we don't do anything with Reason String or User Property at the moment */
|
||||
mosquitto_property_free_all(&properties);
|
||||
|
||||
rc = db__message_delete_outgoing(db, mosq, mid, mosq_ms_wait_for_pubcomp, qos);
|
||||
if(rc == MOSQ_ERR_NOT_FOUND){
|
||||
log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received %s from %s for an unknown packet identifier %d.", type, mosq->id, mid);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d, RC:%d)", mosq->id, type, mid, reason_code);
|
||||
|
||||
rc = message__delete(mosq, mid, mosq_md_out, qos);
|
||||
if(rc){
|
||||
return rc;
|
||||
}else{
|
||||
/* Only inform the client the message has been sent once. */
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_publish){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_publish(mosq, mosq->userdata, mid);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_publish_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
mosquitto_property_free_all(&properties);
|
||||
}
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
message__release_to_inflight(mosq, mosq_md_out);
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,169 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "property_mosq.h"
|
||||
#include "send_mosq.h"
|
||||
#include "time_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
|
||||
int handle__publish(struct mosquitto *mosq)
|
||||
{
|
||||
uint8_t header;
|
||||
struct mosquitto_message_all *message;
|
||||
int rc = 0;
|
||||
uint16_t mid;
|
||||
int slen;
|
||||
mosquitto_property *properties = NULL;
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
message = mosquitto__calloc(1, sizeof(struct mosquitto_message_all));
|
||||
if(!message) return MOSQ_ERR_NOMEM;
|
||||
|
||||
header = mosq->in_packet.command;
|
||||
|
||||
message->dup = (header & 0x08)>>3;
|
||||
message->msg.qos = (header & 0x06)>>1;
|
||||
message->msg.retain = (header & 0x01);
|
||||
|
||||
rc = packet__read_string(&mosq->in_packet, &message->msg.topic, &slen);
|
||||
if(rc){
|
||||
message__cleanup(&message);
|
||||
return rc;
|
||||
}
|
||||
if(!slen){
|
||||
message__cleanup(&message);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
if(message->msg.qos > 0){
|
||||
if(mosq->protocol == mosq_p_mqtt5){
|
||||
if(mosq->msgs_in.inflight_quota == 0){
|
||||
message__cleanup(&message);
|
||||
/* FIXME - should send a DISCONNECT here */
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
rc = packet__read_uint16(&mosq->in_packet, &mid);
|
||||
if(rc){
|
||||
message__cleanup(&message);
|
||||
return rc;
|
||||
}
|
||||
if(mid == 0){
|
||||
message__cleanup(&message);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
message->msg.mid = (int)mid;
|
||||
}
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5){
|
||||
rc = property__read_all(CMD_PUBLISH, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos;
|
||||
if(message->msg.payloadlen){
|
||||
message->msg.payload = mosquitto__calloc(message->msg.payloadlen+1, sizeof(uint8_t));
|
||||
if(!message->msg.payload){
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
rc = packet__read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen);
|
||||
if(rc){
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG,
|
||||
"Client %s received PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))",
|
||||
mosq->id, message->dup, message->msg.qos, message->msg.retain,
|
||||
message->msg.mid, message->msg.topic,
|
||||
(long)message->msg.payloadlen);
|
||||
|
||||
message->timestamp = mosquitto_time();
|
||||
switch(message->msg.qos){
|
||||
case 0:
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_message){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_message(mosq, mosq->userdata, &message->msg);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_message_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
case 1:
|
||||
util__decrement_receive_quota(mosq);
|
||||
rc = send__puback(mosq, message->msg.mid, 0);
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_message){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_message(mosq, mosq->userdata, &message->msg);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_message_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_message_v5(mosq, mosq->userdata, &message->msg, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties);
|
||||
return rc;
|
||||
case 2:
|
||||
message->properties = properties;
|
||||
util__decrement_receive_quota(mosq);
|
||||
rc = send__pubrec(mosq, message->msg.mid, 0);
|
||||
pthread_mutex_lock(&mosq->msgs_in.mutex);
|
||||
message->state = mosq_ms_wait_for_pubrel;
|
||||
message__queue(mosq, message, mosq_md_in);
|
||||
pthread_mutex_unlock(&mosq->msgs_in.mutex);
|
||||
return rc;
|
||||
default:
|
||||
message__cleanup(&message);
|
||||
mosquitto_property_free_all(&properties);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# include "mosquitto_broker_internal.h"
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "read_handle.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
int handle__pubrec(struct mosquitto_db *db, struct mosquitto *mosq)
|
||||
{
|
||||
uint8_t reason_code = 0;
|
||||
uint16_t mid;
|
||||
int rc;
|
||||
mosquitto_property *properties = NULL;
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
rc = packet__read_uint16(&mosq->in_packet, &mid);
|
||||
if(rc) return rc;
|
||||
if(mid == 0) return MOSQ_ERR_PROTOCOL;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
|
||||
rc = packet__read_byte(&mosq->in_packet, &reason_code);
|
||||
if(rc) return rc;
|
||||
|
||||
if(mosq->in_packet.remaining_length > 3){
|
||||
rc = property__read_all(CMD_PUBREC, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
/* Immediately free, we don't do anything with Reason String or User Property at the moment */
|
||||
mosquitto_property_free_all(&properties);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid);
|
||||
|
||||
if(reason_code < 0x80){
|
||||
rc = db__message_update_outgoing(mosq, mid, mosq_ms_wait_for_pubcomp, 2);
|
||||
}else{
|
||||
return db__message_delete_outgoing(db, mosq, mid, mosq_ms_wait_for_pubrec, 2);
|
||||
}
|
||||
#else
|
||||
UNUSED(db);
|
||||
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid);
|
||||
|
||||
if(reason_code < 0x80 || mosq->protocol != mosq_p_mqtt5){
|
||||
rc = message__out_update(mosq, mid, mosq_ms_wait_for_pubcomp, 2);
|
||||
}else{
|
||||
if(!message__delete(mosq, mid, mosq_md_out, 2)){
|
||||
/* Only inform the client the message has been sent once. */
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_publish_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_publish_v5(mosq, mosq->userdata, mid, reason_code, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
util__increment_send_quota(mosq);
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
message__release_to_inflight(mosq, mosq_md_out);
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
if(rc == MOSQ_ERR_NOT_FOUND){
|
||||
log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREC from %s for an unknown packet identifier %d.", mosq->id, mid);
|
||||
}else if(rc != MOSQ_ERR_SUCCESS){
|
||||
return rc;
|
||||
}
|
||||
rc = send__pubrel(mosq, mid);
|
||||
if(rc) return rc;
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# include "mosquitto_broker_internal.h"
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "read_handle.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
|
||||
int handle__pubrel(struct mosquitto_db *db, struct mosquitto *mosq)
|
||||
{
|
||||
uint8_t reason_code;
|
||||
uint16_t mid;
|
||||
#ifndef WITH_BROKER
|
||||
struct mosquitto_message_all *message = NULL;
|
||||
#endif
|
||||
int rc;
|
||||
mosquitto_property *properties = NULL;
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
if(mosq->protocol != mosq_p_mqtt31){
|
||||
if((mosq->in_packet.command&0x0F) != 0x02){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
}
|
||||
rc = packet__read_uint16(&mosq->in_packet, &mid);
|
||||
if(rc) return rc;
|
||||
if(mid == 0) return MOSQ_ERR_PROTOCOL;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5 && mosq->in_packet.remaining_length > 2){
|
||||
rc = packet__read_byte(&mosq->in_packet, &reason_code);
|
||||
if(rc) return rc;
|
||||
|
||||
if(mosq->in_packet.remaining_length > 3){
|
||||
rc = property__read_all(CMD_PUBREL, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid);
|
||||
|
||||
/* Immediately free, we don't do anything with Reason String or User Property at the moment */
|
||||
mosquitto_property_free_all(&properties);
|
||||
|
||||
rc = db__message_release_incoming(db, mosq, mid);
|
||||
if(rc == MOSQ_ERR_NOT_FOUND){
|
||||
/* Message not found. Still send a PUBCOMP anyway because this could be
|
||||
* due to a repeated PUBREL after a client has reconnected. */
|
||||
}else if(rc != MOSQ_ERR_SUCCESS){
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = send__pubcomp(mosq, mid);
|
||||
if(rc) return rc;
|
||||
#else
|
||||
UNUSED(db);
|
||||
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid);
|
||||
|
||||
rc = send__pubcomp(mosq, mid);
|
||||
if(rc){
|
||||
message__remove(mosq, mid, mosq_md_in, &message, 2);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = message__remove(mosq, mid, mosq_md_in, &message, 2);
|
||||
if(rc){
|
||||
return rc;
|
||||
}else{
|
||||
/* Only pass the message on if we have removed it from the queue - this
|
||||
* prevents multiple callbacks for the same message. */
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_message){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_message(mosq, mosq->userdata, &message->msg);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_message_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_message_v5(mosq, mosq->userdata, &message->msg, message->properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
mosquitto_property_free_all(&properties);
|
||||
message__cleanup(&message);
|
||||
}
|
||||
#endif
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# include "mosquitto_broker_internal.h"
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "property_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
|
||||
int handle__suback(struct mosquitto *mosq)
|
||||
{
|
||||
uint16_t mid;
|
||||
uint8_t qos;
|
||||
int *granted_qos;
|
||||
int qos_count;
|
||||
int i = 0;
|
||||
int rc;
|
||||
mosquitto_property *properties = NULL;
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id);
|
||||
#else
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK", mosq->id);
|
||||
#endif
|
||||
rc = packet__read_uint16(&mosq->in_packet, &mid);
|
||||
if(rc) return rc;
|
||||
if(mid == 0) return MOSQ_ERR_PROTOCOL;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5){
|
||||
rc = property__read_all(CMD_SUBACK, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos;
|
||||
granted_qos = mosquitto__malloc(qos_count*sizeof(int));
|
||||
if(!granted_qos) return MOSQ_ERR_NOMEM;
|
||||
while(mosq->in_packet.pos < mosq->in_packet.remaining_length){
|
||||
rc = packet__read_byte(&mosq->in_packet, &qos);
|
||||
if(rc){
|
||||
mosquitto__free(granted_qos);
|
||||
return rc;
|
||||
}
|
||||
granted_qos[i] = (int)qos;
|
||||
i++;
|
||||
}
|
||||
#ifdef WITH_BROKER
|
||||
/* Immediately free, we don't do anything with Reason String or User Property at the moment */
|
||||
mosquitto_property_free_all(&properties);
|
||||
#else
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_subscribe){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_subscribe(mosq, mosq->userdata, mid, qos_count, granted_qos);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_subscribe_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_subscribe_v5(mosq, mosq->userdata, mid, qos_count, granted_qos, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
mosquitto_property_free_all(&properties);
|
||||
#endif
|
||||
mosquitto__free(granted_qos);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
# include "mosquitto_broker_internal.h"
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "logging_mosq.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "property_mosq.h"
|
||||
#include "read_handle.h"
|
||||
#include "send_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
|
||||
int handle__unsuback(struct mosquitto *mosq)
|
||||
{
|
||||
uint16_t mid;
|
||||
int rc;
|
||||
mosquitto_property *properties = NULL;
|
||||
int state;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state != mosq_cs_active){
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBACK from %s", mosq->id);
|
||||
#else
|
||||
log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received UNSUBACK", mosq->id);
|
||||
#endif
|
||||
rc = packet__read_uint16(&mosq->in_packet, &mid);
|
||||
if(rc) return rc;
|
||||
if(mid == 0) return MOSQ_ERR_PROTOCOL;
|
||||
|
||||
if(mosq->protocol == mosq_p_mqtt5){
|
||||
rc = property__read_all(CMD_UNSUBACK, &mosq->in_packet, &properties);
|
||||
if(rc) return rc;
|
||||
}
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
/* Immediately free, we don't do anything with Reason String or User Property at the moment */
|
||||
mosquitto_property_free_all(&properties);
|
||||
#else
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_unsubscribe){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_unsubscribe(mosq, mosq->userdata, mid);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_unsubscribe_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_unsubscribe_v5(mosq, mosq->userdata, mid, properties);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
mosquitto_property_free_all(&properties);
|
||||
#endif
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,227 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
|
||||
struct userdata__callback {
|
||||
const char *topic;
|
||||
int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *);
|
||||
void *userdata;
|
||||
int qos;
|
||||
int rc;
|
||||
};
|
||||
|
||||
struct userdata__simple {
|
||||
struct mosquitto_message *messages;
|
||||
int max_msg_count;
|
||||
int message_count;
|
||||
bool want_retained;
|
||||
};
|
||||
|
||||
|
||||
static void on_connect(struct mosquitto *mosq, void *obj, int rc)
|
||||
{
|
||||
struct userdata__callback *userdata = obj;
|
||||
|
||||
UNUSED(rc);
|
||||
|
||||
mosquitto_subscribe(mosq, NULL, userdata->topic, userdata->qos);
|
||||
}
|
||||
|
||||
|
||||
static void on_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
|
||||
{
|
||||
int rc;
|
||||
struct userdata__callback *userdata = obj;
|
||||
|
||||
rc = userdata->callback(mosq, userdata->userdata, message);
|
||||
if(rc){
|
||||
mosquitto_disconnect(mosq);
|
||||
}
|
||||
}
|
||||
|
||||
static int on_message_simple(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
|
||||
{
|
||||
struct userdata__simple *userdata = obj;
|
||||
int rc;
|
||||
|
||||
if(userdata->max_msg_count == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't process stale retained messages if 'want_retained' was false */
|
||||
if(!userdata->want_retained && message->retain){
|
||||
return 0;
|
||||
}
|
||||
|
||||
userdata->max_msg_count--;
|
||||
|
||||
rc = mosquitto_message_copy(&userdata->messages[userdata->message_count], message);
|
||||
if(rc){
|
||||
return rc;
|
||||
}
|
||||
userdata->message_count++;
|
||||
if(userdata->max_msg_count == 0){
|
||||
mosquitto_disconnect(mosq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
libmosq_EXPORT int mosquitto_subscribe_simple(
|
||||
struct mosquitto_message **messages,
|
||||
int msg_count,
|
||||
bool want_retained,
|
||||
const char *topic,
|
||||
int qos,
|
||||
const char *host,
|
||||
int port,
|
||||
const char *client_id,
|
||||
int keepalive,
|
||||
bool clean_session,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const struct libmosquitto_will *will,
|
||||
const struct libmosquitto_tls *tls)
|
||||
{
|
||||
struct userdata__simple userdata;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
if(!topic || msg_count < 1 || !messages){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
*messages = NULL;
|
||||
|
||||
userdata.messages = calloc(sizeof(struct mosquitto_message), msg_count);
|
||||
if(!userdata.messages){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
userdata.message_count = 0;
|
||||
userdata.max_msg_count = msg_count;
|
||||
userdata.want_retained = want_retained;
|
||||
|
||||
rc = mosquitto_subscribe_callback(
|
||||
on_message_simple, &userdata,
|
||||
topic, qos,
|
||||
host, port,
|
||||
client_id, keepalive, clean_session,
|
||||
username, password,
|
||||
will, tls);
|
||||
|
||||
if(!rc && userdata.max_msg_count == 0){
|
||||
*messages = userdata.messages;
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
for(i=0; i<msg_count; i++){
|
||||
mosquitto_message_free_contents(&userdata.messages[i]);
|
||||
}
|
||||
free(userdata.messages);
|
||||
userdata.messages = NULL;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
libmosq_EXPORT int mosquitto_subscribe_callback(
|
||||
int (*callback)(struct mosquitto *, void *, const struct mosquitto_message *),
|
||||
void *userdata,
|
||||
const char *topic,
|
||||
int qos,
|
||||
const char *host,
|
||||
int port,
|
||||
const char *client_id,
|
||||
int keepalive,
|
||||
bool clean_session,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const struct libmosquitto_will *will,
|
||||
const struct libmosquitto_tls *tls)
|
||||
{
|
||||
struct mosquitto *mosq;
|
||||
struct userdata__callback cb_userdata;
|
||||
int rc;
|
||||
|
||||
if(!callback || !topic){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
cb_userdata.topic = topic;
|
||||
cb_userdata.qos = qos;
|
||||
cb_userdata.rc = 0;
|
||||
cb_userdata.userdata = userdata;
|
||||
cb_userdata.callback = callback;
|
||||
|
||||
mosq = mosquitto_new(client_id, clean_session, &cb_userdata);
|
||||
if(!mosq){
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
if(will){
|
||||
rc = mosquitto_will_set(mosq, will->topic, will->payloadlen, will->payload, will->qos, will->retain);
|
||||
if(rc){
|
||||
mosquitto_destroy(mosq);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if(username){
|
||||
rc = mosquitto_username_pw_set(mosq, username, password);
|
||||
if(rc){
|
||||
mosquitto_destroy(mosq);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if(tls){
|
||||
rc = mosquitto_tls_set(mosq, tls->cafile, tls->capath, tls->certfile, tls->keyfile, tls->pw_callback);
|
||||
if(rc){
|
||||
mosquitto_destroy(mosq);
|
||||
return rc;
|
||||
}
|
||||
rc = mosquitto_tls_opts_set(mosq, tls->cert_reqs, tls->tls_version, tls->ciphers);
|
||||
if(rc){
|
||||
mosquitto_destroy(mosq);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
mosquitto_connect_callback_set(mosq, on_connect);
|
||||
mosquitto_message_callback_set(mosq, on_message_callback);
|
||||
|
||||
rc = mosquitto_connect(mosq, host, port, keepalive);
|
||||
if(rc){
|
||||
mosquitto_destroy(mosq);
|
||||
return rc;
|
||||
}
|
||||
rc = mosquitto_loop_forever(mosq, -1, 1);
|
||||
mosquitto_destroy(mosq);
|
||||
if(cb_userdata.rc){
|
||||
rc = cb_userdata.rc;
|
||||
}
|
||||
//if(!rc && cb_userdata.max_msg_count == 0){
|
||||
//return MOSQ_ERR_SUCCESS;
|
||||
//}else{
|
||||
//return rc;
|
||||
//}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mosquitto_internal.h"
|
||||
#include "mosquitto.h"
|
||||
#include "memory_mosq.h"
|
||||
|
||||
int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
char *s;
|
||||
int len;
|
||||
|
||||
assert(mosq);
|
||||
assert(fmt);
|
||||
|
||||
pthread_mutex_lock(&mosq->log_callback_mutex);
|
||||
if(mosq->on_log){
|
||||
len = strlen(fmt) + 500;
|
||||
s = mosquitto__malloc(len*sizeof(char));
|
||||
if(!s){
|
||||
pthread_mutex_unlock(&mosq->log_callback_mutex);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
|
||||
va_start(va, fmt);
|
||||
vsnprintf(s, len, fmt, va);
|
||||
va_end(va);
|
||||
s[len-1] = '\0'; /* Ensure string is null terminated. */
|
||||
|
||||
mosq->on_log(mosq, mosq->userdata, priority, s);
|
||||
|
||||
mosquitto__free(s);
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->log_callback_mutex);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
#ifndef LOGGING_MOSQ_H
|
||||
#define LOGGING_MOSQ_H
|
||||
|
||||
#include "mosquitto.h"
|
||||
|
||||
int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...);
|
||||
|
||||
#endif
|
@ -1,381 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/select.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "socks_mosq.h"
|
||||
#include "tls_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
#if !defined(WIN32) && !defined(__SYMBIAN32__)
|
||||
#define HAVE_PSELECT
|
||||
#endif
|
||||
|
||||
int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets)
|
||||
{
|
||||
#ifdef HAVE_PSELECT
|
||||
struct timespec local_timeout;
|
||||
#else
|
||||
struct timeval local_timeout;
|
||||
#endif
|
||||
fd_set readfds, writefds;
|
||||
int fdcount;
|
||||
int rc;
|
||||
char pairbuf;
|
||||
int maxfd = 0;
|
||||
time_t now;
|
||||
#ifdef WITH_SRV
|
||||
int state;
|
||||
#endif
|
||||
|
||||
if(!mosq || max_packets < 1) return MOSQ_ERR_INVAL;
|
||||
#ifndef WIN32
|
||||
if(mosq->sock >= FD_SETSIZE || mosq->sockpairR >= FD_SETSIZE){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
if(mosq->sock != INVALID_SOCKET){
|
||||
maxfd = mosq->sock;
|
||||
FD_SET(mosq->sock, &readfds);
|
||||
pthread_mutex_lock(&mosq->current_out_packet_mutex);
|
||||
pthread_mutex_lock(&mosq->out_packet_mutex);
|
||||
if(mosq->out_packet || mosq->current_out_packet){
|
||||
FD_SET(mosq->sock, &writefds);
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
if(mosq->want_write){
|
||||
FD_SET(mosq->sock, &writefds);
|
||||
}else if(mosq->want_connect){
|
||||
/* Remove possible FD_SET from above, we don't want to check
|
||||
* for writing if we are still connecting, unless want_write is
|
||||
* definitely set. The presence of outgoing packets does not
|
||||
* matter yet. */
|
||||
FD_CLR(mosq->sock, &writefds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&mosq->out_packet_mutex);
|
||||
pthread_mutex_unlock(&mosq->current_out_packet_mutex);
|
||||
}else{
|
||||
#ifdef WITH_SRV
|
||||
if(mosq->achan){
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state == mosq_cs_connect_srv){
|
||||
rc = ares_fds(mosq->achan, &readfds, &writefds);
|
||||
if(rc > maxfd){
|
||||
maxfd = rc;
|
||||
}
|
||||
}else{
|
||||
return MOSQ_ERR_NO_CONN;
|
||||
}
|
||||
}
|
||||
#else
|
||||
return MOSQ_ERR_NO_CONN;
|
||||
#endif
|
||||
}
|
||||
if(mosq->sockpairR != INVALID_SOCKET){
|
||||
/* sockpairR is used to break out of select() before the timeout, on a
|
||||
* call to publish() etc. */
|
||||
FD_SET(mosq->sockpairR, &readfds);
|
||||
if(mosq->sockpairR > maxfd){
|
||||
maxfd = mosq->sockpairR;
|
||||
}
|
||||
}
|
||||
|
||||
if(timeout < 0){
|
||||
timeout = 1000;
|
||||
}
|
||||
|
||||
now = mosquitto_time();
|
||||
if(mosq->next_msg_out && now + timeout/1000 > mosq->next_msg_out){
|
||||
timeout = (mosq->next_msg_out - now)*1000;
|
||||
}
|
||||
|
||||
if(timeout < 0){
|
||||
/* There has been a delay somewhere which means we should have already
|
||||
* sent a message. */
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
local_timeout.tv_sec = timeout/1000;
|
||||
#ifdef HAVE_PSELECT
|
||||
local_timeout.tv_nsec = (timeout-local_timeout.tv_sec*1000)*1e6;
|
||||
#else
|
||||
local_timeout.tv_usec = (timeout-local_timeout.tv_sec*1000)*1000;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PSELECT
|
||||
fdcount = pselect(maxfd+1, &readfds, &writefds, NULL, &local_timeout, NULL);
|
||||
#else
|
||||
fdcount = select(maxfd+1, &readfds, &writefds, NULL, &local_timeout);
|
||||
#endif
|
||||
if(fdcount == -1){
|
||||
#ifdef WIN32
|
||||
errno = WSAGetLastError();
|
||||
#endif
|
||||
if(errno == EINTR){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_ERRNO;
|
||||
}
|
||||
}else{
|
||||
if(mosq->sock != INVALID_SOCKET){
|
||||
if(FD_ISSET(mosq->sock, &readfds)){
|
||||
rc = mosquitto_loop_read(mosq, max_packets);
|
||||
if(rc || mosq->sock == INVALID_SOCKET){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){
|
||||
#ifndef WIN32
|
||||
if(read(mosq->sockpairR, &pairbuf, 1) == 0){
|
||||
}
|
||||
#else
|
||||
recv(mosq->sockpairR, &pairbuf, 1, 0);
|
||||
#endif
|
||||
/* Fake write possible, to stimulate output write even though
|
||||
* we didn't ask for it, because at that point the publish or
|
||||
* other command wasn't present. */
|
||||
if(mosq->sock != INVALID_SOCKET)
|
||||
FD_SET(mosq->sock, &writefds);
|
||||
}
|
||||
if(mosq->sock != INVALID_SOCKET && FD_ISSET(mosq->sock, &writefds)){
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->want_connect){
|
||||
rc = net__socket_connect_tls(mosq);
|
||||
if(rc) return rc;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
rc = mosquitto_loop_write(mosq, max_packets);
|
||||
if(rc || mosq->sock == INVALID_SOCKET){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef WITH_SRV
|
||||
if(mosq->achan){
|
||||
ares_process(mosq->achan, &readfds, &writefds);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return mosquitto_loop_misc(mosq);
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets)
|
||||
{
|
||||
int run = 1;
|
||||
int rc;
|
||||
unsigned long reconnect_delay;
|
||||
#ifndef WIN32
|
||||
struct timespec req, rem;
|
||||
#endif
|
||||
int state;
|
||||
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
|
||||
mosq->reconnects = 0;
|
||||
|
||||
while(run){
|
||||
do{
|
||||
rc = mosquitto_loop(mosq, timeout, max_packets);
|
||||
}while(run && rc == MOSQ_ERR_SUCCESS);
|
||||
/* Quit after fatal errors. */
|
||||
switch(rc){
|
||||
case MOSQ_ERR_NOMEM:
|
||||
case MOSQ_ERR_PROTOCOL:
|
||||
case MOSQ_ERR_INVAL:
|
||||
case MOSQ_ERR_NOT_FOUND:
|
||||
case MOSQ_ERR_TLS:
|
||||
case MOSQ_ERR_PAYLOAD_SIZE:
|
||||
case MOSQ_ERR_NOT_SUPPORTED:
|
||||
case MOSQ_ERR_AUTH:
|
||||
case MOSQ_ERR_ACL_DENIED:
|
||||
case MOSQ_ERR_UNKNOWN:
|
||||
case MOSQ_ERR_EAI:
|
||||
case MOSQ_ERR_PROXY:
|
||||
return rc;
|
||||
case MOSQ_ERR_ERRNO:
|
||||
break;
|
||||
}
|
||||
if(errno == EPROTO){
|
||||
return rc;
|
||||
}
|
||||
do{
|
||||
rc = MOSQ_ERR_SUCCESS;
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state == mosq_cs_disconnecting || state == mosq_cs_disconnected){
|
||||
run = 0;
|
||||
}else{
|
||||
if(mosq->reconnect_delay_max > mosq->reconnect_delay){
|
||||
if(mosq->reconnect_exponential_backoff){
|
||||
reconnect_delay = mosq->reconnect_delay*(mosq->reconnects+1)*(mosq->reconnects+1);
|
||||
}else{
|
||||
reconnect_delay = mosq->reconnect_delay*(mosq->reconnects+1);
|
||||
}
|
||||
}else{
|
||||
reconnect_delay = mosq->reconnect_delay;
|
||||
}
|
||||
|
||||
if(reconnect_delay > mosq->reconnect_delay_max){
|
||||
reconnect_delay = mosq->reconnect_delay_max;
|
||||
}else{
|
||||
mosq->reconnects++;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(reconnect_delay*1000);
|
||||
#else
|
||||
req.tv_sec = reconnect_delay;
|
||||
req.tv_nsec = 0;
|
||||
while(nanosleep(&req, &rem) == -1 && errno == EINTR){
|
||||
req = rem;
|
||||
}
|
||||
#endif
|
||||
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state == mosq_cs_disconnecting || state == mosq_cs_disconnected){
|
||||
run = 0;
|
||||
}else{
|
||||
rc = mosquitto_reconnect(mosq);
|
||||
}
|
||||
}
|
||||
}while(run && rc != MOSQ_ERR_SUCCESS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_loop_misc(struct mosquitto *mosq)
|
||||
{
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;
|
||||
|
||||
return mosquitto__check_keepalive(mosq);
|
||||
}
|
||||
|
||||
|
||||
static int mosquitto__loop_rc_handle(struct mosquitto *mosq, int rc)
|
||||
{
|
||||
int state;
|
||||
|
||||
if(rc){
|
||||
net__socket_close(mosq);
|
||||
state = mosquitto__get_state(mosq);
|
||||
if(state == mosq_cs_disconnecting || state == mosq_cs_disconnected){
|
||||
rc = MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
pthread_mutex_lock(&mosq->callback_mutex);
|
||||
if(mosq->on_disconnect){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_disconnect(mosq, mosq->userdata, rc);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
if(mosq->on_disconnect_v5){
|
||||
mosq->in_callback = true;
|
||||
mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL);
|
||||
mosq->in_callback = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->callback_mutex);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_loop_read(struct mosquitto *mosq, int max_packets)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
if(max_packets < 1) return MOSQ_ERR_INVAL;
|
||||
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->want_connect){
|
||||
return net__socket_connect_tls(mosq);
|
||||
}
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
max_packets = mosq->msgs_out.queue_len;
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_in.mutex);
|
||||
max_packets += mosq->msgs_in.queue_len;
|
||||
pthread_mutex_unlock(&mosq->msgs_in.mutex);
|
||||
|
||||
if(max_packets < 1) max_packets = 1;
|
||||
/* Queue len here tells us how many messages are awaiting processing and
|
||||
* have QoS > 0. We should try to deal with that many in this loop in order
|
||||
* to keep up. */
|
||||
for(i=0; i<max_packets || SSL_DATA_PENDING(mosq); i++){
|
||||
#ifdef WITH_SOCKS
|
||||
if(mosq->socks5_host){
|
||||
rc = socks5__read(mosq);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
rc = packet__read(mosq);
|
||||
}
|
||||
if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
|
||||
return mosquitto__loop_rc_handle(mosq, rc);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_loop_write(struct mosquitto *mosq, int max_packets)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
if(max_packets < 1) return MOSQ_ERR_INVAL;
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
max_packets = mosq->msgs_out.queue_len;
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_in.mutex);
|
||||
max_packets += mosq->msgs_in.queue_len;
|
||||
pthread_mutex_unlock(&mosq->msgs_in.mutex);
|
||||
|
||||
if(max_packets < 1) max_packets = 1;
|
||||
/* Queue len here tells us how many messages are awaiting processing and
|
||||
* have QoS > 0. We should try to deal with that many in this loop in order
|
||||
* to keep up. */
|
||||
for(i=0; i<max_packets; i++){
|
||||
rc = packet__write(mosq);
|
||||
if(rc || errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){
|
||||
return mosquitto__loop_rc_handle(mosq, rc);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -1,160 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "memory_mosq.h"
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
# if defined(__APPLE__)
|
||||
# include <malloc/malloc.h>
|
||||
# define malloc_usable_size malloc_size
|
||||
# elif defined(__FreeBSD__)
|
||||
# include <malloc_np.h>
|
||||
# else
|
||||
# include <malloc.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
static unsigned long memcount = 0;
|
||||
static unsigned long max_memcount = 0;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
static size_t mem_limit = 0;
|
||||
void memory__set_limit(size_t lim)
|
||||
{
|
||||
mem_limit = lim;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *mosquitto__calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem_limit && memcount + size > mem_limit){
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
void *mem = calloc(nmemb, size);
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem){
|
||||
memcount += malloc_usable_size(mem);
|
||||
if(memcount > max_memcount){
|
||||
max_memcount = memcount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void mosquitto__free(void *mem)
|
||||
{
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(!mem){
|
||||
return;
|
||||
}
|
||||
memcount -= malloc_usable_size(mem);
|
||||
#endif
|
||||
free(mem);
|
||||
}
|
||||
|
||||
void *mosquitto__malloc(size_t size)
|
||||
{
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem_limit && memcount + size > mem_limit){
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
void *mem = malloc(size);
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem){
|
||||
memcount += malloc_usable_size(mem);
|
||||
if(memcount > max_memcount){
|
||||
max_memcount = memcount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
unsigned long mosquitto__memory_used(void)
|
||||
{
|
||||
return memcount;
|
||||
}
|
||||
|
||||
unsigned long mosquitto__max_memory_used(void)
|
||||
{
|
||||
return max_memcount;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *mosquitto__realloc(void *ptr, size_t size)
|
||||
{
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem_limit && memcount + size > mem_limit){
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
void *mem;
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(ptr){
|
||||
memcount -= malloc_usable_size(ptr);
|
||||
}
|
||||
#endif
|
||||
mem = realloc(ptr, size);
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem){
|
||||
memcount += malloc_usable_size(mem);
|
||||
if(memcount > max_memcount){
|
||||
max_memcount = memcount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
char *mosquitto__strdup(const char *s)
|
||||
{
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(mem_limit && memcount + strlen(s) > mem_limit){
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
char *str = strdup(s);
|
||||
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
if(str){
|
||||
memcount += malloc_usable_size(str);
|
||||
if(memcount > max_memcount){
|
||||
max_memcount = memcount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return str;
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#ifndef MEMORY_MOSQ_H
|
||||
#define MEMORY_MOSQ_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(WITH_MEMORY_TRACKING) && defined(WITH_BROKER) && defined(__GLIBC__)
|
||||
#define REAL_WITH_MEMORY_TRACKING
|
||||
#endif
|
||||
|
||||
void *mosquitto__calloc(size_t nmemb, size_t size);
|
||||
void mosquitto__free(void *mem);
|
||||
void *mosquitto__malloc(size_t size);
|
||||
#ifdef REAL_WITH_MEMORY_TRACKING
|
||||
unsigned long mosquitto__memory_used(void);
|
||||
unsigned long mosquitto__max_memory_used(void);
|
||||
#endif
|
||||
void *mosquitto__realloc(void *ptr, size_t size);
|
||||
char *mosquitto__strdup(const char *s);
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
void memory__set_limit(size_t lim);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,345 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utlist.h>
|
||||
|
||||
#include "mosquitto_internal.h"
|
||||
#include "mosquitto.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "send_mosq.h"
|
||||
#include "time_mosq.h"
|
||||
#include "util_mosq.h"
|
||||
|
||||
void message__cleanup(struct mosquitto_message_all **message)
|
||||
{
|
||||
struct mosquitto_message_all *msg;
|
||||
|
||||
if(!message || !*message) return;
|
||||
|
||||
msg = *message;
|
||||
|
||||
mosquitto__free(msg->msg.topic);
|
||||
mosquitto__free(msg->msg.payload);
|
||||
mosquitto_property_free_all(&msg->properties);
|
||||
mosquitto__free(msg);
|
||||
}
|
||||
|
||||
void message__cleanup_all(struct mosquitto *mosq)
|
||||
{
|
||||
struct mosquitto_message_all *tail, *tmp;
|
||||
|
||||
assert(mosq);
|
||||
|
||||
DL_FOREACH_SAFE(mosq->msgs_in.inflight, tail, tmp){
|
||||
DL_DELETE(mosq->msgs_in.inflight, tail);
|
||||
message__cleanup(&tail);
|
||||
}
|
||||
DL_FOREACH_SAFE(mosq->msgs_out.inflight, tail, tmp){
|
||||
DL_DELETE(mosq->msgs_out.inflight, tail);
|
||||
message__cleanup(&tail);
|
||||
}
|
||||
}
|
||||
|
||||
int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src)
|
||||
{
|
||||
if(!dst || !src) return MOSQ_ERR_INVAL;
|
||||
|
||||
dst->mid = src->mid;
|
||||
dst->topic = mosquitto__strdup(src->topic);
|
||||
if(!dst->topic) return MOSQ_ERR_NOMEM;
|
||||
dst->qos = src->qos;
|
||||
dst->retain = src->retain;
|
||||
if(src->payloadlen){
|
||||
dst->payload = mosquitto__calloc(src->payloadlen+1, sizeof(uint8_t));
|
||||
if(!dst->payload){
|
||||
mosquitto__free(dst->topic);
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
memcpy(dst->payload, src->payload, src->payloadlen);
|
||||
dst->payloadlen = src->payloadlen;
|
||||
}else{
|
||||
dst->payloadlen = 0;
|
||||
dst->payload = NULL;
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos)
|
||||
{
|
||||
struct mosquitto_message_all *message;
|
||||
int rc;
|
||||
assert(mosq);
|
||||
|
||||
rc = message__remove(mosq, mid, dir, &message, qos);
|
||||
if(rc == MOSQ_ERR_SUCCESS){
|
||||
message__cleanup(&message);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mosquitto_message_free(struct mosquitto_message **message)
|
||||
{
|
||||
struct mosquitto_message *msg;
|
||||
|
||||
if(!message || !*message) return;
|
||||
|
||||
msg = *message;
|
||||
|
||||
mosquitto__free(msg->topic);
|
||||
mosquitto__free(msg->payload);
|
||||
mosquitto__free(msg);
|
||||
}
|
||||
|
||||
void mosquitto_message_free_contents(struct mosquitto_message *message)
|
||||
{
|
||||
if(!message) return;
|
||||
|
||||
mosquitto__free(message->topic);
|
||||
mosquitto__free(message->payload);
|
||||
}
|
||||
|
||||
int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir)
|
||||
{
|
||||
/* mosq->*_message_mutex should be locked before entering this function */
|
||||
assert(mosq);
|
||||
assert(message);
|
||||
assert(message->msg.qos != 0);
|
||||
|
||||
if(dir == mosq_md_out){
|
||||
DL_APPEND(mosq->msgs_out.inflight, message);
|
||||
mosq->msgs_out.queue_len++;
|
||||
}else{
|
||||
DL_APPEND(mosq->msgs_in.inflight, message);
|
||||
mosq->msgs_in.queue_len++;
|
||||
}
|
||||
|
||||
return message__release_to_inflight(mosq, dir);
|
||||
}
|
||||
|
||||
void message__reconnect_reset(struct mosquitto *mosq)
|
||||
{
|
||||
struct mosquitto_message_all *message, *tmp;
|
||||
assert(mosq);
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_in.mutex);
|
||||
mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum;
|
||||
mosq->msgs_in.queue_len = 0;
|
||||
DL_FOREACH_SAFE(mosq->msgs_in.inflight, message, tmp){
|
||||
mosq->msgs_in.queue_len++;
|
||||
message->timestamp = 0;
|
||||
if(message->msg.qos != 2){
|
||||
DL_DELETE(mosq->msgs_in.inflight, message);
|
||||
message__cleanup(&message);
|
||||
}else{
|
||||
/* Message state can be preserved here because it should match
|
||||
* whatever the client has got. */
|
||||
util__decrement_receive_quota(mosq);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->msgs_in.mutex);
|
||||
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum;
|
||||
mosq->msgs_out.queue_len = 0;
|
||||
DL_FOREACH_SAFE(mosq->msgs_out.inflight, message, tmp){
|
||||
mosq->msgs_out.queue_len++;
|
||||
|
||||
message->timestamp = 0;
|
||||
if(mosq->msgs_out.inflight_quota != 0){
|
||||
util__decrement_send_quota(mosq);
|
||||
if(message->msg.qos == 1){
|
||||
message->state = mosq_ms_publish_qos1;
|
||||
}else if(message->msg.qos == 2){
|
||||
if(message->state == mosq_ms_wait_for_pubrec){
|
||||
message->state = mosq_ms_publish_qos2;
|
||||
}else if(message->state == mosq_ms_wait_for_pubcomp){
|
||||
message->state = mosq_ms_resend_pubrel;
|
||||
}
|
||||
/* Should be able to preserve state. */
|
||||
}
|
||||
}else{
|
||||
message->state = mosq_ms_invalid;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
}
|
||||
|
||||
|
||||
int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir)
|
||||
{
|
||||
/* mosq->*_message_mutex should be locked before entering this function */
|
||||
struct mosquitto_message_all *cur, *tmp;
|
||||
int rc = MOSQ_ERR_SUCCESS;
|
||||
|
||||
if(dir == mosq_md_out){
|
||||
DL_FOREACH_SAFE(mosq->msgs_out.inflight, cur, tmp){
|
||||
if(mosq->msgs_out.inflight_quota > 0){
|
||||
if(cur->msg.qos > 0 && cur->state == mosq_ms_invalid){
|
||||
if(cur->msg.qos == 1){
|
||||
cur->state = mosq_ms_wait_for_puback;
|
||||
}else if(cur->msg.qos == 2){
|
||||
cur->state = mosq_ms_wait_for_pubrec;
|
||||
}
|
||||
rc = send__publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup, cur->properties, NULL, 0);
|
||||
if(rc){
|
||||
return rc;
|
||||
}
|
||||
util__decrement_send_quota(mosq);
|
||||
}
|
||||
}else{
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos)
|
||||
{
|
||||
struct mosquitto_message_all *cur, *tmp;
|
||||
bool found = false;
|
||||
assert(mosq);
|
||||
assert(message);
|
||||
|
||||
if(dir == mosq_md_out){
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
|
||||
DL_FOREACH_SAFE(mosq->msgs_out.inflight, cur, tmp){
|
||||
if(found == false && cur->msg.mid == mid){
|
||||
if(cur->msg.qos != qos){
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
DL_DELETE(mosq->msgs_out.inflight, cur);
|
||||
|
||||
*message = cur;
|
||||
mosq->msgs_out.queue_len--;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
if(found){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
}else{
|
||||
pthread_mutex_lock(&mosq->msgs_in.mutex);
|
||||
DL_FOREACH_SAFE(mosq->msgs_in.inflight, cur, tmp){
|
||||
if(cur->msg.mid == mid){
|
||||
if(cur->msg.qos != qos){
|
||||
pthread_mutex_unlock(&mosq->msgs_in.mutex);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
DL_DELETE(mosq->msgs_in.inflight, cur);
|
||||
*message = cur;
|
||||
mosq->msgs_in.queue_len--;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mosq->msgs_in.mutex);
|
||||
if(found){
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}else{
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void message__retry_check(struct mosquitto *mosq)
|
||||
{
|
||||
struct mosquitto_message_all *msg;
|
||||
time_t now = mosquitto_time();
|
||||
assert(mosq);
|
||||
|
||||
#ifdef WITH_THREADING
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
#endif
|
||||
|
||||
DL_FOREACH(mosq->msgs_out.inflight, msg){
|
||||
switch(msg->state){
|
||||
case mosq_ms_publish_qos1:
|
||||
case mosq_ms_publish_qos2:
|
||||
msg->timestamp = now;
|
||||
msg->dup = true;
|
||||
send__publish(mosq, msg->msg.mid, msg->msg.topic, msg->msg.payloadlen, msg->msg.payload, msg->msg.qos, msg->msg.retain, msg->dup, msg->properties, NULL, 0);
|
||||
break;
|
||||
case mosq_ms_wait_for_pubrel:
|
||||
msg->timestamp = now;
|
||||
msg->dup = true;
|
||||
send__pubrec(mosq, msg->msg.mid, 0);
|
||||
break;
|
||||
case mosq_ms_resend_pubrel:
|
||||
case mosq_ms_wait_for_pubcomp:
|
||||
msg->timestamp = now;
|
||||
msg->dup = true;
|
||||
send__pubrel(mosq, msg->msg.mid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef WITH_THREADING
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
UNUSED(message_retry);
|
||||
}
|
||||
|
||||
int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos)
|
||||
{
|
||||
struct mosquitto_message_all *message, *tmp;
|
||||
assert(mosq);
|
||||
|
||||
pthread_mutex_lock(&mosq->msgs_out.mutex);
|
||||
DL_FOREACH_SAFE(mosq->msgs_out.inflight, message, tmp){
|
||||
if(message->msg.mid == mid){
|
||||
if(message->msg.qos != qos){
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
return MOSQ_ERR_PROTOCOL;
|
||||
}
|
||||
message->state = state;
|
||||
message->timestamp = mosquitto_time();
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mosq->msgs_out.mutex);
|
||||
return MOSQ_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages)
|
||||
{
|
||||
return mosquitto_int_option(mosq, MOSQ_OPT_SEND_MAXIMUM, max_inflight_messages);
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
#ifndef MESSAGES_MOSQ_H
|
||||
#define MESSAGES_MOSQ_H
|
||||
|
||||
#include "mosquitto_internal.h"
|
||||
#include "mosquitto.h"
|
||||
|
||||
void message__cleanup_all(struct mosquitto *mosq);
|
||||
void message__cleanup(struct mosquitto_message_all **message);
|
||||
int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos);
|
||||
int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir);
|
||||
void message__reconnect_reset(struct mosquitto *mosq);
|
||||
int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir);
|
||||
int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos);
|
||||
void message__retry_check(struct mosquitto *mosq);
|
||||
int message__out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state, int qos);
|
||||
|
||||
#endif
|
@ -1,613 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/time.h>
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "mosquitto_internal.h"
|
||||
#include "memory_mosq.h"
|
||||
#include "messages_mosq.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "net_mosq.h"
|
||||
#include "packet_mosq.h"
|
||||
#include "will_mosq.h"
|
||||
|
||||
|
||||
void mosquitto__destroy(struct mosquitto *mosq);
|
||||
|
||||
int mosquitto_lib_version(int *major, int *minor, int *revision)
|
||||
{
|
||||
if(major) *major = LIBMOSQUITTO_MAJOR;
|
||||
if(minor) *minor = LIBMOSQUITTO_MINOR;
|
||||
if(revision) *revision = LIBMOSQUITTO_REVISION;
|
||||
return LIBMOSQUITTO_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
int mosquitto_lib_init(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
srand(GetTickCount64());
|
||||
#elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK)
|
||||
struct timespec tp;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
srand(tp.tv_nsec);
|
||||
#elif defined(__APPLE__)
|
||||
uint64_t ticks;
|
||||
|
||||
ticks = mach_absolute_time();
|
||||
srand((unsigned int)ticks);
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
srand(tv.tv_sec*1000 + tv.tv_usec/1000);
|
||||
#endif
|
||||
|
||||
return net__init();
|
||||
}
|
||||
|
||||
int mosquitto_lib_cleanup(void)
|
||||
{
|
||||
net__cleanup();
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata)
|
||||
{
|
||||
struct mosquitto *mosq = NULL;
|
||||
int rc;
|
||||
|
||||
if(clean_start == false && id == NULL){
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
mosq = (struct mosquitto *)mosquitto__calloc(1, sizeof(struct mosquitto));
|
||||
if(mosq){
|
||||
mosq->sock = INVALID_SOCKET;
|
||||
mosq->sockpairR = INVALID_SOCKET;
|
||||
mosq->sockpairW = INVALID_SOCKET;
|
||||
#ifdef WITH_THREADING
|
||||
mosq->thread_id = pthread_self();
|
||||
#endif
|
||||
rc = mosquitto_reinitialise(mosq, id, clean_start, userdata);
|
||||
if(rc){
|
||||
mosquitto_destroy(mosq);
|
||||
if(rc == MOSQ_ERR_INVAL){
|
||||
errno = EINVAL;
|
||||
}else if(rc == MOSQ_ERR_NOMEM){
|
||||
errno = ENOMEM;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}else{
|
||||
errno = ENOMEM;
|
||||
}
|
||||
return mosq;
|
||||
}
|
||||
|
||||
int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_start, void *userdata)
|
||||
{
|
||||
if(!mosq) return MOSQ_ERR_INVAL;
|
||||
|
||||
if(clean_start == false && id == NULL){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
mosquitto__destroy(mosq);
|
||||
memset(mosq, 0, sizeof(struct mosquitto));
|
||||
|
||||
if(userdata){
|
||||
mosq->userdata = userdata;
|
||||
}else{
|
||||
mosq->userdata = mosq;
|
||||
}
|
||||
mosq->protocol = mosq_p_mqtt311;
|
||||
mosq->sock = INVALID_SOCKET;
|
||||
mosq->sockpairR = INVALID_SOCKET;
|
||||
mosq->sockpairW = INVALID_SOCKET;
|
||||
mosq->keepalive = 60;
|
||||
mosq->clean_start = clean_start;
|
||||
if(id){
|
||||
if(STREMPTY(id)){
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
if(mosquitto_validate_utf8(id, strlen(id))){
|
||||
return MOSQ_ERR_MALFORMED_UTF8;
|
||||
}
|
||||
mosq->id = mosquitto__strdup(id);
|
||||
}
|
||||
mosq->in_packet.payload = NULL;
|
||||
packet__cleanup(&mosq->in_packet);
|
||||
mosq->out_packet = NULL;
|
||||
mosq->current_out_packet = NULL;
|
||||
mosq->last_msg_in = mosquitto_time();
|
||||
mosq->next_msg_out = mosquitto_time() + mosq->keepalive;
|
||||
mosq->ping_t = 0;
|
||||
mosq->last_mid = 0;
|
||||
mosq->state = mosq_cs_new;
|
||||
mosq->maximum_qos = 2;
|
||||
mosq->msgs_in.inflight_maximum = 20;
|
||||
mosq->msgs_out.inflight_maximum = 20;
|
||||
mosq->msgs_in.inflight_quota = 20;
|
||||
mosq->msgs_out.inflight_quota = 20;
|
||||
mosq->will = NULL;
|
||||
mosq->on_connect = NULL;
|
||||
mosq->on_publish = NULL;
|
||||
mosq->on_message = NULL;
|
||||
mosq->on_subscribe = NULL;
|
||||
mosq->on_unsubscribe = NULL;
|
||||
mosq->host = NULL;
|
||||
mosq->port = 1883;
|
||||
mosq->in_callback = false;
|
||||
mosq->reconnect_delay = 1;
|
||||
mosq->reconnect_delay_max = 1;
|
||||
mosq->reconnect_exponential_backoff = false;
|
||||
mosq->threaded = mosq_ts_none;
|
||||
#ifdef WITH_TLS
|
||||
mosq->ssl = NULL;
|
||||
mosq->ssl_ctx = NULL;
|
||||
mosq->tls_cert_reqs = SSL_VERIFY_PEER;
|
||||
mosq->tls_insecure = false;
|
||||
mosq->want_write = false;
|
||||
mosq->tls_ocsp_required = false;
|
||||
#endif
|
||||
#ifdef WITH_THREADING
|
||||
pthread_mutex_init(&mosq->callback_mutex, NULL);
|
||||
pthread_mutex_init(&mosq->log_callback_mutex, NULL);
|
||||
pthread_mutex_init(&mosq->state_mutex, NULL);
|
||||
pthread_mutex_init(&mosq->out_packet_mutex, NULL);
|
||||
pthread_mutex_init(&mosq->current_out_packet_mutex, NULL);
|
||||
pthread_mutex_init(&mosq->msgtime_mutex, NULL);
|
||||
pthread_mutex_init(&mosq->msgs_in.mutex, NULL);
|
||||
pthread_mutex_init(&mosq->msgs_out.mutex, NULL);
|
||||
pthread_mutex_init(&mosq->mid_mutex, NULL);
|
||||
mosq->thread_id = pthread_self();
|
||||
#endif
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void mosquitto__destroy(struct mosquitto *mosq)
|
||||
{
|
||||
struct mosquitto__packet *packet;
|
||||
if(!mosq) return;
|
||||
|
||||
#ifdef WITH_THREADING
|
||||
# ifdef HAVE_PTHREAD_CANCEL
|
||||
if(mosq->threaded == mosq_ts_self && !pthread_equal(mosq->thread_id, pthread_self())){
|
||||
pthread_cancel(mosq->thread_id);
|
||||
pthread_join(mosq->thread_id, NULL);
|
||||
mosq->threaded = mosq_ts_none;
|
||||
}
|
||||
# endif
|
||||
|
||||
if(mosq->id){
|
||||
/* If mosq->id is not NULL then the client has already been initialised
|
||||
* and so the mutexes need destroying. If mosq->id is NULL, the mutexes
|
||||
* haven't been initialised. */
|
||||
pthread_mutex_destroy(&mosq->callback_mutex);
|
||||
pthread_mutex_destroy(&mosq->log_callback_mutex);
|
||||
pthread_mutex_destroy(&mosq->state_mutex);
|
||||
pthread_mutex_destroy(&mosq->out_packet_mutex);
|
||||
pthread_mutex_destroy(&mosq->current_out_packet_mutex);
|
||||
pthread_mutex_destroy(&mosq->msgtime_mutex);
|
||||
pthread_mutex_destroy(&mosq->msgs_in.mutex);
|
||||
pthread_mutex_destroy(&mosq->msgs_out.mutex);
|
||||
pthread_mutex_destroy(&mosq->mid_mutex);
|
||||
}
|
||||
#endif
|
||||
if(mosq->sock != INVALID_SOCKET){
|
||||
net__socket_close(mosq);
|
||||
}
|
||||
message__cleanup_all(mosq);
|
||||
will__clear(mosq);
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
SSL_free(mosq->ssl);
|
||||
}
|
||||
if(mosq->ssl_ctx){
|
||||
SSL_CTX_free(mosq->ssl_ctx);
|
||||
}
|
||||
mosquitto__free(mosq->tls_cafile);
|
||||
mosquitto__free(mosq->tls_capath);
|
||||
mosquitto__free(mosq->tls_certfile);
|
||||
mosquitto__free(mosq->tls_keyfile);
|
||||
if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL;
|
||||
mosquitto__free(mosq->tls_version);
|
||||
mosquitto__free(mosq->tls_ciphers);
|
||||
mosquitto__free(mosq->tls_psk);
|
||||
mosquitto__free(mosq->tls_psk_identity);
|
||||
mosquitto__free(mosq->tls_alpn);
|
||||
#endif
|
||||
|
||||
mosquitto__free(mosq->address);
|
||||
mosq->address = NULL;
|
||||
|
||||
mosquitto__free(mosq->id);
|
||||
mosq->id = NULL;
|
||||
|
||||
mosquitto__free(mosq->username);
|
||||
mosq->username = NULL;
|
||||
|
||||
mosquitto__free(mosq->password);
|
||||
mosq->password = NULL;
|
||||
|
||||
mosquitto__free(mosq->host);
|
||||
mosq->host = NULL;
|
||||
|
||||
mosquitto__free(mosq->bind_address);
|
||||
mosq->bind_address = NULL;
|
||||
|
||||
/* Out packet cleanup */
|
||||
if(mosq->out_packet && !mosq->current_out_packet){
|
||||
mosq->current_out_packet = mosq->out_packet;
|
||||
mosq->out_packet = mosq->out_packet->next;
|
||||
}
|
||||
while(mosq->current_out_packet){
|
||||
packet = mosq->current_out_packet;
|
||||
/* Free data and reset values */
|
||||
mosq->current_out_packet = mosq->out_packet;
|
||||
if(mosq->out_packet){
|
||||
mosq->out_packet = mosq->out_packet->next;
|
||||
}
|
||||
|
||||
packet__cleanup(packet);
|
||||
mosquitto__free(packet);
|
||||
}
|
||||
|
||||
packet__cleanup(&mosq->in_packet);
|
||||
if(mosq->sockpairR != INVALID_SOCKET){
|
||||
COMPAT_CLOSE(mosq->sockpairR);
|
||||
mosq->sockpairR = INVALID_SOCKET;
|
||||
}
|
||||
if(mosq->sockpairW != INVALID_SOCKET){
|
||||
COMPAT_CLOSE(mosq->sockpairW);
|
||||
mosq->sockpairW = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
void mosquitto_destroy(struct mosquitto *mosq)
|
||||
{
|
||||
if(!mosq) return;
|
||||
|
||||
mosquitto__destroy(mosq);
|
||||
mosquitto__free(mosq);
|
||||
}
|
||||
|
||||
int mosquitto_socket(struct mosquitto *mosq)
|
||||
{
|
||||
if(!mosq) return INVALID_SOCKET;
|
||||
return mosq->sock;
|
||||
}
|
||||
|
||||
|
||||
bool mosquitto_want_write(struct mosquitto *mosq)
|
||||
{
|
||||
bool result = false;
|
||||
if(mosq->out_packet || mosq->current_out_packet){
|
||||
result = true;
|
||||
}
|
||||
#ifdef WITH_TLS
|
||||
if(mosq->ssl){
|
||||
if (mosq->want_write) {
|
||||
result = true;
|
||||
}else if(mosq->want_connect){
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const char *mosquitto_strerror(int mosq_errno)
|
||||
{
|
||||
switch(mosq_errno){
|
||||
case MOSQ_ERR_AUTH_CONTINUE:
|
||||
return "Continue with authentication.";
|
||||
case MOSQ_ERR_NO_SUBSCRIBERS:
|
||||
return "No subscribers.";
|
||||
case MOSQ_ERR_SUB_EXISTS:
|
||||
return "Subscription already exists.";
|
||||
case MOSQ_ERR_CONN_PENDING:
|
||||
return "Connection pending.";
|
||||
case MOSQ_ERR_SUCCESS:
|
||||
return "No error.";
|
||||
case MOSQ_ERR_NOMEM:
|
||||
return "Out of memory.";
|
||||
case MOSQ_ERR_PROTOCOL:
|
||||
return "A network protocol error occurred when communicating with the broker.";
|
||||
case MOSQ_ERR_INVAL:
|
||||
return "Invalid function arguments provided.";
|
||||
case MOSQ_ERR_NO_CONN:
|
||||
return "The client is not currently connected.";
|
||||
case MOSQ_ERR_CONN_REFUSED:
|
||||
return "The connection was refused.";
|
||||
case MOSQ_ERR_NOT_FOUND:
|
||||
return "Message not found (internal error).";
|
||||
case MOSQ_ERR_CONN_LOST:
|
||||
return "The connection was lost.";
|
||||
case MOSQ_ERR_TLS:
|
||||
return "A TLS error occurred.";
|
||||
case MOSQ_ERR_PAYLOAD_SIZE:
|
||||
return "Payload too large.";
|
||||
case MOSQ_ERR_NOT_SUPPORTED:
|
||||
return "This feature is not supported.";
|
||||
case MOSQ_ERR_AUTH:
|
||||
return "Authorisation failed.";
|
||||
case MOSQ_ERR_ACL_DENIED:
|
||||
return "Access denied by ACL.";
|
||||
case MOSQ_ERR_UNKNOWN:
|
||||
return "Unknown error.";
|
||||
case MOSQ_ERR_ERRNO:
|
||||
return strerror(errno);
|
||||
case MOSQ_ERR_EAI:
|
||||
return "Lookup error.";
|
||||
case MOSQ_ERR_PROXY:
|
||||
return "Proxy error.";
|
||||
case MOSQ_ERR_MALFORMED_UTF8:
|
||||
return "Malformed UTF-8";
|
||||
case MOSQ_ERR_DUPLICATE_PROPERTY:
|
||||
return "Duplicate property in property list";
|
||||
case MOSQ_ERR_TLS_HANDSHAKE:
|
||||
return "TLS handshake failed.";
|
||||
case MOSQ_ERR_QOS_NOT_SUPPORTED:
|
||||
return "Requested QoS not supported on server.";
|
||||
case MOSQ_ERR_OVERSIZE_PACKET:
|
||||
return "Packet larger than supported by the server.";
|
||||
case MOSQ_ERR_OCSP:
|
||||
return "OCSP error.";
|
||||
default:
|
||||
return "Unknown error.";
|
||||
}
|
||||
}
|
||||
|
||||
const char *mosquitto_connack_string(int connack_code)
|
||||
{
|
||||
switch(connack_code){
|
||||
case 0:
|
||||
return "Connection Accepted.";
|
||||
case 1:
|
||||
return "Connection Refused: unacceptable protocol version.";
|
||||
case 2:
|
||||
return "Connection Refused: identifier rejected.";
|
||||
case 3:
|
||||
return "Connection Refused: broker unavailable.";
|
||||
case 4:
|
||||
return "Connection Refused: bad user name or password.";
|
||||
case 5:
|
||||
return "Connection Refused: not authorised.";
|
||||
default:
|
||||
return "Connection Refused: unknown reason.";
|
||||
}
|
||||
}
|
||||
|
||||
const char *mosquitto_reason_string(int reason_code)
|
||||
{
|
||||
switch(reason_code){
|
||||
case MQTT_RC_SUCCESS:
|
||||
return "Success";
|
||||
case MQTT_RC_GRANTED_QOS1:
|
||||
return "Granted QoS 1";
|
||||
case MQTT_RC_GRANTED_QOS2:
|
||||
return "Granted QoS 2";
|
||||
case MQTT_RC_DISCONNECT_WITH_WILL_MSG:
|
||||
return "Disconnect with Will Message";
|
||||
case MQTT_RC_NO_MATCHING_SUBSCRIBERS:
|
||||
return "No matching subscribers";
|
||||
case MQTT_RC_NO_SUBSCRIPTION_EXISTED:
|
||||
return "No subscription existed";
|
||||
case MQTT_RC_CONTINUE_AUTHENTICATION:
|
||||
return "Continue authentication";
|
||||
case MQTT_RC_REAUTHENTICATE:
|
||||
return "Re-authenticate";
|
||||
|
||||
case MQTT_RC_UNSPECIFIED:
|
||||
return "Unspecified error";
|
||||
case MQTT_RC_MALFORMED_PACKET:
|
||||
return "Malformed Packet";
|
||||
case MQTT_RC_PROTOCOL_ERROR:
|
||||
return "Protocol Error";
|
||||
case MQTT_RC_IMPLEMENTATION_SPECIFIC:
|
||||
return "Implementation specific error";
|
||||
case MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION:
|
||||
return "Unsupported Protocol Version";
|
||||
case MQTT_RC_CLIENTID_NOT_VALID:
|
||||
return "Client Identifier not valid";
|
||||
case MQTT_RC_BAD_USERNAME_OR_PASSWORD:
|
||||
return "Bad User Name or Password";
|
||||
case MQTT_RC_NOT_AUTHORIZED:
|
||||
return "Not authorized";
|
||||
case MQTT_RC_SERVER_UNAVAILABLE:
|
||||
return "Server unavailable";
|
||||
case MQTT_RC_SERVER_BUSY:
|
||||
return "Server busy";
|
||||
case MQTT_RC_BANNED:
|
||||
return "Banned";
|
||||
case MQTT_RC_SERVER_SHUTTING_DOWN:
|
||||
return "Server shutting down";
|
||||
case MQTT_RC_BAD_AUTHENTICATION_METHOD:
|
||||
return "Bad authentication method";
|
||||
case MQTT_RC_KEEP_ALIVE_TIMEOUT:
|
||||
return "Keep Alive timeout";
|
||||
case MQTT_RC_SESSION_TAKEN_OVER:
|
||||
return "Session taken over";
|
||||
case MQTT_RC_TOPIC_FILTER_INVALID:
|
||||
return "Topic Filter invalid";
|
||||
case MQTT_RC_TOPIC_NAME_INVALID:
|
||||
return "Topic Name invalid";
|
||||
case MQTT_RC_PACKET_ID_IN_USE:
|
||||
return "Packet Identifier in use";
|
||||
case MQTT_RC_PACKET_ID_NOT_FOUND:
|
||||
return "Packet Identifier not found";
|
||||
case MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED:
|
||||
return "Receive Maximum exceeded";
|
||||
case MQTT_RC_TOPIC_ALIAS_INVALID:
|
||||
return "Topic Alias invalid";
|
||||
case MQTT_RC_PACKET_TOO_LARGE:
|
||||
return "Packet too large";
|
||||
case MQTT_RC_MESSAGE_RATE_TOO_HIGH:
|
||||
return "Message rate too high";
|
||||
case MQTT_RC_QUOTA_EXCEEDED:
|
||||
return "Quota exceeded";
|
||||
case MQTT_RC_ADMINISTRATIVE_ACTION:
|
||||
return "Administrative action";
|
||||
case MQTT_RC_PAYLOAD_FORMAT_INVALID:
|
||||
return "Payload format invalid";
|
||||
case MQTT_RC_RETAIN_NOT_SUPPORTED:
|
||||
return "Retain not supported";
|
||||
case MQTT_RC_QOS_NOT_SUPPORTED:
|
||||
return "QoS not supported";
|
||||
case MQTT_RC_USE_ANOTHER_SERVER:
|
||||
return "Use another server";
|
||||
case MQTT_RC_SERVER_MOVED:
|
||||
return "Server moved";
|
||||
case MQTT_RC_SHARED_SUBS_NOT_SUPPORTED:
|
||||
return "Shared Subscriptions not supported";
|
||||
case MQTT_RC_CONNECTION_RATE_EXCEEDED:
|
||||
return "Connection rate exceeded";
|
||||
case MQTT_RC_MAXIMUM_CONNECT_TIME:
|
||||
return "Maximum connect time";
|
||||
case MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED:
|
||||
return "Subscription identifiers not supported";
|
||||
case MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED:
|
||||
return "Wildcard Subscriptions not supported";
|
||||
default:
|
||||
return "Unknown reason";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_string_to_command(const char *str, int *cmd)
|
||||
{
|
||||
if(!strcasecmp(str, "connect")){
|
||||
*cmd = CMD_CONNECT;
|
||||
}else if(!strcasecmp(str, "connack")){
|
||||
*cmd = CMD_CONNACK;
|
||||
}else if(!strcasecmp(str, "publish")){
|
||||
*cmd = CMD_PUBLISH;
|
||||
}else if(!strcasecmp(str, "puback")){
|
||||
*cmd = CMD_PUBACK;
|
||||
}else if(!strcasecmp(str, "pubrec")){
|
||||
*cmd = CMD_PUBREC;
|
||||
}else if(!strcasecmp(str, "pubrel")){
|
||||
*cmd = CMD_PUBREL;
|
||||
}else if(!strcasecmp(str, "pubcomp")){
|
||||
*cmd = CMD_PUBCOMP;
|
||||
}else if(!strcasecmp(str, "subscribe")){
|
||||
*cmd = CMD_SUBSCRIBE;
|
||||
}else if(!strcasecmp(str, "unsubscribe")){
|
||||
*cmd = CMD_UNSUBSCRIBE;
|
||||
}else if(!strcasecmp(str, "disconnect")){
|
||||
*cmd = CMD_DISCONNECT;
|
||||
}else if(!strcasecmp(str, "auth")){
|
||||
*cmd = CMD_AUTH;
|
||||
}else if(!strcasecmp(str, "will")){
|
||||
*cmd = CMD_WILL;
|
||||
}else{
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count)
|
||||
{
|
||||
int len;
|
||||
int hier_count = 1;
|
||||
int start, stop;
|
||||
int hier;
|
||||
int tlen;
|
||||
int i, j;
|
||||
|
||||
if(!subtopic || !topics || !count) return MOSQ_ERR_INVAL;
|
||||
|
||||
len = strlen(subtopic);
|
||||
|
||||
for(i=0; i<len; i++){
|
||||
if(subtopic[i] == '/'){
|
||||
if(i > len-1){
|
||||
/* Separator at end of line */
|
||||
}else{
|
||||
hier_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*topics) = mosquitto__calloc(hier_count, sizeof(char *));
|
||||
if(!(*topics)) return MOSQ_ERR_NOMEM;
|
||||
|
||||
start = 0;
|
||||
stop = 0;
|
||||
hier = 0;
|
||||
|
||||
for(i=0; i<len+1; i++){
|
||||
if(subtopic[i] == '/' || subtopic[i] == '\0'){
|
||||
stop = i;
|
||||
if(start != stop){
|
||||
tlen = stop-start + 1;
|
||||
(*topics)[hier] = mosquitto__calloc(tlen, sizeof(char));
|
||||
if(!(*topics)[hier]){
|
||||
for(j=0; j<hier; j++){
|
||||
mosquitto__free((*topics)[j]);
|
||||
}
|
||||
mosquitto__free((*topics));
|
||||
return MOSQ_ERR_NOMEM;
|
||||
}
|
||||
for(j=start; j<stop; j++){
|
||||
(*topics)[hier][j-start] = subtopic[j];
|
||||
}
|
||||
}
|
||||
start = i+1;
|
||||
hier++;
|
||||
}
|
||||
}
|
||||
|
||||
*count = hier_count;
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int mosquitto_sub_topic_tokens_free(char ***topics, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!topics || !(*topics) || count<1) return MOSQ_ERR_INVAL;
|
||||
|
||||
for(i=0; i<count; i++){
|
||||
mosquitto__free((*topics)[i]);
|
||||
}
|
||||
mosquitto__free(*topics);
|
||||
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,356 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2010-2019 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
Tatsuzo Osawa - Add epoll.
|
||||
*/
|
||||
|
||||
#ifndef MOSQUITTO_INTERNAL_H
|
||||
#define MOSQUITTO_INTERNAL_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_TLS
|
||||
# include <openssl/ssl.h>
|
||||
#else
|
||||
# include <time.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(WITH_THREADING) && !defined(WITH_BROKER)
|
||||
# include <pthread.h>
|
||||
#else
|
||||
# include <dummypthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SRV
|
||||
# include <ares.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
# if _MSC_VER < 1600
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
# else
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "mosquitto.h"
|
||||
#include "time_mosq.h"
|
||||
#ifdef WITH_BROKER
|
||||
# ifdef __linux__
|
||||
# include <netdb.h>
|
||||
# endif
|
||||
# include "uthash.h"
|
||||
struct mosquitto_client_msg;
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
typedef SOCKET mosq_sock_t;
|
||||
#else
|
||||
typedef int mosq_sock_t;
|
||||
#endif
|
||||
|
||||
enum mosquitto_msg_direction {
|
||||
mosq_md_in = 0,
|
||||
mosq_md_out = 1
|
||||
};
|
||||
|
||||
enum mosquitto_msg_state {
|
||||
mosq_ms_invalid = 0,
|
||||
mosq_ms_publish_qos0 = 1,
|
||||
mosq_ms_publish_qos1 = 2,
|
||||
mosq_ms_wait_for_puback = 3,
|
||||
mosq_ms_publish_qos2 = 4,
|
||||
mosq_ms_wait_for_pubrec = 5,
|
||||
mosq_ms_resend_pubrel = 6,
|
||||
mosq_ms_wait_for_pubrel = 7,
|
||||
mosq_ms_resend_pubcomp = 8,
|
||||
mosq_ms_wait_for_pubcomp = 9,
|
||||
mosq_ms_send_pubrec = 10,
|
||||
mosq_ms_queued = 11
|
||||
};
|
||||
|
||||
enum mosquitto_client_state {
|
||||
mosq_cs_new = 0,
|
||||
mosq_cs_connected = 1,
|
||||
mosq_cs_disconnecting = 2,
|
||||
mosq_cs_active = 3,
|
||||
mosq_cs_connect_pending = 4,
|
||||
mosq_cs_connect_srv = 5,
|
||||
mosq_cs_disconnect_ws = 6,
|
||||
mosq_cs_disconnected = 7,
|
||||
mosq_cs_socks5_new = 8,
|
||||
mosq_cs_socks5_start = 9,
|
||||
mosq_cs_socks5_request = 10,
|
||||
mosq_cs_socks5_reply = 11,
|
||||
mosq_cs_socks5_auth_ok = 12,
|
||||
mosq_cs_socks5_userpass_reply = 13,
|
||||
mosq_cs_socks5_send_userpass = 14,
|
||||
mosq_cs_expiring = 15,
|
||||
mosq_cs_duplicate = 17, /* client that has been taken over by another with the same id */
|
||||
mosq_cs_disconnect_with_will = 18,
|
||||
mosq_cs_disused = 19, /* client that has been added to the disused list to be freed */
|
||||
mosq_cs_authenticating = 20, /* Client has sent CONNECT but is still undergoing extended authentication */
|
||||
mosq_cs_reauthenticating = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */
|
||||
};
|
||||
|
||||
enum mosquitto__protocol {
|
||||
mosq_p_invalid = 0,
|
||||
mosq_p_mqtt31 = 1,
|
||||
mosq_p_mqtt311 = 2,
|
||||
mosq_p_mqtts = 3,
|
||||
mosq_p_mqtt5 = 5,
|
||||
};
|
||||
|
||||
enum mosquitto__threaded_state {
|
||||
mosq_ts_none, /* No threads in use */
|
||||
mosq_ts_self, /* Threads started by libmosquitto */
|
||||
mosq_ts_external /* Threads started by external code */
|
||||
};
|
||||
|
||||
enum mosquitto__transport {
|
||||
mosq_t_invalid = 0,
|
||||
mosq_t_tcp = 1,
|
||||
mosq_t_ws = 2,
|
||||
mosq_t_sctp = 3
|
||||
};
|
||||
|
||||
|
||||
struct mosquitto__alias{
|
||||
char *topic;
|
||||
uint16_t alias;
|
||||
};
|
||||
|
||||
struct session_expiry_list {
|
||||
struct mosquitto *context;
|
||||
struct session_expiry_list *prev;
|
||||
struct session_expiry_list *next;
|
||||
};
|
||||
|
||||
struct mosquitto__packet{
|
||||
uint8_t *payload;
|
||||
struct mosquitto__packet *next;
|
||||
uint32_t remaining_mult;
|
||||
uint32_t remaining_length;
|
||||
uint32_t packet_length;
|
||||
uint32_t to_process;
|
||||
uint32_t pos;
|
||||
uint16_t mid;
|
||||
uint8_t command;
|
||||
int8_t remaining_count;
|
||||
};
|
||||
|
||||
struct mosquitto_message_all{
|
||||
struct mosquitto_message_all *next;
|
||||
struct mosquitto_message_all *prev;
|
||||
mosquitto_property *properties;
|
||||
time_t timestamp;
|
||||
//enum mosquitto_msg_direction direction;
|
||||
enum mosquitto_msg_state state;
|
||||
bool dup;
|
||||
struct mosquitto_message msg;
|
||||
uint32_t expiry_interval;
|
||||
};
|
||||
|
||||
#ifdef WITH_TLS
|
||||
enum mosquitto__keyform {
|
||||
mosq_k_pem = 0,
|
||||
mosq_k_engine = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct will_delay_list {
|
||||
struct mosquitto *context;
|
||||
struct will_delay_list *prev;
|
||||
struct will_delay_list *next;
|
||||
};
|
||||
|
||||
struct mosquitto_msg_data{
|
||||
#ifdef WITH_BROKER
|
||||
struct mosquitto_client_msg *inflight;
|
||||
struct mosquitto_client_msg *queued;
|
||||
unsigned long msg_bytes;
|
||||
unsigned long msg_bytes12;
|
||||
int msg_count;
|
||||
int msg_count12;
|
||||
#else
|
||||
struct mosquitto_message_all *inflight;
|
||||
int queue_len;
|
||||
# ifdef WITH_THREADING
|
||||
pthread_mutex_t mutex;
|
||||
# endif
|
||||
#endif
|
||||
int inflight_quota;
|
||||
uint16_t inflight_maximum;
|
||||
};
|
||||
|
||||
|
||||
struct mosquitto {
|
||||
mosq_sock_t sock;
|
||||
#ifndef WITH_BROKER
|
||||
mosq_sock_t sockpairR, sockpairW;
|
||||
#endif
|
||||
#if defined(__GLIBC__) && defined(WITH_ADNS)
|
||||
struct gaicb *adns; /* For getaddrinfo_a */
|
||||
#endif
|
||||
enum mosquitto__protocol protocol;
|
||||
char *address;
|
||||
char *id;
|
||||
char *username;
|
||||
char *password;
|
||||
uint16_t keepalive;
|
||||
uint16_t last_mid;
|
||||
enum mosquitto_client_state state;
|
||||
time_t last_msg_in;
|
||||
time_t next_msg_out;
|
||||
time_t ping_t;
|
||||
struct mosquitto__packet in_packet;
|
||||
struct mosquitto__packet *current_out_packet;
|
||||
struct mosquitto__packet *out_packet;
|
||||
struct mosquitto_message_all *will;
|
||||
struct mosquitto__alias *aliases;
|
||||
struct will_delay_list *will_delay_entry;
|
||||
uint32_t maximum_packet_size;
|
||||
int alias_count;
|
||||
uint32_t will_delay_interval;
|
||||
time_t will_delay_time;
|
||||
#ifdef WITH_TLS
|
||||
SSL *ssl;
|
||||
SSL_CTX *ssl_ctx;
|
||||
char *tls_cafile;
|
||||
char *tls_capath;
|
||||
char *tls_certfile;
|
||||
char *tls_keyfile;
|
||||
int (*tls_pw_callback)(char *buf, int size, int rwflag, void *userdata);
|
||||
char *tls_version;
|
||||
char *tls_ciphers;
|
||||
char *tls_psk;
|
||||
char *tls_psk_identity;
|
||||
int tls_cert_reqs;
|
||||
bool tls_insecure;
|
||||
bool ssl_ctx_defaults;
|
||||
bool tls_ocsp_required;
|
||||
char *tls_engine;
|
||||
char *tls_engine_kpass_sha1;
|
||||
enum mosquitto__keyform tls_keyform;
|
||||
char *tls_alpn;
|
||||
#endif
|
||||
bool want_write;
|
||||
bool want_connect;
|
||||
#if defined(WITH_THREADING) && !defined(WITH_BROKER)
|
||||
pthread_mutex_t callback_mutex;
|
||||
pthread_mutex_t log_callback_mutex;
|
||||
pthread_mutex_t msgtime_mutex;
|
||||
pthread_mutex_t out_packet_mutex;
|
||||
pthread_mutex_t current_out_packet_mutex;
|
||||
pthread_mutex_t state_mutex;
|
||||
pthread_mutex_t mid_mutex;
|
||||
pthread_t thread_id;
|
||||
#endif
|
||||
bool clean_start;
|
||||
uint32_t session_expiry_interval;
|
||||
time_t session_expiry_time;
|
||||
#ifdef WITH_BROKER
|
||||
bool removed_from_by_id; /* True if removed from by_id hash */
|
||||
bool is_dropping;
|
||||
bool is_bridge;
|
||||
struct mosquitto__bridge *bridge;
|
||||
struct mosquitto_msg_data msgs_in;
|
||||
struct mosquitto_msg_data msgs_out;
|
||||
struct mosquitto__acl_user *acl_list;
|
||||
struct mosquitto__listener *listener;
|
||||
struct mosquitto__packet *out_packet_last;
|
||||
struct mosquitto__subhier **subs;
|
||||
struct mosquitto__subshared_ref **shared_subs;
|
||||
char *auth_method;
|
||||
int sub_count;
|
||||
int shared_sub_count;
|
||||
int pollfd_index;
|
||||
# ifdef WITH_WEBSOCKETS
|
||||
# if defined(LWS_LIBRARY_VERSION_NUMBER)
|
||||
struct lws *wsi;
|
||||
# else
|
||||
struct libwebsocket_context *ws_context;
|
||||
struct libwebsocket *wsi;
|
||||
# endif
|
||||
# endif
|
||||
bool ws_want_write;
|
||||
bool assigned_id;
|
||||
#else
|
||||
# ifdef WITH_SOCKS
|
||||
char *socks5_host;
|
||||
int socks5_port;
|
||||
char *socks5_username;
|
||||
char *socks5_password;
|
||||
# endif
|
||||
void *userdata;
|
||||
bool in_callback;
|
||||
struct mosquitto_msg_data msgs_in;
|
||||
struct mosquitto_msg_data msgs_out;
|
||||
void (*on_connect)(struct mosquitto *, void *userdata, int rc);
|
||||
void (*on_connect_with_flags)(struct mosquitto *, void *userdata, int rc, int flags);
|
||||
void (*on_connect_v5)(struct mosquitto *, void *userdata, int rc, int flags, const mosquitto_property *props);
|
||||
void (*on_disconnect)(struct mosquitto *, void *userdata, int rc);
|
||||
void (*on_disconnect_v5)(struct mosquitto *, void *userdata, int rc, const mosquitto_property *props);
|
||||
void (*on_publish)(struct mosquitto *, void *userdata, int mid);
|
||||
void (*on_publish_v5)(struct mosquitto *, void *userdata, int mid, int reason_code, const mosquitto_property *props);
|
||||
void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message);
|
||||
void (*on_message_v5)(struct mosquitto *, void *userdata, const struct mosquitto_message *message, const mosquitto_property *props);
|
||||
void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos);
|
||||
void (*on_subscribe_v5)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos, const mosquitto_property *props);
|
||||
void (*on_unsubscribe)(struct mosquitto *, void *userdata, int mid);
|
||||
void (*on_unsubscribe_v5)(struct mosquitto *, void *userdata, int mid, const mosquitto_property *props);
|
||||
void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str);
|
||||
//void (*on_error)();
|
||||
char *host;
|
||||
int port;
|
||||
char *bind_address;
|
||||
unsigned int reconnects;
|
||||
unsigned int reconnect_delay;
|
||||
unsigned int reconnect_delay_max;
|
||||
bool reconnect_exponential_backoff;
|
||||
char threaded;
|
||||
struct mosquitto__packet *out_packet_last;
|
||||
# ifdef WITH_SRV
|
||||
ares_channel achan;
|
||||
# endif
|
||||
#endif
|
||||
uint8_t maximum_qos;
|
||||
|
||||
#ifdef WITH_BROKER
|
||||
UT_hash_handle hh_id;
|
||||
UT_hash_handle hh_sock;
|
||||
struct mosquitto *for_free_next;
|
||||
struct session_expiry_list *expiry_list_item;
|
||||
#endif
|
||||
#ifdef WITH_EPOLL
|
||||
uint32_t events;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define STREMPTY(str) (str[0] == '\0')
|
||||
|
||||
void do_client_disconnect(struct mosquitto *mosq, int reason_code, const mosquitto_property *properties);
|
||||
|
||||
#endif
|
||||
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2018 Roger Light <roger@atchoo.org>
|
||||
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
|
||||
The Eclipse Public License is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
and the Eclipse Distribution License is available at
|
||||
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
|
||||
Contributors:
|
||||
Roger Light - initial implementation and documentation.
|
||||
*/
|
||||
|
||||
#ifndef MQTT_PROTOCOL_H
|
||||
#define MQTT_PROTOCOL_H
|
||||
|
||||
#define PROTOCOL_NAME_v31 "MQIsdp"
|
||||
#define PROTOCOL_VERSION_v31 3
|
||||
|
||||
#define PROTOCOL_NAME "MQTT"
|
||||
|
||||
#define PROTOCOL_VERSION_v311 4
|
||||
#define PROTOCOL_VERSION_v5 5
|
||||
|
||||
|
||||
/* Message types */
|
||||
#define CMD_CONNECT 0x10
|
||||
#define CMD_CONNACK 0x20
|
||||
#define CMD_PUBLISH 0x30
|
||||
#define CMD_PUBACK 0x40
|
||||
#define CMD_PUBREC 0x50
|
||||
#define CMD_PUBREL 0x60
|
||||
#define CMD_PUBCOMP 0x70
|
||||
#define CMD_SUBSCRIBE 0x80
|
||||
#define CMD_SUBACK 0x90
|
||||
#define CMD_UNSUBSCRIBE 0xA0
|
||||
#define CMD_UNSUBACK 0xB0
|
||||
#define CMD_PINGREQ 0xC0
|
||||
#define CMD_PINGRESP 0xD0
|
||||
#define CMD_DISCONNECT 0xE0
|
||||
#define CMD_AUTH 0xF0
|
||||
|
||||
/* Mosquitto only: for distinguishing CONNECT and WILL properties */
|
||||
#define CMD_WILL 0x100
|
||||
|
||||
enum mqtt311_connack_codes {
|
||||
CONNACK_ACCEPTED = 0,
|
||||
CONNACK_REFUSED_PROTOCOL_VERSION = 1,
|
||||
CONNACK_REFUSED_IDENTIFIER_REJECTED = 2,
|
||||
CONNACK_REFUSED_SERVER_UNAVAILABLE = 3,
|
||||
CONNACK_REFUSED_BAD_USERNAME_PASSWORD = 4,
|
||||
CONNACK_REFUSED_NOT_AUTHORIZED = 5,
|
||||
};
|
||||
|
||||
|
||||
enum mqtt5_return_codes {
|
||||
MQTT_RC_SUCCESS = 0, /* CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH */
|
||||
MQTT_RC_NORMAL_DISCONNECTION = 0, /* DISCONNECT */
|
||||
MQTT_RC_GRANTED_QOS0 = 0, /* SUBACK */
|
||||
MQTT_RC_GRANTED_QOS1 = 1, /* SUBACK */
|
||||
MQTT_RC_GRANTED_QOS2 = 2, /* SUBACK */
|
||||
MQTT_RC_DISCONNECT_WITH_WILL_MSG = 4, /* DISCONNECT */
|
||||
MQTT_RC_NO_MATCHING_SUBSCRIBERS = 16, /* PUBACK, PUBREC */
|
||||
MQTT_RC_NO_SUBSCRIPTION_EXISTED = 17, /* UNSUBACK */
|
||||
MQTT_RC_CONTINUE_AUTHENTICATION = 24, /* AUTH */
|
||||
MQTT_RC_REAUTHENTICATE = 25, /* AUTH */
|
||||
|
||||
MQTT_RC_UNSPECIFIED = 128, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */
|
||||
MQTT_RC_MALFORMED_PACKET = 129, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_PROTOCOL_ERROR = 130, /* DISCONNECT */
|
||||
MQTT_RC_IMPLEMENTATION_SPECIFIC = 131, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */
|
||||
MQTT_RC_UNSUPPORTED_PROTOCOL_VERSION = 132, /* CONNACK */
|
||||
MQTT_RC_CLIENTID_NOT_VALID = 133, /* CONNACK */
|
||||
MQTT_RC_BAD_USERNAME_OR_PASSWORD = 134, /* CONNACK */
|
||||
MQTT_RC_NOT_AUTHORIZED = 135, /* CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT */
|
||||
MQTT_RC_SERVER_UNAVAILABLE = 136, /* CONNACK */
|
||||
MQTT_RC_SERVER_BUSY = 137, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_BANNED = 138, /* CONNACK */
|
||||
MQTT_RC_SERVER_SHUTTING_DOWN = 139, /* DISCONNECT */
|
||||
MQTT_RC_BAD_AUTHENTICATION_METHOD = 140, /* CONNACK */
|
||||
MQTT_RC_KEEP_ALIVE_TIMEOUT = 141, /* DISCONNECT */
|
||||
MQTT_RC_SESSION_TAKEN_OVER = 142, /* DISCONNECT */
|
||||
MQTT_RC_TOPIC_FILTER_INVALID = 143, /* SUBACK, UNSUBACK, DISCONNECT */
|
||||
MQTT_RC_TOPIC_NAME_INVALID = 144, /* CONNACK, PUBACK, PUBREC, DISCONNECT */
|
||||
MQTT_RC_PACKET_ID_IN_USE = 145, /* PUBACK, SUBACK, UNSUBACK */
|
||||
MQTT_RC_PACKET_ID_NOT_FOUND = 146, /* PUBREL, PUBCOMP */
|
||||
MQTT_RC_RECEIVE_MAXIMUM_EXCEEDED = 147, /* DISCONNECT */
|
||||
MQTT_RC_TOPIC_ALIAS_INVALID = 148, /* DISCONNECT */
|
||||
MQTT_RC_PACKET_TOO_LARGE = 149, /* CONNACK, PUBACK, PUBREC, DISCONNECT */
|
||||
MQTT_RC_MESSAGE_RATE_TOO_HIGH = 150, /* DISCONNECT */
|
||||
MQTT_RC_QUOTA_EXCEEDED = 151, /* PUBACK, PUBREC, SUBACK, DISCONNECT */
|
||||
MQTT_RC_ADMINISTRATIVE_ACTION = 152, /* DISCONNECT */
|
||||
MQTT_RC_PAYLOAD_FORMAT_INVALID = 153, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_RETAIN_NOT_SUPPORTED = 154, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_QOS_NOT_SUPPORTED = 155, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_USE_ANOTHER_SERVER = 156, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_SERVER_MOVED = 157, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_SHARED_SUBS_NOT_SUPPORTED = 158, /* SUBACK, DISCONNECT */
|
||||
MQTT_RC_CONNECTION_RATE_EXCEEDED = 159, /* CONNACK, DISCONNECT */
|
||||
MQTT_RC_MAXIMUM_CONNECT_TIME = 160, /* DISCONNECT */
|
||||
MQTT_RC_SUBSCRIPTION_IDS_NOT_SUPPORTED = 161, /* SUBACK, DISCONNECT */
|
||||
MQTT_RC_WILDCARD_SUBS_NOT_SUPPORTED = 162, /* SUBACK, DISCONNECT */
|
||||
};
|
||||
|
||||
enum mqtt5_property {
|
||||
MQTT_PROP_PAYLOAD_FORMAT_INDICATOR = 1, /* Byte : PUBLISH, Will Properties */
|
||||
MQTT_PROP_MESSAGE_EXPIRY_INTERVAL = 2, /* 4 byte int : PUBLISH, Will Properties */
|
||||
MQTT_PROP_CONTENT_TYPE = 3, /* UTF-8 string : PUBLISH, Will Properties */
|
||||
MQTT_PROP_RESPONSE_TOPIC = 8, /* UTF-8 string : PUBLISH, Will Properties */
|
||||
MQTT_PROP_CORRELATION_DATA = 9, /* Binary Data : PUBLISH, Will Properties */
|
||||
MQTT_PROP_SUBSCRIPTION_IDENTIFIER = 11, /* Variable byte int : PUBLISH, SUBSCRIBE */
|
||||
MQTT_PROP_SESSION_EXPIRY_INTERVAL = 17, /* 4 byte int : CONNECT, CONNACK, DISCONNECT */
|
||||
MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER = 18, /* UTF-8 string : CONNACK */
|
||||
MQTT_PROP_SERVER_KEEP_ALIVE = 19, /* 2 byte int : CONNACK */
|
||||
MQTT_PROP_AUTHENTICATION_METHOD = 21, /* UTF-8 string : CONNECT, CONNACK, AUTH */
|
||||
MQTT_PROP_AUTHENTICATION_DATA = 22, /* Binary Data : CONNECT, CONNACK, AUTH */
|
||||
MQTT_PROP_REQUEST_PROBLEM_INFORMATION = 23, /* Byte : CONNECT */
|
||||
MQTT_PROP_WILL_DELAY_INTERVAL = 24, /* 4 byte int : Will properties */
|
||||
MQTT_PROP_REQUEST_RESPONSE_INFORMATION = 25,/* Byte : CONNECT */
|
||||
MQTT_PROP_RESPONSE_INFORMATION = 26, /* UTF-8 string : CONNACK */
|
||||
MQTT_PROP_SERVER_REFERENCE = 28, /* UTF-8 string : CONNACK, DISCONNECT */
|
||||
MQTT_PROP_REASON_STRING = 31, /* UTF-8 string : All except Will properties */
|
||||
MQTT_PROP_RECEIVE_MAXIMUM = 33, /* 2 byte int : CONNECT, CONNACK */
|
||||
MQTT_PROP_TOPIC_ALIAS_MAXIMUM = 34, /* 2 byte int : CONNECT, CONNACK */
|
||||
MQTT_PROP_TOPIC_ALIAS = 35, /* 2 byte int : PUBLISH */
|
||||
MQTT_PROP_MAXIMUM_QOS = 36, /* Byte : CONNACK */
|
||||
MQTT_PROP_RETAIN_AVAILABLE = 37, /* Byte : CONNACK */
|
||||
MQTT_PROP_USER_PROPERTY = 38, /* UTF-8 string pair : All */
|
||||
MQTT_PROP_MAXIMUM_PACKET_SIZE = 39, /* 4 byte int : CONNECT, CONNACK */
|
||||
MQTT_PROP_WILDCARD_SUB_AVAILABLE = 40, /* Byte : CONNACK */
|
||||
MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE = 41, /* Byte : CONNACK */
|
||||
MQTT_PROP_SHARED_SUB_AVAILABLE = 42, /* Byte : CONNACK */
|
||||
};
|
||||
|
||||
enum mqtt5_property_type {
|
||||
MQTT_PROP_TYPE_BYTE = 1,
|
||||
MQTT_PROP_TYPE_INT16 = 2,
|
||||
MQTT_PROP_TYPE_INT32 = 3,
|
||||
MQTT_PROP_TYPE_VARINT = 4,
|
||||
MQTT_PROP_TYPE_BINARY = 5,
|
||||
MQTT_PROP_TYPE_STRING = 6,
|
||||
MQTT_PROP_TYPE_STRING_PAIR = 7
|
||||
};
|
||||
|
||||
enum mqtt5_sub_options {
|
||||
MQTT_SUB_OPT_NO_LOCAL = 0x04,
|
||||
MQTT_SUB_OPT_RETAIN_AS_PUBLISHED = 0x08,
|
||||
MQTT_SUB_OPT_SEND_RETAIN_ALWAYS = 0x00,
|
||||
MQTT_SUB_OPT_SEND_RETAIN_NEW = 0x10,
|
||||
MQTT_SUB_OPT_SEND_RETAIN_NEVER = 0x20,
|
||||
};
|
||||
|
||||
#define MQTT_MAX_PAYLOAD 268435455
|
||||
|
||||
#endif
|