mosquitto-1.4.15/0000775000175000017500000000000013245550210012663 5ustar rogerrogermosquitto-1.4.15/config.mk0000664000175000017500000001536313245550210014471 0ustar rogerroger# ============================================================================= # User configuration section. # # These options control compilation on all systems apart from Windows and Mac # OS X. Use CMake to compile on Windows and Mac. # # Largely, these are options that are designed to make mosquitto run more # easily in restrictive environments by removing features. # # Modify the variable below to enable/disable features. # # Can also be overriden at the command line, e.g.: # # make WITH_TLS=no # ============================================================================= # Uncomment to compile the broker with tcpd/libwrap support. #WITH_WRAP:=yes # Comment out to disable SSL/TLS support in the broker and client. # Disabling this will also mean that passwords must be stored in plain text. It # is strongly recommended that you only disable WITH_TLS if you are not using # password authentication at all. WITH_TLS:=yes # Comment out to disable TLS/PSK support in the broker and client. Requires # WITH_TLS=yes. # This must be disabled if using openssl < 1.0. WITH_TLS_PSK:=yes # Comment out to disable client client threading support. WITH_THREADING:=yes # Comment out to remove bridge support from the broker. This allow the broker # to connect to other brokers and subscribe/publish to topics. You probably # want to leave this included unless you want to save a very small amount of # memory size and CPU time. WITH_BRIDGE:=yes # Comment out to remove persistent database support from the broker. This # allows the broker to store retained messages and durable subscriptions to a # file periodically and on shutdown. This is usually desirable (and is # suggested by the MQTT spec), but it can be disabled if required. WITH_PERSISTENCE:=yes # Comment out to remove memory tracking support from the broker. If disabled, # mosquitto won't track heap memory usage nor export '$SYS/broker/heap/current # size', but will use slightly less memory and CPU time. WITH_MEMORY_TRACKING:=yes # Compile with database upgrading support? If disabled, mosquitto won't # automatically upgrade old database versions. # Not currently supported. #WITH_DB_UPGRADE:=yes # Comment out to remove publishing of the $SYS topic hierarchy containing # information about the broker state. WITH_SYS_TREE:=yes # Build with SRV lookup support. WITH_SRV:=yes # Build using libuuid for clientid generation (Linux only - please report if # supported on your platform). WITH_UUID:=yes # Build with websockets support on the broker. WITH_WEBSOCKETS:=no # Use elliptic keys in broker WITH_EC:=yes # Build man page documentation by default. WITH_DOCS:=yes # Build with client support for SOCK5 proxy. WITH_SOCKS:=yes # Build with async dns lookup support for bridges (temporary). Requires glibc. #WITH_ADNS:=yes # ============================================================================= # End of user configuration # ============================================================================= # Also bump lib/mosquitto.h, CMakeLists.txt, # installer/mosquitto.nsi, installer/mosquitto-cygwin.nsi VERSION=1.4.15 TIMESTAMP:=$(shell date "+%F %T%z") # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 # Man page generation requires xsltproc and docbook-xsl XSLTPROC=xsltproc # For html generation DB_HTML_XSL=man/html.xsl #MANCOUNTRIES=en_GB UNAME:=$(shell uname -s) ifeq ($(UNAME),SunOS) ifeq ($(CC),cc) CFLAGS?=-O else CFLAGS?=-Wall -ggdb -O2 endif else CFLAGS?=-Wall -ggdb -O2 endif LIB_CFLAGS:=${CFLAGS} ${CPPFLAGS} -I. -I.. -I../lib LIB_CXXFLAGS:=$(LIB_CFLAGS) ${CPPFLAGS} LIB_LDFLAGS:=${LDFLAGS} BROKER_CFLAGS:=${LIB_CFLAGS} ${CPPFLAGS} -DVERSION="\"${VERSION}\"" -DTIMESTAMP="\"${TIMESTAMP}\"" -DWITH_BROKER CLIENT_CFLAGS:=${CFLAGS} ${CPPFLAGS} -I../lib -DVERSION="\"${VERSION}\"" ifneq ($(or $(findstring $(UNAME),FreeBSD), $(findstring $(UNAME),OpenBSD)),) BROKER_LIBS:=-lm else BROKER_LIBS:=-ldl -lm endif LIB_LIBS:= PASSWD_LIBS:= ifeq ($(UNAME),Linux) BROKER_LIBS:=$(BROKER_LIBS) -lrt -Wl,--dynamic-list=linker.syms LIB_LIBS:=$(LIB_LIBS) -lrt endif CLIENT_LDFLAGS:=$(LDFLAGS) -L../lib ../lib/libmosquitto.so.${SOVERSION} ifeq ($(UNAME),SunOS) ifeq ($(CC),cc) LIB_CFLAGS:=$(LIB_CFLAGS) -xc99 -KPIC else LIB_CFLAGS:=$(LIB_CFLAGS) -fPIC endif ifeq ($(CXX),CC) LIB_CXXFLAGS:=$(LIB_CXXFLAGS) -KPIC else LIB_CXXFLAGS:=$(LIB_CXXFLAGS) -fPIC endif else LIB_CFLAGS:=$(LIB_CFLAGS) -fPIC LIB_CXXFLAGS:=$(LIB_CXXFLAGS) -fPIC endif ifneq ($(UNAME),SunOS) LIB_LDFLAGS:=$(LIB_LDFLAGS) -Wl,--version-script=linker.version -Wl,-soname,libmosquitto.so.$(SOVERSION) endif ifeq ($(UNAME),QNX) BROKER_LIBS:=$(BROKER_LIBS) -lsocket LIB_LIBS:=$(LIB_LIBS) -lsocket endif ifeq ($(WITH_WRAP),yes) BROKER_LIBS:=$(BROKER_LIBS) -lwrap BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_WRAP endif ifeq ($(WITH_TLS),yes) BROKER_LIBS:=$(BROKER_LIBS) -lssl -lcrypto LIB_LIBS:=$(LIB_LIBS) -lssl -lcrypto BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_TLS LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_TLS PASSWD_LIBS:=-lcrypto CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -DWITH_TLS ifeq ($(WITH_TLS_PSK),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_TLS_PSK LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_TLS_PSK CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -DWITH_TLS_PSK endif endif ifeq ($(WITH_THREADING),yes) LIB_LIBS:=$(LIB_LIBS) -lpthread LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_THREADING endif ifeq ($(WITH_SOCKS),yes) LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_SOCKS CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -DWITH_SOCKS endif ifeq ($(WITH_UUID),yes) ifeq ($(UNAME),Linux) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_UUID BROKER_LIBS:=$(BROKER_LIBS) -luuid endif endif ifeq ($(WITH_BRIDGE),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_BRIDGE endif ifeq ($(WITH_PERSISTENCE),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_PERSISTENCE endif ifeq ($(WITH_MEMORY_TRACKING),yes) ifneq ($(UNAME),SunOS) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_MEMORY_TRACKING endif endif #ifeq ($(WITH_DB_UPGRADE),yes) # BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_DB_UPGRADE #endif ifeq ($(WITH_SYS_TREE),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_SYS_TREE endif ifeq ($(WITH_SRV),yes) LIB_CFLAGS:=$(LIB_CFLAGS) -DWITH_SRV LIB_LIBS:=$(LIB_LIBS) -lcares CLIENT_CFLAGS:=$(CLIENT_CFLAGS) -DWITH_SRV endif ifeq ($(WITH_WEBSOCKETS),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_WEBSOCKETS BROKER_LIBS:=$(BROKER_LIBS) -lwebsockets endif ifeq ($(UNAME),SunOS) BROKER_LIBS:=$(BROKER_LIBS) -lsocket -lnsl LIB_LIBS:=$(LIB_LIBS) -lsocket -lnsl endif ifeq ($(WITH_EC),yes) BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_EC endif ifeq ($(WITH_ADNS),yes) BROKER_LIBS:=$(BROKER_LIBS) -lanl BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_ADNS endif MAKE_ALL:=mosquitto ifeq ($(WITH_DOCS),yes) MAKE_ALL:=$(MAKE_ALL) docs endif INSTALL?=install prefix=/usr/local mandir=${prefix}/share/man localedir=${prefix}/share/locale STRIP?=strip mosquitto-1.4.15/readme-windows.txt0000664000175000017500000000406013245550210016351 0ustar rogerrogerMosquitto for Windows ===================== Mosquitto for Windows comes in two flavours, win32 or Cygwin. The win32 version is only supported on Windows Vista or later. In all cases, the dependencies are not provided in this installer and must be installed separately in the case that they are not already available. Capabilities ------------ Some versions of Windows have limitations on the number of concurrent connections. Non-server versions have been reported to be limited to approximately 1024 connections. Websockets ---------- The broker executables provided in the installers do not have Websockets support enabled. If you wish to have a version of the broker with Websockets support, you will need to compile libwebsockets version v1.7 onwards because no Windows binaries are provided. Please note that on Windows, libwebsockets limits connections to a maximum of 64 clients. Dependencies - win32 -------------------- * OpenSSL Link: http://slproweb.com/products/Win32OpenSSL.html Install "Win32 OpenSSL " Required DLLs: libeay32.dll ssleay32.dll * pthreads Link: ftp://sourceware.org/pub/pthreads-win32 Install "pthreads-w32--release.zip Required DLLs: pthreadVC2.dll Please ensure that the required DLLs are on the system path, or are in the same directory as the mosquitto executable. Dependencies - Cygwin --------------------- * OpenSSL Link: http://slproweb.com/products/Win32OpenSSL.html Install "Win32 OpenSSL " * pthreads Link: ftp://sourceware.org/pub/pthreads-win32 Install "pthreads-w32--release.zip * Cygwin Link: https://www.cygwin.com/setup-x86.exe Required packages: libgcc1, openssl, zlib0 Windows Service --------------- If all dependencies are installed prior to the installer being run, the broker can be installed as a Windows service. You can start/stop it from the control panel as well as running it as a normal executable. When running as a service, the configuration in mosquitto.conf in the installation directory is used so modify this to your needs. mosquitto-1.4.15/pskfile.example0000664000175000017500000000002713245550210015674 0ustar rogerrogerid:deadbeef easy:12345 mosquitto-1.4.15/pwfile.example0000664000175000017500000000054313245550210015530 0ustar rogerrogerroger:$6$clQ4Ocu312S0qWgl$Cv2wUxgEN73c6C6jlBkswqR4AkHsvDLWvtEXZZ8NpsBLgP1WAo/qA+WXcmEN/mjDNgdUwcxRAveqNMs2xUVQYA== sub_client:$6$U+qg0/32F0g2Fh+n$fBPSkq/rfNyEQ/TkEjRgwGTTVBpvNhKSyGShovH9KHewsvJ731tD5Zx26IHhR5RYCICt0L9qBW0/KK31UkCliw== pub_client:$6$vxQ89y+7WrsnL2yn$fSPMmEZn9TSrC8s/jaPmxJ9NijWpkP2e7bMJLz78JXR1vW2x8+T3FZ23byJA6xs5Mt+LeOybAHwcUv0OCl40rA== mosquitto-1.4.15/logo/0000775000175000017500000000000013245550210013623 5ustar rogerrogermosquitto-1.4.15/logo/mosquitto-logo-only.svg0000664000175000017500000001027313245550210020330 0ustar rogerroger image/svg+xmlmosquitto-1.4.15/logo/mosquitto-logo-min.svg0000664000175000017500000000712313245550210020132 0ustar rogerroger image/svg+xmlmosquitto-1.4.15/logo/mosquitto-text-side.svg0000664000175000017500000002330113245550210020313 0ustar rogerroger image/svg+xmlmosquitto-1.4.15/logo/legacy/0000775000175000017500000000000013245550210015067 5ustar rogerrogermosquitto-1.4.15/logo/legacy/mosquitto-14x14.png0000664000175000017500000000100113245550210020410 0ustar rogerrogerPNG  IHDR*sRGBbKGD pHYs0 tIME ~5IDAT(ϵP3&Yq Te` .ڴhY˅Ap )\6|۸{t8|p0I@cx<өmۂ xt7jYrD"t:P("TU?vBl6[B1) 7` X,h4H$dY$i0$Inw]7Ns Zipn1Mzhx9?X,nE4 j(0RTTmq4,J"I>PJzn6ۍRl ˡh:z hZ,c!p>)d]W'/ pEIENDB`mosquitto-1.4.15/logo/legacy/mosquitto-16x16.png0000664000175000017500000000106613245550210020427 0ustar rogerrogerPNG  IHDRh6sRGBbKGDPPPƇ pHYs tIME :4IDAT(ϵ?P}$J h!XJ,,l? XWYYhaao/` DD%hPT޻Dz,X:3)f J)7LUh0 !r 7ZVTt:e2vK)EwHRH$r<~n81>~*n{β,x^<,d2zXg1!Xy>vFNS>7M3je#$Ir(fl?>??UU\.$qgFZ%0 s8t]NSEAV+v8 jD"1LfۍFBn_MS0  uCQeB޲,,{4E)tz8l6PJ5M4 {IKcBIENDB`mosquitto-1.4.15/logo/legacy/mosquitto.svg0000664000175000017500000002112713245550210017657 0ustar rogerroger image/svg+xml mosquitto-1.4.15/logo/mosquitto-text-below.svg0000664000175000017500000002344013245550210020503 0ustar rogerroger image/svg+xmlmosquitto-1.4.15/logo/mosquitto.ico0000664000175000017500000010341413245550210016366 0ustar rogerroger hV   F00 % vBD(  $$wwwwR<R<R<R<ww w wR<R<R<R<R<R<]RR<RR|@@@(0` $$$wwwwwwwwww%w%wR<R<R<R<ww9w9wR<R<R<R<R<R<RR<R<-RR~>9y̳x<x<x<x<x<x<x<x<x<x<x<x<x<x<x<xߏDsVX}8[`"v(EJk0?_ @ i"zCpx홏!O lI`8ަȧ_ص|ǚ_`0Kfi/<Húl ,zL_\&feGDfg2GfڝRGF徺@ To/­x]+YH]_Eqb󁻁|3cXS.6[30uZR@3\E"ڳdKρqE8.>fIo EE(c*9w;p-ۓ̲o7 0GXdzFz8ʜoZS|IYPaǴ1b?Qa @TSb=لv*%qf@E<CUc0?1x8=;Ho@ pLɉm FkU$;#LL.1S0PF%ؖaiB'UF:NPD\7$+ ڰKbM<;b`Y`񶳱>68YNiFDU-s*?.Kbq=w p>0,y,JKz U1AiNRc瀔mSjFl Kt_)y [wP(ۼ+YXOu$&Z1:Mo\^{rjn)Ş҃E10C14gXHOFz ֫Zj'~4lU^Q*V6n شPLt?/7 +7-H$Ĥ+}#,m'&^`s&~xkYi^q1*&71+^IU9! o2 lzl'4v_&&or3Hp6%=lSyv8H{c\`&;t'vn:lj7!pMSŹaQs`;"$$jnJ[9Hbga?LqrNv2UV[ȿ)+#]J[q\!׾ XRڐoHOlrC!pRXuZ; (e6ޥz[Gpec}F|Iˀ+c! 0N6֙'L6=Mp{EU͔mhbo%4X/Hy([FzתHH{.O飯HNI]^c" c(+yiz 18>ս~/6FJ^nkQ3`S:\7|OR0'F?{ JHg 0jݖ=Q >G`?0߭6 [sEʑF [>Y.X፪l&܂etv̆o חlR^Q K]~kfc#n_[}olXmWƘ]Is3AJ5\JR%goƞXC=4?JH^2 (s|+sϫ+&? ;vEU Ns}eW}Q|y}P7#GzlgݣuRCU.y 섑%Jipe*;$ivՑFk(p4,O-x_x*YPF%] 9p_\Մؐj1d摮^HOb=/M0`@:gcu1K]KQˀG~ aȻ <(<lw s-9:XF:ʀRHŽunҴS7FTraamy%:4 (`ж]]l\coɁ9J:dO!ݾ}CN!]VHC |#p#*y;=9_9*9ae۽ѮJu@>@zc_@BYQ^l8֗p#i1~6W`"_#%,Us}?(@zsq6ظ\wDUv=#t0z p@cOv̳p %tKɝ ؽf+& ;5Ie_Fvd[L@TIb]U8Ё^&FSF&ʧd Izۭټ@:՞f&uR]6@CJ.96@̣dU_J";T6ge,:$֏S"`꿢 ϒ6\\xG&y[Pl~İVXqXM>Q4a%(3 7~d'd`وR숼wgHҋ<|[4*!u)IدwGV 4UIH#_Ǝ Ulg||=6OªJY%R4$Ovt1kf'/ahu{z"pu8M@)vL8dǠ49a.z>fd n\1p~RP"\WY;(4%|8B5=͓fAl7 q>R4p`(o8򦢻WFSJ XX '-HņȷJBGnxw%n_ް&Su*n0'I_>'{] \YqZ%%uvlHP:U"D;WH>s^@ףPvCyO%v<\RjglơtqpNO Gk{+U`P}ă_V*[-'і,ǎKzdKfg Z7ci]R+$Z _ly{ S1cMq)ŖKw~I6j4IZ=xϏuҸZ';qzlRD&anX/Kb>¼322aۑol`cR\C*Lkъd2.@],#Ii#Z':iwa*cy; }q2-jg (`w@f1r-sp$i?"T:@n;f(5{,/6J;.h4`줿k\~z_auҸCZ'K!W 8 8|Bk˸#ƽ9i=:<"6yd]d#McL׶vL6/y 侎cc`W8Z75:+N7řj V:i'`sl4N(SuS\ &Z4J*,d*PS\CdC:eB%r#M2O7W;J=+yo2ਘc95$< <,8nk ƚ29Y"Ol2!I EXkA;-%L*k`J\W9 eN7n(p66ݸ/ fz8gpo9wÜy$Ӷ7LH[6ѭ@ d@Yq'^F4AGL[$1tsq ;<#/ 5mc3)Egl8{ wxY>S܏4 0vZ$IP[\ll\(~'O £XC{U2"z4s[s3ܝWFw9+|{0u"I=w_-~1X)n ˑg 4MVq_5y{8YW:sJ\-ָr8ů[ݲ gIAqN$l/VR+@1#7`*X/ O3"5JC#w{.rMvwc]PXmY  O6 y|c{X'| 007ȕm y}ɒlȝTZq6G0AZ.fc&6W/7If@͢ƹUzw(+z-(j!R0 WkA.6"@>jb"Y 0F^%c&:)!xPA2A@6^STm;Jc *POYeXHs1$싕zf#811pH#@2}ƍq/2J|u W=.| )AKqK39Kńz3gy.QAV>WjG!ˑ県@f#7@4UD%8!kټrZYkK$Y>Pc^pdLc$ >Tf9r#*"2V RNY}3jpIlϛkș͵Rrdًo'u %5B>[fyy!5Hbd &8;XMWU{1oc:9`rix 6jgָk3,1}xSeq/U5Y<7c(m^x&@1^ sv%NƍR@- KYg+m*ap׃XlɰC~qL)rj[1ʙ2䫎8S3Q (u\ml`KqA`ƸۿxLhw:z;yHy a:+kCpߗcYŒAnC vlJu')YDgz/HC$`#eܗ;Muf/.o>F"QS4.|dFOjPlNjkde3: I vMGQm>'dk*o"[&iL]}]%p7a@# T,]}=(SC}M1"7N&W`&;LɅGqK(9IȗX#KLqܟq977͍.ovR疏}?Y#+]+;6G^( LƑȭ{rҴ2oFؽ*ʸW1Yg[֛:͠~|yx 3z;XPdٟԖ2E䓏oB_FU$ `t/qRHt]d]qFYѻ]oι ±3zG],E6f/f lcQ sPJ}sR 7"3K; $(վX}Xu/2ؽ..<}v[{9~c3S<kt))yNzwsx蝿z.ȻO@>B}Z >|>C (5~%_;l %fviEW9QMH^N$WJiWN=39KGO p;GOߖfPik !/c1nє QVaJyn0>_bNx?)hiW,FVEv-!7vU*pK`I3K;m. #] Ϳ _ (;͕ۖMvzwy똞 1Rlfs9gC;l1Cw@"S8g!=~6ȝTcz y{S O9qeӴw#'R0?.<'G-R(d91)t. ;((Q#zn<, r5X٤'d ZU[I Yԣ 8̱UQ`j]/C"N1Zpwq9X;-)6"MAIOYq%՝j-3rACY'YYn)j!+'cF 1 ~t0M)׃*#= m$ KA9}{#.T8;1Y;u1 g1Ґ?z݆K{ LunY \|sFe]bt Vs^i_ë2u&R;$[0쵥aǧOyDogg`ܪ>氤]i@>'5YwcT R0#`p+Z@/$a7k=UAs.'"+kx T ۂMqFJGJul8<p ˁ'ё|kՌ,(,ޑQ%tf(m0'^!4u @X #}bYN"}[q8,ŵ g!nlˡ`^yH_,# ˙`v a#Jr`=PO i20:/B Kx\FU&N@BeF@ -Γ@6QiS-ǓU)!h2`;RW8 Ic_s~rhBTEZOM#/90ȝNF: &U)6;h #=6tur4XD!ڪZ= F MMc{ w.v ? \Us>Ia/aW؁,u~Reח^Rp>rAC~Ť9kN=75cݙ Wamv}qځHD*/ hԦȫN$5yVTYg j6mXMG g0_s}QF L&]nw_dex9~؁.՟V"뱺,s< Zx k؜9夛*I(Ty'aU ę6,']y56řXya;}}ɛh_n l@DƯ>uVϯF`L] S {džN9!Gh{WE+QFNށ Fcӎ%?`FɕAXލZۊnU魍e?uG<,c;$X;g;y3e$q6@+V@%GŞO04sIb0 FXe-s@@;p$Ϩ$X(%6PZ0 Ht=.KסtVQ[wf47{pBNQ{b<𿅱FrM-^Ȋ*ke!)5+Zdb v"JÁm$[3/4.UAQSTEGZO-EFqq"$X߀;k$0jz_8ե7 M)pd-E1Ͻ 0ҵFruSrkL^$  x,Kz^*\l+9S{ˀ _eTI;غuiȲ' aTpMS IXO5ePLo> :e>8_hϑ-,|T79׾$~+5qOPJ@ےka ]5cI~_I~yz˗[Ӑ+<&Fu%i4Μ3 ukIn~K/7IJϳa * bWc9>y77ֻX̖򷒲UW9)2+]\0Nk3b1owgmk`>%Xuc} bVJ9c.cwt5M W) k֤W3I]NS&"MPI-9V?AR(b_Nt3ti  .CX)Zmj @A^Vu<*UM9,.EqAR֮j-kMB a4zR_gV_XY }r((+m(TL]Oq]QS:%_XSEr֎#&3 ^VGgb}Ғ7s{c)TӱdG>#it`"k%zycS۸4fO_C(hVq7aE_|"Ww$ʭk)Lgrl^*-$}4*\9|.ƭ{o"]QPV&ҩ$mVbǠH̐!lba yJvQ0+Ppށ=0ʷZ*1ye\vKyެ̺c:Hb8.pSc} +o#=.mC͊0!=8;*#89zͨ5W.V ΐEvnn% L-U)_VJ>^2=/o3ZYDvFWQ@`\Bi:X[ BxaMv6XZ:}Igc3YFʛź/O7* ZT gaǸ s(Ö agz"ߛ}ŜUl:#6Fzl{)OcRϯ. Lv].<+h*`')O:pER_\ib( xt(;4y<+3?P~߿$zu)OU HaN:bXӵkzٷF+0'bE>F@_=Yt+? )FYS;/sӓ}A O/&qORHb^?maŊžOWQ6(awF6OyŅZ> 1[16^ Z(&eW0TqSTYfCy8)}y%t@E$Xq4z x}FX\LH!Gu,, 7?A!_$~ Wo?MS,^: @{@{JںkOO Jt#+nDmp+Ke/X50/~zZ;W2;OIbm[[a5-ہﻨ__ h}[w^ ]Ua|tce8fu{vߙ~318K+$)BgMн"%|!PX* ß #include /usr/sbin/mosquitto r, /etc/mosquitto/mosquitto.conf r, /etc/mosquitto/ca_certificates/* r, /etc/mosquitto/certs/* r, /etc/mosquitto/conf.d/* r, /var/lib/mosquitto/ r, /var/lib/mosquitto/mosquitto.db rwk, /var/run/mosquitto.pid rw, network inet stream, network inet6 stream, network inet dgram, network inet6 dgram, # For drop privileges capability setgid, capability setuid, # For tcp-wrappers /lib{,32,64}/libwrap.so* rm, /etc/hosts.allow r, /etc/hosts.deny r, } mosquitto-1.4.15/epl-v100000664000175000017500000002665713245550210014012 0ustar rogerrogerEclipse Public License - v 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. mosquitto-1.4.15/CMakeLists.txt0000664000175000017500000000527113245550210015430 0ustar rogerroger# This is a cmake script. Process it with the CMake gui or command line utility # to produce makefiles / Visual Studio project files on Mac OS X and Windows. # # To configure the build options either use the CMake gui, or run the command # line utility including the "-i" option. set(CMAKE_LEGACY_CYGWIN_WIN32 0) project(mosquitto) cmake_minimum_required(VERSION 2.8) # Only for version 3 and up. cmake_policy(SET CMP0042 NEW) set (VERSION 1.4.15) if (WIN32) execute_process(COMMAND cmd /c echo %DATE% %TIME% OUTPUT_VARIABLE TIMESTAMP OUTPUT_STRIP_TRAILING_WHITESPACE) else (WIN32) execute_process(COMMAND date "+%F %T%z" OUTPUT_VARIABLE TIMESTAMP OUTPUT_STRIP_TRAILING_WHITESPACE) endif (WIN32) add_definitions (-DCMAKE -DVERSION=\"${VERSION}\" -DTIMESTAMP=\"${TIMESTAMP}\") if (WIN32) set (BINDIR .) set (SBINDIR .) set (SYSCONFDIR .) set (LIBDIR .) set (INCLUDEDIR include) set (DATAROOTDIR share) set (MANDIR man) set (SHAREDEST .) add_definitions("-D_CRT_SECURE_NO_WARNINGS") add_definitions("-D_CRT_NONSTDC_NO_DEPRECATE") else (WIN32) set (BINDIR bin) set (SBINDIR sbin) if ("${CMAKE_INSTALL_PREFIX}" STREQUAL /usr) set (SYSCONFDIR /etc/mosquitto) else ("${CMAKE_INSTALL_PREFIX}" STREQUAL /usr) set (SYSCONFDIR etc/mosquitto) endif ("${CMAKE_INSTALL_PREFIX}" STREQUAL /usr) set (LIBDIR lib${LIB_SUFFIX}) set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBDIR}") set (INCLUDEDIR include) set (DATAROOTDIR share) set (MANDIR "${DATAROOTDIR}/man") set (SHAREDIR "${DATAROOTDIR}/mosquitto") endif (WIN32) option(WITH_TLS "Include SSL/TLS support?" ON) option(WITH_TLS_PSK "Include TLS-PSK support (requires WITH_TLS)?" ON) option(WITH_EC "Include Elliptic Curve support (requires WITH_TLS)?" ON) if (${WITH_TLS} STREQUAL ON) find_package(OpenSSL REQUIRED) add_definitions("-DWITH_TLS") if (${WITH_TLS_PSK} STREQUAL ON) add_definitions("-DWITH_TLS_PSK") endif (${WITH_TLS_PSK} STREQUAL ON) if (${WITH_EC} STREQUAL ON) add_definitions("-DWITH_EC") endif (${WITH_EC} STREQUAL ON) else (${WITH_TLS} STREQUAL ON) set (OPENSSL_INCLUDE_DIR "") endif (${WITH_TLS} STREQUAL ON) option(WITH_SOCKS "Include SOCKS5 support?" ON) if (${WITH_SOCKS} STREQUAL ON) add_definitions("-DWITH_SOCKS") endif (${WITH_SOCKS} STREQUAL ON) option(WITH_SRV "Include SRV lookup support?" ON) # ======================================== # Include projects # ======================================== add_subdirectory(lib) add_subdirectory(client) add_subdirectory(src) add_subdirectory(man) # ======================================== # Install config file # ======================================== install(FILES mosquitto.conf aclfile.example pskfile.example pwfile.example DESTINATION "${SYSCONFDIR}") mosquitto-1.4.15/installer/0000775000175000017500000000000013245550210014660 5ustar rogerrogermosquitto-1.4.15/installer/mosquitto-cygwin.nsi0000664000175000017500000001221713245550210020740 0ustar rogerroger; NSIS installer script for mosquitto !include "MUI.nsh" ; For environment variable code !include "WinMessages.nsh" !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "mosquitto" !define VERSION 1.4.15 OutFile "mosquitto-${VERSION}-install-cygwin.exe" InstallDir "$PROGRAMFILES\mosquitto" ;-------------------------------- ; Installer pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !define MUI_FINISHPAGE_TEXT "mosquitto has been installed on your computer.\n\nTo complete the installation you must install the dependencies described in the following readme.\n\nClick Finish to close this wizard." !define MUI_FINISHPAGE_SHOWREADME $INSTDIR\readme-dependencies-cygwin.txt !define MUI_FINISHPAGE_SHOWREADME_TEXT "Show dependencies readme" !insertmacro MUI_PAGE_FINISH ;-------------------------------- ; Uninstaller pages !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH ;-------------------------------- ; Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ; Installer sections Section "Files" SecInstall SectionIn RO SetOutPath "$INSTDIR" ;File "c:\cygwin\bin\cygwin1.dll" ;File "c:\cygwin\bin\cyggcc_s-1.dll" ;File "c:\cygwin\bin\cygcrypto-1.0.0.dll" ;File "c:\cygwin\bin\cygssl-1.0.0.dll" ;File "c:\cygwin\bin\cygz.dll" File "..\src\mosquitto.exe" File "..\build\src\Release\mosquitto_passwd.exe" File "..\build\client\Release\mosquitto_pub.exe" File "..\build\client\Release\mosquitto_sub.exe" File "..\build\lib\Release\mosquitto.dll" File "..\build\lib\cpp\Release\mosquittopp.dll" File "..\aclfile.example" File "..\ChangeLog.txt" File "..\mosquitto.conf" File "..\pwfile.example" File "..\readme.md" File "..\readme-windows.txt" ;File "C:\pthreads\Pre-built.2\dll\x86\pthreadVC2.dll" ;File "C:\OpenSSL-Win32\libeay32.dll" ;File "C:\OpenSSL-Win32\ssleay32.dll" File "..\edl-v10" File "..\epl-v10" SetOutPath "$INSTDIR\devel" File "..\lib\mosquitto.h" File "..\build\lib\Release\mosquitto.lib" File "..\lib\cpp\mosquittopp.h" File "..\build\lib\cpp\Release\mosquittopp.lib" File "..\src\mosquitto_plugin.h" WriteUninstaller "$INSTDIR\Uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "DisplayName" "Mosquitto MQTT broker" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "HelpLink" "http://mosquitto.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "URLInfoAbout" "http://mosquitto.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "DisplayVersion" "${VERSION}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "NoModify" "1" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" "NoRepair" "1" WriteRegExpandStr ${env_hklm} MOSQUITTO_DIR $INSTDIR SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SectionEnd Section "Service" SecService ExecWait '"$INSTDIR\mosquitto.exe" install' SectionEnd Section "Uninstall" ExecWait '"$INSTDIR\mosquitto.exe" uninstall' ;Delete "$INSTDIR\cygwin1.dll" ;Delete "$INSTDIR\cyggcc_s-1.dll" ;Delete "$INSTDIR\cygcrypto-1.0.0.dll" ;Delete "$INSTDIR\cygssl-1.0.0.dll" ;Delete "$INSTDIR\cygz.dll" Delete "$INSTDIR\mosquitto.exe" Delete "$INSTDIR\mosquitto_passwd.exe" Delete "$INSTDIR\mosquitto_pub.exe" Delete "$INSTDIR\mosquitto_sub.exe" Delete "$INSTDIR\mosquitto.dll" Delete "$INSTDIR\mosquittopp.dll" Delete "$INSTDIR\aclfile.example" Delete "$INSTDIR\ChangeLog.txt" Delete "$INSTDIR\mosquitto.conf" Delete "$INSTDIR\pwfile.example" Delete "$INSTDIR\readme.txt" Delete "$INSTDIR\readme-windows.txt" ;Delete "$INSTDIR\pthreadVC2.dll" ;Delete "$INSTDIR\libeay32.dll" ;Delete "$INSTDIR\ssleay32.dll" Delete "$INSTDIR\edl-v10" Delete "$INSTDIR\epl-v10" Delete "$INSTDIR\devel\mosquitto.h" Delete "$INSTDIR\devel\mosquitto.lib" Delete "$INSTDIR\devel\mosquittopp.h" Delete "$INSTDIR\devel\mosquittopp.lib" Delete "$INSTDIR\devel\mosquitto_plugin.h" Delete "$INSTDIR\Uninstall.exe" RMDir "$INSTDIR" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MosquittoCygwin" DeleteRegValue ${env_hklm} MOSQUITTO_DIR SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SectionEnd LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." LangString DESC_SecService ${LANG_ENGLISH} "Install mosquitto as a Windows service (needs all dependencies installed)?" !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) !insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService) !insertmacro MUI_FUNCTION_DESCRIPTION_END mosquitto-1.4.15/installer/mosquitto.nsi0000664000175000017500000001273113245550210017443 0ustar rogerroger; NSIS installer script for mosquitto !include "MUI2.nsh" !include "nsDialogs.nsh" !include "LogicLib.nsh" ; For environment variable code !include "WinMessages.nsh" !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "mosquitto" !define VERSION 1.4.15 OutFile "mosquitto-${VERSION}-install-win32.exe" InstallDir "$PROGRAMFILES\mosquitto" ;-------------------------------- ; Installer pages !insertmacro MUI_PAGE_WELCOME Page custom DependencyPage !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH ;-------------------------------- ; Uninstaller pages !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH ;-------------------------------- ; Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ; Installer sections Section "Files" SecInstall SectionIn RO SetOutPath "$INSTDIR" File "..\build\src\Release\mosquitto.exe" File "..\build\src\Release\mosquitto_passwd.exe" File "..\build\client\Release\mosquitto_pub.exe" File "..\build\client\Release\mosquitto_sub.exe" File "..\build\lib\Release\mosquitto.dll" File "..\build\lib\cpp\Release\mosquittopp.dll" File "..\aclfile.example" File "..\ChangeLog.txt" File "..\mosquitto.conf" File "..\pwfile.example" File "..\readme.md" File "..\readme-windows.txt" ;File "C:\pthreads\Pre-built.2\dll\x86\pthreadVC2.dll" ;File "C:\OpenSSL-Win32\libeay32.dll" ;File "C:\OpenSSL-Win32\ssleay32.dll" File "..\edl-v10" File "..\epl-v10" SetOutPath "$INSTDIR\devel" File "..\lib\mosquitto.h" File "..\build\lib\Release\mosquitto.lib" File "..\lib\cpp\mosquittopp.h" File "..\build\lib\cpp\Release\mosquittopp.lib" File "..\src\mosquitto_plugin.h" WriteUninstaller "$INSTDIR\Uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "DisplayName" "Mosquitto MQTT broker" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "HelpLink" "http://mosquitto.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "URLInfoAbout" "http://mosquitto.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "DisplayVersion" "${VERSION}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "NoModify" "1" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" "NoRepair" "1" WriteRegExpandStr ${env_hklm} MOSQUITTO_DIR $INSTDIR SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SectionEnd Section "Service" SecService ExecWait '"$INSTDIR\mosquitto.exe" install' SectionEnd Section "Uninstall" ExecWait '"$INSTDIR\mosquitto.exe" uninstall' Delete "$INSTDIR\mosquitto.exe" Delete "$INSTDIR\mosquitto_passwd.exe" Delete "$INSTDIR\mosquitto_pub.exe" Delete "$INSTDIR\mosquitto_sub.exe" Delete "$INSTDIR\mosquitto.dll" Delete "$INSTDIR\mosquittopp.dll" Delete "$INSTDIR\aclfile.example" Delete "$INSTDIR\ChangeLog.txt" Delete "$INSTDIR\mosquitto.conf" Delete "$INSTDIR\pwfile.example" Delete "$INSTDIR\readme.txt" Delete "$INSTDIR\readme-windows.txt" ;Delete "$INSTDIR\pthreadVC2.dll" ;Delete "$INSTDIR\libeay32.dll" ;Delete "$INSTDIR\ssleay32.dll" Delete "$INSTDIR\edl-v10" Delete "$INSTDIR\epl-v10" Delete "$INSTDIR\devel\mosquitto.h" Delete "$INSTDIR\devel\mosquitto.lib" Delete "$INSTDIR\devel\mosquittopp.h" Delete "$INSTDIR\devel\mosquittopp.lib" Delete "$INSTDIR\devel\mosquitto_plugin.h" Delete "$INSTDIR\Uninstall.exe" RMDir "$INSTDIR" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Mosquitto" DeleteRegValue ${env_hklm} MOSQUITTO_DIR SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 SectionEnd LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." LangString DESC_SecService ${LANG_ENGLISH} "Install mosquitto as a Windows service?" !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) !insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService) !insertmacro MUI_FUNCTION_DESCRIPTION_END Var Dialog Var OSSLLink Var PTHLink Function DependencyPage nsDialogs::Create 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 12u "OpenSSL - install 'Win32 OpenSSL vXXXXX Light' then copy dlls to the mosquitto directory" ${NSD_CreateLink} 13u 13u 100% 12u "http://slproweb.com/products/Win32OpenSSL.html" Pop $OSSLLink ${NSD_OnClick} $OSSLLink OnClick_OSSL ${NSD_CreateLabel} 0 26u 100% 12u "pthreads - copy 'pthreadVC2.dll' to the mosquitto directory" ${NSD_CreateLink} 13u 39u 100% 12u "ftp://sources.redhat.com/pub/pthreads-win32/dll-latest/dll/x86/" Pop $PTHLink ${NSD_OnClick} $PTHLink OnClick_PTH !insertmacro MUI_HEADER_TEXT_PAGE "Dependencies" "This page lists packages that must be installed if not already present" nsDialogs::Show FunctionEnd Function OnClick_OSSL Pop $0 ExecShell "open" "http://slproweb.com/products/Win32OpenSSL.html" FunctionEnd Function OnClick_PTH Pop $0 ExecShell "open" "ftp://sources.redhat.com/pub/pthreads-win32/dll-latest/dll/x86/" FunctionEnd mosquitto-1.4.15/LICENSE.txt0000664000175000017500000000023313245550210014504 0ustar rogerrogerThis project is dual licensed under the Eclipse Public License 1.0 and the Eclipse Distribution License 1.0 as described in the epl-v10 and edl-v10 files. mosquitto-1.4.15/src/0000775000175000017500000000000013245550210013452 5ustar rogerrogermosquitto-1.4.15/src/security_default.c0000664000175000017500000005243313245550210017200 0ustar rogerroger/* Copyright (c) 2011-2018 Roger Light 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 #include #include #include #include #include "util_mosq.h" static int _aclfile_parse(struct mosquitto_db *db); static int _unpwd_file_parse(struct mosquitto_db *db); static int _acl_cleanup(struct mosquitto_db *db, bool reload); static int _unpwd_cleanup(struct _mosquitto_unpwd **unpwd, bool reload); static int _psk_file_parse(struct mosquitto_db *db); #ifdef WITH_TLS static int _pw_digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len); static int _base64_decode(char *in, unsigned char **decoded, unsigned int *decoded_len); #endif static int mosquitto__memcmp_const(const void *ptr1, const void *b, size_t len); int mosquitto_security_init_default(struct mosquitto_db *db, bool reload) { int rc; /* Load username/password data if required. */ if(db->config->password_file){ rc = _unpwd_file_parse(db); if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error opening password file \"%s\".", db->config->password_file); return rc; } } /* Load acl data if required. */ if(db->config->acl_file){ rc = _aclfile_parse(db); if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error opening acl file \"%s\".", db->config->acl_file); return rc; } } /* Load psk data if required. */ if(db->config->psk_file){ rc = _psk_file_parse(db); if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error opening psk file \"%s\".", db->config->psk_file); return rc; } } return MOSQ_ERR_SUCCESS; } int mosquitto_security_cleanup_default(struct mosquitto_db *db, bool reload) { int rc; rc = _acl_cleanup(db, reload); if(rc != MOSQ_ERR_SUCCESS) return rc; rc = _unpwd_cleanup(&db->unpwd, reload); if(rc != MOSQ_ERR_SUCCESS) return rc; return _unpwd_cleanup(&db->psk_id, reload); } int _add_acl(struct mosquitto_db *db, const char *user, const char *topic, int access) { struct _mosquitto_acl_user *acl_user=NULL, *user_tail; struct _mosquitto_acl *acl, *acl_tail; char *local_topic; bool new_user = false; if(!db || !topic) return MOSQ_ERR_INVAL; local_topic = _mosquitto_strdup(topic); if(!local_topic){ return MOSQ_ERR_NOMEM; } if(db->acl_list){ user_tail = db->acl_list; while(user_tail){ if(user == NULL){ if(user_tail->username == NULL){ acl_user = user_tail; break; } }else if(user_tail->username && !strcmp(user_tail->username, user)){ acl_user = user_tail; break; } user_tail = user_tail->next; } } if(!acl_user){ acl_user = _mosquitto_malloc(sizeof(struct _mosquitto_acl_user)); if(!acl_user){ _mosquitto_free(local_topic); return MOSQ_ERR_NOMEM; } new_user = true; if(user){ acl_user->username = _mosquitto_strdup(user); if(!acl_user->username){ _mosquitto_free(local_topic); _mosquitto_free(acl_user); return MOSQ_ERR_NOMEM; } }else{ acl_user->username = NULL; } acl_user->next = NULL; acl_user->acl = NULL; } acl = _mosquitto_malloc(sizeof(struct _mosquitto_acl)); if(!acl){ _mosquitto_free(local_topic); return MOSQ_ERR_NOMEM; } acl->access = access; acl->topic = local_topic; acl->next = NULL; acl->ccount = 0; acl->ucount = 0; /* Add acl to user acl list */ if(acl_user->acl){ acl_tail = acl_user->acl; while(acl_tail->next){ acl_tail = acl_tail->next; } acl_tail->next = acl; }else{ acl_user->acl = acl; } if(new_user){ /* Add to end of list */ if(db->acl_list){ user_tail = db->acl_list; while(user_tail->next){ user_tail = user_tail->next; } user_tail->next = acl_user; }else{ db->acl_list = acl_user; } } return MOSQ_ERR_SUCCESS; } int _add_acl_pattern(struct mosquitto_db *db, const char *topic, int access) { struct _mosquitto_acl *acl, *acl_tail; char *local_topic; char *s; if(!db || !topic) return MOSQ_ERR_INVAL; local_topic = _mosquitto_strdup(topic); if(!local_topic){ return MOSQ_ERR_NOMEM; } acl = _mosquitto_malloc(sizeof(struct _mosquitto_acl)); if(!acl){ _mosquitto_free(local_topic); return MOSQ_ERR_NOMEM; } acl->access = access; acl->topic = local_topic; acl->next = NULL; acl->ccount = 0; s = local_topic; while(s){ s = strstr(s, "%c"); if(s){ acl->ccount++; s+=2; } } acl->ucount = 0; s = local_topic; while(s){ s = strstr(s, "%u"); if(s){ acl->ucount++; s+=2; } } if(db->acl_patterns){ acl_tail = db->acl_patterns; while(acl_tail->next){ acl_tail = acl_tail->next; } acl_tail->next = acl; }else{ db->acl_patterns = acl; } return MOSQ_ERR_SUCCESS; } int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access) { char *local_acl; struct _mosquitto_acl *acl_root; bool result; int i; int len, tlen, clen, ulen; char *s; if(!db || !context || !topic) return MOSQ_ERR_INVAL; if(!db->acl_list && !db->acl_patterns) return MOSQ_ERR_SUCCESS; if(context->bridge) return MOSQ_ERR_SUCCESS; if(!context->acl_list && !db->acl_patterns) return MOSQ_ERR_ACL_DENIED; if(context->acl_list){ acl_root = context->acl_list->acl; }else{ acl_root = NULL; } /* Loop through all ACLs for this client. */ while(acl_root){ /* Loop through the topic looking for matches to this ACL. */ /* If subscription starts with $, acl_root->topic must also start with $. */ if(topic[0] == '$' && acl_root->topic[0] != '$'){ acl_root = acl_root->next; continue; } mosquitto_topic_matches_sub(acl_root->topic, topic, &result); if(result){ if(access & acl_root->access){ /* And access is allowed. */ return MOSQ_ERR_SUCCESS; } } acl_root = acl_root->next; } acl_root = db->acl_patterns; if(acl_root){ /* We are using pattern based acls. Check whether the username or * client id contains a + or # and if so deny access. * * Without this, a malicious client may configure its username/client * id to bypass ACL checks (or have a username/client id that cannot * publish or receive messages to its own place in the hierarchy). */ if(context->username && strpbrk(context->username, "+#")){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", context->username); return MOSQ_ERR_ACL_DENIED; } if(context->id && strpbrk(context->id, "+#")){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", context->id); return MOSQ_ERR_ACL_DENIED; } } /* Loop through all pattern ACLs. */ clen = strlen(context->id); while(acl_root){ tlen = strlen(acl_root->topic); if(acl_root->ucount && !context->username){ acl_root = acl_root->next; continue; } if(context->username){ ulen = strlen(context->username); len = tlen + acl_root->ccount*(clen-2) + acl_root->ucount*(ulen-2); }else{ ulen = 0; len = tlen + acl_root->ccount*(clen-2); } local_acl = _mosquitto_malloc(len+1); if(!local_acl) return 1; // FIXME s = local_acl; for(i=0; itopic[i] == '%'){ if(acl_root->topic[i+1] == 'c'){ i++; strncpy(s, context->id, clen); s+=clen; continue; }else if(context->username && acl_root->topic[i+1] == 'u'){ i++; strncpy(s, context->username, ulen); s+=ulen; continue; } } s[0] = acl_root->topic[i]; s++; } local_acl[len] = '\0'; mosquitto_topic_matches_sub(local_acl, topic, &result); _mosquitto_free(local_acl); if(result){ if(access & acl_root->access){ /* And access is allowed. */ return MOSQ_ERR_SUCCESS; } } acl_root = acl_root->next; } return MOSQ_ERR_ACL_DENIED; } static int _aclfile_parse(struct mosquitto_db *db) { FILE *aclfile; char buf[1024]; char *token; char *user = NULL; char *topic; char *access_s; int access; int rc; int slen; int topic_pattern; char *saveptr = NULL; if(!db || !db->config) return MOSQ_ERR_INVAL; if(!db->config->acl_file) return MOSQ_ERR_SUCCESS; aclfile = _mosquitto_fopen(db->config->acl_file, "rt", false); if(!aclfile){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open acl_file \"%s\".", db->config->acl_file); return 1; } // topic [read|write] // user while(fgets(buf, 1024, aclfile)){ slen = strlen(buf); while(slen > 0 && (buf[slen-1] == 10 || buf[slen-1] == 13)){ buf[slen-1] = '\0'; slen = strlen(buf); } if(buf[0] == '#'){ continue; } token = strtok_r(buf, " ", &saveptr); if(token){ if(!strcmp(token, "topic") || !strcmp(token, "pattern")){ if(!strcmp(token, "topic")){ topic_pattern = 0; }else{ topic_pattern = 1; } access_s = strtok_r(NULL, " ", &saveptr); if(!access_s){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty topic in acl_file."); if(user) _mosquitto_free(user); fclose(aclfile); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, "", &saveptr); if(token){ topic = token; /* Ignore duplicate spaces */ while(topic[0] == ' '){ topic++; } }else{ topic = access_s; access_s = NULL; } if(access_s){ if(!strcmp(access_s, "read")){ access = MOSQ_ACL_READ; }else if(!strcmp(access_s, "write")){ access = MOSQ_ACL_WRITE; }else if(!strcmp(access_s, "readwrite")){ access = MOSQ_ACL_READ | MOSQ_ACL_WRITE; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid topic access type \"%s\" in acl_file.", access_s); if(user) _mosquitto_free(user); fclose(aclfile); return MOSQ_ERR_INVAL; } }else{ access = MOSQ_ACL_READ | MOSQ_ACL_WRITE; } if(topic_pattern == 0){ rc = _add_acl(db, user, topic, access); }else{ rc = _add_acl_pattern(db, topic, access); } if(rc){ if(user) _mosquitto_free(user); fclose(aclfile); return rc; } }else if(!strcmp(token, "user")){ token = strtok_r(NULL, "", &saveptr); if(token){ /* Ignore duplicate spaces */ while(token[0] == ' '){ token++; } if(user) _mosquitto_free(user); user = _mosquitto_strdup(token); if(!user){ fclose(aclfile); return MOSQ_ERR_NOMEM; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Missing username in acl_file."); if(user) _mosquitto_free(user); fclose(aclfile); return 1; } } } } if(user) _mosquitto_free(user); fclose(aclfile); return MOSQ_ERR_SUCCESS; } static void _free_acl(struct _mosquitto_acl *acl) { if(!acl) return; if(acl->next){ _free_acl(acl->next); } if(acl->topic){ _mosquitto_free(acl->topic); } _mosquitto_free(acl); } static int _acl_cleanup(struct mosquitto_db *db, bool reload) { struct mosquitto *context, *ctxt_tmp; struct _mosquitto_acl_user *user_tail; if(!db) return MOSQ_ERR_INVAL; if(!db->acl_list) return MOSQ_ERR_SUCCESS; /* As we're freeing ACLs, we must clear context->acl_list to ensure no * invalid memory accesses take place later. * This *requires* the ACLs to be reapplied after _acl_cleanup() * is called if we are reloading the config. If this is not done, all * access will be denied to currently connected clients. */ HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ context->acl_list = NULL; } while(db->acl_list){ user_tail = db->acl_list->next; _free_acl(db->acl_list->acl); if(db->acl_list->username){ _mosquitto_free(db->acl_list->username); } _mosquitto_free(db->acl_list); db->acl_list = user_tail; } if(db->acl_patterns){ _free_acl(db->acl_patterns); db->acl_patterns = NULL; } return MOSQ_ERR_SUCCESS; } static int _pwfile_parse(const char *file, struct _mosquitto_unpwd **root) { FILE *pwfile; struct _mosquitto_unpwd *unpwd; char buf[256]; char *username, *password; int len; char *saveptr = NULL; pwfile = _mosquitto_fopen(file, "rt", false); if(!pwfile){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open pwfile \"%s\".", file); return 1; } while(!feof(pwfile)){ if(fgets(buf, 256, pwfile)){ username = strtok_r(buf, ":", &saveptr); if(username){ unpwd = _mosquitto_calloc(1, sizeof(struct _mosquitto_unpwd)); if(!unpwd){ fclose(pwfile); return MOSQ_ERR_NOMEM; } unpwd->username = _mosquitto_strdup(username); if(!unpwd->username){ _mosquitto_free(unpwd); fclose(pwfile); return MOSQ_ERR_NOMEM; } len = strlen(unpwd->username); while(unpwd->username[len-1] == 10 || unpwd->username[len-1] == 13){ unpwd->username[len-1] = '\0'; len = strlen(unpwd->username); } password = strtok_r(NULL, ":", &saveptr); if(password){ unpwd->password = _mosquitto_strdup(password); if(!unpwd->password){ fclose(pwfile); _mosquitto_free(unpwd->username); _mosquitto_free(unpwd); return MOSQ_ERR_NOMEM; } len = strlen(unpwd->password); while(len && (unpwd->password[len-1] == 10 || unpwd->password[len-1] == 13)){ unpwd->password[len-1] = '\0'; len = strlen(unpwd->password); } } HASH_ADD_KEYPTR(hh, *root, unpwd->username, strlen(unpwd->username), unpwd); } } } fclose(pwfile); return MOSQ_ERR_SUCCESS; } static int _unpwd_file_parse(struct mosquitto_db *db) { int rc; #ifdef WITH_TLS struct _mosquitto_unpwd *u, *tmp; char *token; unsigned char *salt; unsigned int salt_len; unsigned char *password; unsigned int password_len; #endif if(!db || !db->config) return MOSQ_ERR_INVAL; if(!db->config->password_file) return MOSQ_ERR_SUCCESS; rc = _pwfile_parse(db->config->password_file, &db->unpwd); #ifdef WITH_TLS if(rc) return rc; HASH_ITER(hh, db->unpwd, u, tmp){ /* Need to decode password into hashed data + salt. */ if(u->password){ token = strtok(u->password, "$"); if(token && !strcmp(token, "6")){ token = strtok(NULL, "$"); if(token){ rc = _base64_decode(token, &salt, &salt_len); if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password salt for user %s.", u->username); return MOSQ_ERR_INVAL; } u->salt = salt; u->salt_len = salt_len; token = strtok(NULL, "$"); if(token){ rc = _base64_decode(token, &password, &password_len); if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to decode password for user %s.", u->username); return MOSQ_ERR_INVAL; } _mosquitto_free(u->password); u->password = (char *)password; u->password_len = password_len; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid password hash for user %s.", u->username); return MOSQ_ERR_INVAL; } } } #endif return rc; } static int _psk_file_parse(struct mosquitto_db *db) { int rc; struct _mosquitto_unpwd *u, *tmp; if(!db || !db->config) return MOSQ_ERR_INVAL; /* We haven't been asked to parse a psk file. */ if(!db->config->psk_file) return MOSQ_ERR_SUCCESS; rc = _pwfile_parse(db->config->psk_file, &db->psk_id); if(rc) return rc; HASH_ITER(hh, db->psk_id, u, tmp){ /* Check for hex only digits */ if(!u->password){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty psk for identity \"%s\".", u->username); return MOSQ_ERR_INVAL; } if(strspn(u->password, "0123456789abcdefABCDEF") < strlen(u->password)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: psk for identity \"%s\" contains non-hexadecimal characters.", u->username); return MOSQ_ERR_INVAL; } } return MOSQ_ERR_SUCCESS; } static int mosquitto__memcmp_const(const void *a, const void *b, size_t len) { int i; int rc = 0; if(!a || !b) return 1; for(i=0; iunpwd) return MOSQ_ERR_SUCCESS; if(!username) return MOSQ_ERR_INVAL; /* Check must be made only after checking db->unpwd. */ HASH_ITER(hh, db->unpwd, u, tmp){ if(!strcmp(u->username, username)){ if(u->password){ if(password){ #ifdef WITH_TLS rc = _pw_digest(password, u->salt, u->salt_len, hash, &hash_len); if(rc == MOSQ_ERR_SUCCESS){ if(hash_len == u->password_len && !mosquitto__memcmp_const(u->password, hash, hash_len)){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_AUTH; } }else{ return rc; } #else if(!strcmp(u->password, password)){ return MOSQ_ERR_SUCCESS; } #endif }else{ return MOSQ_ERR_AUTH; } }else{ return MOSQ_ERR_SUCCESS; } } } return MOSQ_ERR_AUTH; } static int _unpwd_cleanup(struct _mosquitto_unpwd **root, bool reload) { struct _mosquitto_unpwd *u, *tmp; if(!root) return MOSQ_ERR_INVAL; HASH_ITER(hh, *root, u, tmp){ HASH_DEL(*root, u); if(u->password) _mosquitto_free(u->password); if(u->username) _mosquitto_free(u->username); #ifdef WITH_TLS if(u->salt) _mosquitto_free(u->salt); #endif _mosquitto_free(u); } *root = NULL; return MOSQ_ERR_SUCCESS; } /* Apply security settings after a reload. * Includes: * - Disconnecting anonymous users if appropriate * - Disconnecting users with invalid passwords * - Reapplying ACLs */ int mosquitto_security_apply_default(struct mosquitto_db *db) { struct mosquitto *context, *ctxt_tmp; struct _mosquitto_acl_user *acl_user_tail; bool allow_anonymous; if(!db) return MOSQ_ERR_INVAL; allow_anonymous = db->config->allow_anonymous; HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ /* Check for anonymous clients when allow_anonymous is false */ if(!allow_anonymous && !context->username){ context->state = mosq_cs_disconnecting; do_disconnect(db, context); continue; } /* Check for connected clients that are no longer authorised */ if(mosquitto_unpwd_check_default(db, context->username, context->password) != MOSQ_ERR_SUCCESS){ context->state = mosq_cs_disconnecting; do_disconnect(db, context); continue; } /* Check for ACLs and apply to user. */ if(db->acl_list){ acl_user_tail = db->acl_list; while(acl_user_tail){ if(acl_user_tail->username){ if(context->username){ if(!strcmp(acl_user_tail->username, context->username)){ context->acl_list = acl_user_tail; break; } } }else{ if(!context->username){ context->acl_list = acl_user_tail; break; } } acl_user_tail = acl_user_tail->next; } } } return MOSQ_ERR_SUCCESS; } int mosquitto_psk_key_get_default(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len) { struct _mosquitto_unpwd *u, *tmp; if(!db || !hint || !identity || !key) return MOSQ_ERR_INVAL; if(!db->psk_id) return MOSQ_ERR_AUTH; HASH_ITER(hh, db->psk_id, u, tmp){ if(!strcmp(u->username, identity)){ strncpy(key, u->password, max_key_len); return MOSQ_ERR_SUCCESS; } } return MOSQ_ERR_AUTH; } #ifdef WITH_TLS int _pw_digest(const char *password, const unsigned char *salt, unsigned int salt_len, unsigned char *hash, unsigned int *hash_len) { const EVP_MD *digest; #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_MD_CTX context; digest = EVP_get_digestbyname("sha512"); if(!digest){ // FIXME fprintf(stderr, "Error: Unable to create openssl digest.\n"); return 1; } EVP_MD_CTX_init(&context); EVP_DigestInit_ex(&context, digest, NULL); EVP_DigestUpdate(&context, password, strlen(password)); EVP_DigestUpdate(&context, salt, salt_len); /* hash is assumed to be EVP_MAX_MD_SIZE bytes long. */ EVP_DigestFinal_ex(&context, hash, hash_len); EVP_MD_CTX_cleanup(&context); #else EVP_MD_CTX *context; digest = EVP_get_digestbyname("sha512"); if(!digest){ // FIXME fprintf(stderr, "Error: Unable to create openssl digest.\n"); return 1; } context = EVP_MD_CTX_new(); EVP_DigestInit_ex(context, digest, NULL); EVP_DigestUpdate(context, password, strlen(password)); EVP_DigestUpdate(context, salt, salt_len); /* hash is assumed to be EVP_MAX_MD_SIZE bytes long. */ EVP_DigestFinal_ex(context, hash, hash_len); EVP_MD_CTX_free(context); #endif return MOSQ_ERR_SUCCESS; } int _base64_decode(char *in, unsigned char **decoded, unsigned int *decoded_len) { BIO *bmem, *b64; b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); BIO_write(bmem, in, strlen(in)); if(BIO_flush(bmem) != 1){ BIO_free_all(b64); return 1; } *decoded = _mosquitto_calloc(strlen(in), 1); *decoded_len = BIO_read(b64, *decoded, strlen(in)); BIO_free_all(b64); return 0; } #endif mosquitto-1.4.15/src/logging.c0000664000175000017500000001437213245550210015253 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #ifndef WIN32 #include #endif #include #ifndef CMAKE #include #endif #include #include #include extern struct mosquitto_db int_db; #ifdef WIN32 HANDLE syslog_h; #endif /* Options for logging should be: * * A combination of: * Via syslog * To a file * To stdout/stderr * To topics */ /* Give option of logging timestamp. * Logging pid. */ static int log_destinations = MQTT3_LOG_STDERR; static int log_priorities = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO; int mqtt3_log_init(struct mqtt3_config *config) { int rc = 0; log_priorities = config->log_type; log_destinations = config->log_dest; if(log_destinations & MQTT3_LOG_SYSLOG){ #ifndef WIN32 openlog("mosquitto", LOG_PID|LOG_CONS, config->log_facility); #else syslog_h = OpenEventLog(NULL, "mosquitto"); #endif } if(log_destinations & MQTT3_LOG_FILE){ if(drop_privileges(config, true)){ return 1; } config->log_fptr = _mosquitto_fopen(config->log_file, "at", true); if(!config->log_fptr){ log_destinations = MQTT3_LOG_STDERR; log_priorities = MOSQ_LOG_ERR; _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open log file %s for writing.", config->log_file); return MOSQ_ERR_INVAL; } restore_privileges(); } return rc; } int mqtt3_log_close(struct mqtt3_config *config) { if(log_destinations & MQTT3_LOG_SYSLOG){ #ifndef WIN32 closelog(); #else CloseEventLog(syslog_h); #endif } if(log_destinations & MQTT3_LOG_FILE){ if(config->log_fptr){ fclose(config->log_fptr); config->log_fptr = NULL; } } /* FIXME - do something for all destinations! */ return MOSQ_ERR_SUCCESS; } int _mosquitto_log_vprintf(struct mosquitto *mosq, int priority, const char *fmt, va_list va) { char *s; char *st; int len; #ifdef WIN32 char *sp; #endif const char *topic; int syslog_priority; time_t now = time(NULL); static time_t last_flush = 0; if((log_priorities & priority) && log_destinations != MQTT3_LOG_NONE){ switch(priority){ case MOSQ_LOG_SUBSCRIBE: topic = "$SYS/broker/log/M/subscribe"; #ifndef WIN32 syslog_priority = LOG_NOTICE; #else syslog_priority = EVENTLOG_INFORMATION_TYPE; #endif break; case MOSQ_LOG_UNSUBSCRIBE: topic = "$SYS/broker/log/M/unsubscribe"; #ifndef WIN32 syslog_priority = LOG_NOTICE; #else syslog_priority = EVENTLOG_INFORMATION_TYPE; #endif break; case MOSQ_LOG_DEBUG: topic = "$SYS/broker/log/D"; #ifndef WIN32 syslog_priority = LOG_DEBUG; #else syslog_priority = EVENTLOG_INFORMATION_TYPE; #endif break; case MOSQ_LOG_ERR: topic = "$SYS/broker/log/E"; #ifndef WIN32 syslog_priority = LOG_ERR; #else syslog_priority = EVENTLOG_ERROR_TYPE; #endif break; case MOSQ_LOG_WARNING: topic = "$SYS/broker/log/W"; #ifndef WIN32 syslog_priority = LOG_WARNING; #else syslog_priority = EVENTLOG_WARNING_TYPE; #endif break; case MOSQ_LOG_NOTICE: topic = "$SYS/broker/log/N"; #ifndef WIN32 syslog_priority = LOG_NOTICE; #else syslog_priority = EVENTLOG_INFORMATION_TYPE; #endif break; case MOSQ_LOG_INFO: topic = "$SYS/broker/log/I"; #ifndef WIN32 syslog_priority = LOG_INFO; #else syslog_priority = EVENTLOG_INFORMATION_TYPE; #endif break; #ifdef WITH_WEBSOCKETS case MOSQ_LOG_WEBSOCKETS: topic = "$SYS/broker/log/WS"; #ifndef WIN32 syslog_priority = LOG_DEBUG; #else syslog_priority = EVENTLOG_INFORMATION_TYPE; #endif break; #endif default: topic = "$SYS/broker/log/E"; #ifndef WIN32 syslog_priority = LOG_ERR; #else syslog_priority = EVENTLOG_ERROR_TYPE; #endif } len = strlen(fmt) + 500; s = _mosquitto_malloc(len*sizeof(char)); if(!s) return MOSQ_ERR_NOMEM; vsnprintf(s, len, fmt, va); s[len-1] = '\0'; /* Ensure string is null terminated. */ if(log_destinations & MQTT3_LOG_STDOUT){ if(int_db.config && int_db.config->log_timestamp){ fprintf(stdout, "%d: %s\n", (int)now, s); }else{ fprintf(stdout, "%s\n", s); } fflush(stdout); } if(log_destinations & MQTT3_LOG_STDERR){ if(int_db.config && int_db.config->log_timestamp){ fprintf(stderr, "%d: %s\n", (int)now, s); }else{ fprintf(stderr, "%s\n", s); } fflush(stderr); } if(log_destinations & MQTT3_LOG_FILE && int_db.config->log_fptr){ if(int_db.config && int_db.config->log_timestamp){ fprintf(int_db.config->log_fptr, "%d: %s\n", (int)now, s); }else{ fprintf(int_db.config->log_fptr, "%s\n", s); } if(now - last_flush > 1){ fflush(int_db.config->log_fptr); last_flush = now; } } if(log_destinations & MQTT3_LOG_SYSLOG){ #ifndef WIN32 syslog(syslog_priority, "%s", s); #else sp = (char *)s; ReportEvent(syslog_h, syslog_priority, 0, 0, NULL, 1, 0, &sp, NULL); #endif } if(log_destinations & MQTT3_LOG_TOPIC && priority != MOSQ_LOG_DEBUG){ if(int_db.config && int_db.config->log_timestamp){ len += 30; st = _mosquitto_malloc(len*sizeof(char)); if(!st){ _mosquitto_free(s); return MOSQ_ERR_NOMEM; } snprintf(st, len, "%d: %s", (int)now, s); mqtt3_db_messages_easy_queue(&int_db, NULL, topic, 2, strlen(st), st, 0); _mosquitto_free(st); }else{ mqtt3_db_messages_easy_queue(&int_db, NULL, topic, 2, strlen(s), s, 0); } } _mosquitto_free(s); } return MOSQ_ERR_SUCCESS; } int _mosquitto_log_printf(struct mosquitto *mosq, int priority, const char *fmt, ...) { va_list va; int rc; va_start(va, fmt); rc = _mosquitto_log_vprintf(mosq, priority, fmt, va); va_end(va); return rc; } void mosquitto_log_printf(int level, const char *fmt, ...) { va_list va; va_start(va, fmt); _mosquitto_log_vprintf(NULL, level, fmt, va); va_end(va); } mosquitto-1.4.15/src/database.c0000664000175000017500000005503113245550210015366 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include static int max_inflight = 20; static int max_queued = 100; #ifdef WITH_SYS_TREE extern unsigned long g_msgs_dropped; #endif int mqtt3_db_open(struct mqtt3_config *config, struct mosquitto_db *db) { int rc = 0; struct _mosquitto_subhier *child; if(!config || !db) return MOSQ_ERR_INVAL; db->last_db_id = 0; db->contexts_by_id = NULL; db->contexts_by_sock = NULL; db->contexts_for_free = NULL; #ifdef WITH_BRIDGE db->bridges = NULL; db->bridge_count = 0; #endif // Initialize the hashtable db->clientid_index_hash = NULL; db->subs.next = NULL; db->subs.subs = NULL; db->subs.topic = ""; child = _mosquitto_malloc(sizeof(struct _mosquitto_subhier)); if(!child){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->parent = NULL; child->next = NULL; child->topic = _mosquitto_strdup(""); if(!child->topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->subs = NULL; child->children = NULL; child->retained = NULL; db->subs.children = child; child = _mosquitto_malloc(sizeof(struct _mosquitto_subhier)); if(!child){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->parent = NULL; child->next = NULL; child->topic = _mosquitto_strdup("$SYS"); if(!child->topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->subs = NULL; child->children = NULL; child->retained = NULL; db->subs.children->next = child; db->unpwd = NULL; #ifdef WITH_PERSISTENCE if(config->persistence && config->persistence_filepath){ if(mqtt3_db_restore(db)) return 1; } #endif return rc; } static void subhier_clean(struct mosquitto_db *db, struct _mosquitto_subhier *subhier) { struct _mosquitto_subhier *next; struct _mosquitto_subleaf *leaf, *nextleaf; while(subhier){ next = subhier->next; leaf = subhier->subs; while(leaf){ nextleaf = leaf->next; _mosquitto_free(leaf); leaf = nextleaf; } if(subhier->retained){ mosquitto__db_msg_store_deref(db, &subhier->retained); } subhier_clean(db, subhier->children); if(subhier->topic) _mosquitto_free(subhier->topic); _mosquitto_free(subhier); subhier = next; } } int mqtt3_db_close(struct mosquitto_db *db) { subhier_clean(db, db->subs.children); mosquitto__db_msg_store_clean(db); return MOSQ_ERR_SUCCESS; } void mosquitto__db_msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store) { store->next = db->msg_store; store->prev = NULL; if(db->msg_store){ db->msg_store->prev = store; } db->msg_store = store; } void mosquitto__db_msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store) { int i; if(store->prev){ store->prev->next = store->next; if(store->next){ store->next->prev = store->prev; } }else{ db->msg_store = store->next; if(store->next){ store->next->prev = NULL; } } db->msg_store_count--; if(store->source_id) _mosquitto_free(store->source_id); if(store->dest_ids){ for(i=0; idest_id_count; i++){ if(store->dest_ids[i]) _mosquitto_free(store->dest_ids[i]); } _mosquitto_free(store->dest_ids); } if(store->topic) _mosquitto_free(store->topic); if(store->payload) _mosquitto_free(store->payload); _mosquitto_free(store); } void mosquitto__db_msg_store_clean(struct mosquitto_db *db) { struct mosquitto_msg_store *store, *next;; store = db->msg_store; while(store){ next = store->next; mosquitto__db_msg_store_remove(db, store); store = next; } } void mosquitto__db_msg_store_deref(struct mosquitto_db *db, struct mosquitto_msg_store **store) { (*store)->ref_count--; if((*store)->ref_count == 0){ mosquitto__db_msg_store_remove(db, *store); *store = NULL; } } static void _message_remove(struct mosquitto_db *db, struct mosquitto *context, struct mosquitto_client_msg **msg, struct mosquitto_client_msg *last) { int i; struct mosquitto_client_msg *tail; if(!context || !msg || !(*msg)){ return; } if((*msg)->store){ mosquitto__db_msg_store_deref(db, &(*msg)->store); } if(last){ last->next = (*msg)->next; if(!last->next){ context->last_msg = last; } }else{ context->msgs = (*msg)->next; if(!context->msgs){ context->last_msg = NULL; } } context->msg_count--; if((*msg)->qos > 0){ context->msg_count12--; } _mosquitto_free(*msg); if(last){ *msg = last->next; }else{ *msg = context->msgs; } tail = context->msgs; i = 0; while(tail && tail->state == mosq_ms_queued && idirection == mosq_md_out){ switch(tail->qos){ case 0: tail->state = mosq_ms_publish_qos0; break; case 1: tail->state = mosq_ms_publish_qos1; break; case 2: tail->state = mosq_ms_publish_qos2; break; } }else{ if(tail->qos == 2){ tail->state = mosq_ms_send_pubrec; } } tail = tail->next; } } int mqtt3_db_message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir) { struct mosquitto_client_msg *tail, *last = NULL; int msg_index = 0; bool deleted = false; if(!context) return MOSQ_ERR_INVAL; tail = context->msgs; while(tail){ msg_index++; if(tail->state == mosq_ms_queued && msg_index <= max_inflight){ tail->timestamp = mosquitto_time(); if(tail->direction == mosq_md_out){ switch(tail->qos){ case 0: tail->state = mosq_ms_publish_qos0; break; case 1: tail->state = mosq_ms_publish_qos1; break; case 2: tail->state = mosq_ms_publish_qos2; break; } }else{ if(tail->qos == 2){ tail->state = mosq_ms_wait_for_pubrel; } } } if(tail->mid == mid && tail->direction == dir){ msg_index--; _message_remove(db, context, &tail, last); deleted = true; }else{ last = tail; tail = tail->next; } if(msg_index > max_inflight && deleted){ return MOSQ_ERR_SUCCESS; } } return MOSQ_ERR_SUCCESS; } int mqtt3_db_message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored) { struct mosquitto_client_msg *msg; enum mosquitto_msg_state state = mosq_ms_invalid; int rc = 0; int i; char **dest_ids; assert(stored); if(!context) return MOSQ_ERR_INVAL; if(!context->id) return MOSQ_ERR_SUCCESS; /* Protect against unlikely "client is disconnected but not entirely freed" scenario */ /* Check whether we've already sent this message to this client * for outgoing messages only. * If retain==true then this is a stale retained message and so should be * sent regardless. FIXME - this does mean retained messages will received * multiple times for overlapping subscriptions, although this is only the * case for SUBSCRIPTION with multiple subs in so is a minor concern. */ if(db->config->allow_duplicate_messages == false && dir == mosq_md_out && retain == false && stored->dest_ids){ for(i=0; idest_id_count; i++){ if(!strcmp(stored->dest_ids[i], context->id)){ /* We have already sent this message to this client. */ return MOSQ_ERR_SUCCESS; } } } if(context->sock == INVALID_SOCKET){ /* Client is not connected only queue messages with QoS>0. */ if(qos == 0 && !db->config->queue_qos0_messages){ if(!context->bridge){ return 2; }else{ if(context->bridge->start_type != bst_lazy){ return 2; } } } } if(context->sock != INVALID_SOCKET){ if(qos == 0 || max_inflight == 0 || context->msg_count12 < max_inflight){ if(dir == mosq_md_out){ switch(qos){ case 0: state = mosq_ms_publish_qos0; break; case 1: state = mosq_ms_publish_qos1; break; case 2: state = mosq_ms_publish_qos2; break; } }else{ if(qos == 2){ state = mosq_ms_wait_for_pubrel; }else{ return 1; } } }else if(max_queued == 0 || context->msg_count12-max_inflight < max_queued){ state = mosq_ms_queued; rc = 2; }else{ /* Dropping message due to full queue. */ if(context->is_dropping == false){ context->is_dropping = true; _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Outgoing messages are being dropped for client %s.", context->id); } #ifdef WITH_SYS_TREE g_msgs_dropped++; #endif return 2; } }else{ if(max_queued > 0 && context->msg_count12 >= max_queued){ #ifdef WITH_SYS_TREE g_msgs_dropped++; #endif if(context->is_dropping == false){ context->is_dropping = true; _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Outgoing messages are being dropped for client %s.", context->id); } return 2; }else{ state = mosq_ms_queued; } } assert(state != mosq_ms_invalid); #ifdef WITH_PERSISTENCE if(state == mosq_ms_queued){ db->persistence_changes++; } #endif msg = _mosquitto_malloc(sizeof(struct mosquitto_client_msg)); if(!msg) return MOSQ_ERR_NOMEM; msg->next = NULL; msg->store = stored; msg->store->ref_count++; msg->mid = mid; msg->timestamp = mosquitto_time(); msg->direction = dir; msg->state = state; msg->dup = false; msg->qos = qos; msg->retain = retain; if(context->last_msg){ context->last_msg->next = msg; context->last_msg = msg; }else{ context->msgs = msg; context->last_msg = msg; } context->msg_count++; if(qos > 0){ context->msg_count12++; } if(db->config->allow_duplicate_messages == false && dir == mosq_md_out && retain == false){ /* Record which client ids this message has been sent to so we can avoid duplicates. * Outgoing messages only. * If retain==true then this is a stale retained message and so should be * sent regardless. FIXME - this does mean retained messages will received * multiple times for overlapping subscriptions, although this is only the * case for SUBSCRIPTION with multiple subs in so is a minor concern. */ dest_ids = _mosquitto_realloc(stored->dest_ids, sizeof(char *)*(stored->dest_id_count+1)); if(dest_ids){ stored->dest_ids = dest_ids; stored->dest_id_count++; stored->dest_ids[stored->dest_id_count-1] = _mosquitto_strdup(context->id); if(!stored->dest_ids[stored->dest_id_count-1]){ return MOSQ_ERR_NOMEM; } }else{ return MOSQ_ERR_NOMEM; } } #ifdef WITH_BRIDGE if(context->bridge && context->bridge->start_type == bst_lazy && context->sock == INVALID_SOCKET && context->msg_count >= context->bridge->threshold){ context->bridge->lazy_reconnect = true; } #endif #ifdef WITH_WEBSOCKETS if(context->wsi && rc == 0){ return mqtt3_db_message_write(db, context); }else{ return rc; } #else return rc; #endif } int mqtt3_db_message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state) { struct mosquitto_client_msg *tail; tail = context->msgs; while(tail){ if(tail->mid == mid && tail->direction == dir){ tail->state = state; tail->timestamp = mosquitto_time(); return MOSQ_ERR_SUCCESS; } tail = tail->next; } return MOSQ_ERR_NOT_FOUND; } int mqtt3_db_messages_delete(struct mosquitto_db *db, struct mosquitto *context) { struct mosquitto_client_msg *tail, *next; if(!context) return MOSQ_ERR_INVAL; tail = context->msgs; while(tail){ mosquitto__db_msg_store_deref(db, &tail->store); next = tail->next; _mosquitto_free(tail); tail = next; } context->msgs = NULL; context->last_msg = NULL; context->msg_count = 0; context->msg_count12 = 0; return MOSQ_ERR_SUCCESS; } int mqtt3_db_messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain) { struct mosquitto_msg_store *stored; char *source_id; assert(db); if(!topic) return MOSQ_ERR_INVAL; if(context && context->id){ source_id = context->id; }else{ source_id = ""; } if(mqtt3_db_message_store(db, source_id, 0, topic, qos, payloadlen, payload, retain, &stored, 0)) return 1; return mqtt3_db_messages_queue(db, source_id, topic, qos, retain, &stored); } int mqtt3_db_message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id) { struct mosquitto_msg_store *temp; assert(db); assert(stored); temp = _mosquitto_malloc(sizeof(struct mosquitto_msg_store)); if(!temp) return MOSQ_ERR_NOMEM; temp->ref_count = 0; if(source){ temp->source_id = _mosquitto_strdup(source); }else{ temp->source_id = _mosquitto_strdup(""); } if(!temp->source_id){ _mosquitto_free(temp); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } temp->source_mid = source_mid; temp->mid = 0; temp->qos = qos; temp->retain = retain; if(topic){ temp->topic = _mosquitto_strdup(topic); if(!temp->topic){ _mosquitto_free(temp->source_id); _mosquitto_free(temp); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } }else{ temp->topic = NULL; } temp->payloadlen = payloadlen; if(payloadlen){ temp->payload = _mosquitto_malloc(sizeof(char)*payloadlen); if(!temp->payload){ if(temp->source_id) _mosquitto_free(temp->source_id); if(temp->topic) _mosquitto_free(temp->topic); if(temp->payload) _mosquitto_free(temp->payload); _mosquitto_free(temp); return MOSQ_ERR_NOMEM; } memcpy(temp->payload, payload, sizeof(char)*payloadlen); }else{ temp->payload = NULL; } if(!temp->source_id || (payloadlen && !temp->payload)){ if(temp->source_id) _mosquitto_free(temp->source_id); if(temp->topic) _mosquitto_free(temp->topic); if(temp->payload) _mosquitto_free(temp->payload); _mosquitto_free(temp); return 1; } temp->dest_ids = NULL; temp->dest_id_count = 0; db->msg_store_count++; (*stored) = temp; if(!store_id){ temp->db_id = ++db->last_db_id; }else{ temp->db_id = store_id; } mosquitto__db_msg_store_add(db, temp); return MOSQ_ERR_SUCCESS; } int mqtt3_db_message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored) { struct mosquitto_client_msg *tail; if(!context) return MOSQ_ERR_INVAL; *stored = NULL; tail = context->msgs; while(tail){ if(tail->store->source_mid == mid && tail->direction == mosq_md_in){ *stored = tail->store; return MOSQ_ERR_SUCCESS; } tail = tail->next; } return 1; } /* Called on reconnect to set outgoing messages to a sensible state and force a * retry, and to set incoming messages to expect an appropriate retry. */ int mqtt3_db_message_reconnect_reset(struct mosquitto_db *db, struct mosquitto *context) { struct mosquitto_client_msg *msg; struct mosquitto_client_msg *prev = NULL; int count; msg = context->msgs; context->msg_count = 0; context->msg_count12 = 0; while(msg){ context->last_msg = msg; context->msg_count++; if(msg->qos > 0){ context->msg_count12++; } if(msg->direction == mosq_md_out){ if(msg->state != mosq_ms_queued){ switch(msg->qos){ case 0: msg->state = mosq_ms_publish_qos0; break; case 1: msg->state = mosq_ms_publish_qos1; break; case 2: if(msg->state == mosq_ms_wait_for_pubcomp){ msg->state = mosq_ms_resend_pubrel; }else{ msg->state = mosq_ms_publish_qos2; } break; } } }else{ if(msg->qos != 2){ /* Anything next; } /* Messages received when the client was disconnected are put * in the mosq_ms_queued state. If we don't change them to the * appropriate "publish" state, then the queued messages won't * get sent until the client next receives a message - and they * will be sent out of order. */ if(context->msgs){ count = 0; msg = context->msgs; while(msg && (max_inflight == 0 || count < max_inflight)){ if(msg->state == mosq_ms_queued){ switch(msg->qos){ case 0: msg->state = mosq_ms_publish_qos0; break; case 1: msg->state = mosq_ms_publish_qos1; break; case 2: msg->state = mosq_ms_publish_qos2; break; } } msg = msg->next; count++; } } return MOSQ_ERR_SUCCESS; } int mqtt3_db_message_timeout_check(struct mosquitto_db *db, unsigned int timeout) { time_t threshold; enum mosquitto_msg_state new_state; struct mosquitto *context, *ctxt_tmp; struct mosquitto_client_msg *msg; threshold = mosquitto_time() - timeout; HASH_ITER(hh_sock, db->contexts_by_sock, context, ctxt_tmp){ msg = context->msgs; while(msg){ new_state = mosq_ms_invalid; if(msg->timestamp < threshold && msg->state != mosq_ms_queued){ switch(msg->state){ case mosq_ms_wait_for_puback: new_state = mosq_ms_publish_qos1; break; case mosq_ms_wait_for_pubrec: new_state = mosq_ms_publish_qos2; break; case mosq_ms_wait_for_pubrel: new_state = mosq_ms_send_pubrec; break; case mosq_ms_wait_for_pubcomp: new_state = mosq_ms_resend_pubrel; break; default: break; } if(new_state != mosq_ms_invalid){ msg->timestamp = mosquitto_time(); msg->state = new_state; msg->dup = true; } } msg = msg->next; } } return MOSQ_ERR_SUCCESS; } int mqtt3_db_message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir) { struct mosquitto_client_msg *tail, *last = NULL; int qos; int retain; char *topic; char *source_id; int msg_index = 0; bool deleted = false; if(!context) return MOSQ_ERR_INVAL; tail = context->msgs; while(tail){ msg_index++; if(tail->state == mosq_ms_queued && msg_index <= max_inflight){ tail->timestamp = mosquitto_time(); if(tail->direction == mosq_md_out){ switch(tail->qos){ case 0: tail->state = mosq_ms_publish_qos0; break; case 1: tail->state = mosq_ms_publish_qos1; break; case 2: tail->state = mosq_ms_publish_qos2; break; } }else{ if(tail->qos == 2){ _mosquitto_send_pubrec(context, tail->mid); tail->state = mosq_ms_wait_for_pubrel; } } } if(tail->mid == mid && tail->direction == dir){ qos = tail->store->qos; topic = tail->store->topic; retain = tail->retain; source_id = tail->store->source_id; /* topic==NULL should be a QoS 2 message that was * denied/dropped and is being processed so the client doesn't * keep resending it. That means we don't send it to other * clients. */ if(!topic || !mqtt3_db_messages_queue(db, source_id, topic, qos, retain, &tail->store)){ _message_remove(db, context, &tail, last); deleted = true; }else{ return 1; } }else{ last = tail; tail = tail->next; } if(msg_index > max_inflight && deleted){ return MOSQ_ERR_SUCCESS; } } if(deleted){ return MOSQ_ERR_SUCCESS; }else{ return 1; } } int mqtt3_db_message_write(struct mosquitto_db *db, struct mosquitto *context) { int rc; struct mosquitto_client_msg *tail, *last = NULL; uint16_t mid; int retries; int retain; const char *topic; int qos; uint32_t payloadlen; const void *payload; int msg_count = 0; if(!context || context->sock == INVALID_SOCKET || (context->state == mosq_cs_connected && !context->id)){ return MOSQ_ERR_INVAL; } if(context->state != mosq_cs_connected){ return MOSQ_ERR_SUCCESS; } tail = context->msgs; while(tail){ if(tail->direction == mosq_md_in){ msg_count++; } if(tail->state != mosq_ms_queued){ mid = tail->mid; retries = tail->dup; retain = tail->retain; topic = tail->store->topic; qos = tail->qos; payloadlen = tail->store->payloadlen; payload = tail->store->payload; switch(tail->state){ case mosq_ms_publish_qos0: rc = _mosquitto_send_publish(context, mid, topic, payloadlen, payload, qos, retain, retries); if(!rc){ _message_remove(db, context, &tail, last); }else{ return rc; } break; case mosq_ms_publish_qos1: rc = _mosquitto_send_publish(context, mid, topic, payloadlen, payload, qos, retain, retries); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_puback; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_publish_qos2: rc = _mosquitto_send_publish(context, mid, topic, payloadlen, payload, qos, retain, retries); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_pubrec; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_send_pubrec: rc = _mosquitto_send_pubrec(context, mid); if(!rc){ tail->state = mosq_ms_wait_for_pubrel; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_resend_pubrel: rc = _mosquitto_send_pubrel(context, mid); if(!rc){ tail->state = mosq_ms_wait_for_pubcomp; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_resend_pubcomp: rc = _mosquitto_send_pubcomp(context, mid); if(!rc){ tail->state = mosq_ms_wait_for_pubrel; }else{ return rc; } last = tail; tail = tail->next; break; default: last = tail; tail = tail->next; break; } }else{ /* state == mosq_ms_queued */ if(tail->direction == mosq_md_in && (max_inflight == 0 || msg_count < max_inflight)){ if(tail->qos == 2){ tail->state = mosq_ms_send_pubrec; } }else{ last = tail; tail = tail->next; } } } return MOSQ_ERR_SUCCESS; } void mqtt3_db_limits_set(int inflight, int queued) { max_inflight = inflight; max_queued = queued; } void mqtt3_db_vacuum(void) { /* FIXME - reimplement? */ } mosquitto-1.4.15/src/loop.c0000664000175000017500000003556313245550210014603 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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. */ #define _GNU_SOURCE #include #include #ifndef WIN32 #include #include #else #include #include #include #endif #include #include #include #include #ifndef WIN32 # include #endif #include #ifdef WITH_WEBSOCKETS # include #endif #include #include #include #include #include extern bool flag_reload; #ifdef WITH_PERSISTENCE extern bool flag_db_backup; #endif extern bool flag_tree_print; extern int run; #ifdef WITH_SYS_TREE extern int g_clients_expired; #endif static void loop_handle_reads_writes(struct mosquitto_db *db, struct pollfd *pollfds); #ifdef WITH_WEBSOCKETS static void temp__expire_websockets_clients(struct mosquitto_db *db) { struct mosquitto *context, *ctxt_tmp; static time_t last_check = 0; time_t now = mosquitto_time(); char *id; if(now - last_check > 60){ HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ if(context->wsi && context->sock != INVALID_SOCKET){ if(context->keepalive && now - context->last_msg_in > (time_t)(context->keepalive)*3/2){ if(db->config->connection_messages == true){ if(context->id){ id = context->id; }else{ id = ""; } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client %s has exceeded timeout, disconnecting.", id); } /* Client has exceeded keepalive*1.5 */ do_disconnect(db, context); } } } last_check = mosquitto_time(); } } #endif int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int listensock_count, int listener_max) { #ifdef WITH_SYS_TREE time_t start_time = mosquitto_time(); #endif #ifdef WITH_PERSISTENCE time_t last_backup = mosquitto_time(); #endif time_t now = 0; time_t now_time; int time_count; int fdcount; struct mosquitto *context, *ctxt_tmp; #ifndef WIN32 sigset_t sigblock, origsig; #endif int i; struct pollfd *pollfds = NULL; int pollfd_index; int pollfd_max; #ifdef WITH_BRIDGE mosq_sock_t bridge_sock; int rc; #endif time_t expiration_check_time = 0; time_t last_timeout_check = 0; char *id; #ifndef WIN32 sigemptyset(&sigblock); sigaddset(&sigblock, SIGINT); sigaddset(&sigblock, SIGTERM); sigaddset(&sigblock, SIGHUP); #endif #ifdef WIN32 pollfd_max = _getmaxstdio(); #else pollfd_max = sysconf(_SC_OPEN_MAX); #endif pollfds = _mosquitto_malloc(sizeof(struct pollfd)*pollfd_max); if(!pollfds){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(db->config->persistent_client_expiration > 0){ expiration_check_time = time(NULL) + 3600; } while(run){ mosquitto__free_disused_contexts(db); #ifdef WITH_SYS_TREE if(db->config->sys_interval > 0){ mqtt3_db_sys_update(db, db->config->sys_interval, start_time); } #endif memset(pollfds, -1, sizeof(struct pollfd)*pollfd_max); pollfd_index = 0; for(i=0; icontexts_by_sock, context, ctxt_tmp){ if(time_count > 0){ time_count--; }else{ time_count = 1000; now = mosquitto_time(); } context->pollfd_index = -1; if(context->sock != INVALID_SOCKET){ #ifdef WITH_BRIDGE if(context->bridge){ _mosquitto_check_keepalive(db, context); if(context->bridge->round_robin == false && context->bridge->cur_address != 0 && now > context->bridge->primary_retry){ if(_mosquitto_try_connect(context, context->bridge->addresses[0].address, context->bridge->addresses[0].port, &bridge_sock, NULL, false) <= 0){ COMPAT_CLOSE(bridge_sock); _mosquitto_socket_close(db, context); context->bridge->cur_address = context->bridge->address_count-1; } } } #endif /* Local bridges never time out in this fashion. */ if(!(context->keepalive) || context->bridge || now - context->last_msg_in < (time_t)(context->keepalive)*3/2){ if(mqtt3_db_message_write(db, context) == MOSQ_ERR_SUCCESS){ pollfds[pollfd_index].fd = context->sock; pollfds[pollfd_index].events = POLLIN; pollfds[pollfd_index].revents = 0; if(context->current_out_packet || context->state == mosq_cs_connect_pending || context->ws_want_write){ pollfds[pollfd_index].events |= POLLOUT; context->ws_want_write = false; } context->pollfd_index = pollfd_index; pollfd_index++; }else{ do_disconnect(db, context); } }else{ if(db->config->connection_messages == true){ if(context->id){ id = context->id; }else{ id = ""; } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client %s has exceeded timeout, disconnecting.", id); } /* Client has exceeded keepalive*1.5 */ do_disconnect(db, context); } } } #ifdef WITH_BRIDGE time_count = 0; for(i=0; ibridge_count; i++){ if(!db->bridges[i]) continue; context = db->bridges[i]; if(context->sock == INVALID_SOCKET){ if(time_count > 0){ time_count--; }else{ time_count = 1000; now = mosquitto_time(); } /* Want to try to restart the bridge connection */ if(!context->bridge->restart_t){ context->bridge->restart_t = now+context->bridge->restart_timeout; context->bridge->cur_address++; if(context->bridge->cur_address == context->bridge->address_count){ context->bridge->cur_address = 0; } if(context->bridge->round_robin == false && context->bridge->cur_address != 0){ context->bridge->primary_retry = now + 5; } }else{ if((context->bridge->start_type == bst_lazy && context->bridge->lazy_reconnect) || (context->bridge->start_type == bst_automatic && now > context->bridge->restart_t)){ context->bridge->restart_t = 0; #if defined(__GLIBC__) && defined(WITH_ADNS) if(context->adns){ /* Waiting on DNS lookup */ rc = gai_error(context->adns); if(rc == EAI_INPROGRESS){ /* Just keep on waiting */ }else if(rc == 0){ rc = mqtt3_bridge_connect_step2(db, context); if(rc == MOSQ_ERR_SUCCESS){ pollfds[pollfd_index].fd = context->sock; pollfds[pollfd_index].events = POLLIN; pollfds[pollfd_index].revents = 0; if(context->current_out_packet){ pollfds[pollfd_index].events |= POLLOUT; } context->pollfd_index = pollfd_index; pollfd_index++; }else{ context->bridge->cur_address++; if(context->bridge->cur_address == context->bridge->address_count){ context->bridge->cur_address = 0; } } }else{ /* Need to retry */ if(context->adns->ar_result){ freeaddrinfo(context->adns->ar_result); } _mosquitto_free(context->adns); context->adns = NULL; } }else{ rc = mqtt3_bridge_connect_step1(db, context); if(rc){ context->bridge->cur_address++; if(context->bridge->cur_address == context->bridge->address_count){ context->bridge->cur_address = 0; } } } #else { rc = mqtt3_bridge_connect(db, context); if(rc == MOSQ_ERR_SUCCESS){ pollfds[pollfd_index].fd = context->sock; pollfds[pollfd_index].events = POLLIN; pollfds[pollfd_index].revents = 0; if(context->current_out_packet){ pollfds[pollfd_index].events |= POLLOUT; } context->pollfd_index = pollfd_index; pollfd_index++; }else{ context->bridge->cur_address++; if(context->bridge->cur_address == context->bridge->address_count){ context->bridge->cur_address = 0; } } } #endif } } } } #endif now_time = time(NULL); if(db->config->persistent_client_expiration > 0 && now_time > expiration_check_time){ HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ if(context->sock == INVALID_SOCKET && context->clean_session == 0){ /* This is a persistent client, check to see if the * last time it connected was longer than * persistent_client_expiration seconds ago. If so, * expire it and clean up. */ if(now_time > context->disconnect_t+db->config->persistent_client_expiration){ if(context->id){ id = context->id; }else{ id = ""; } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Expiring persistent client %s due to timeout.", id); #ifdef WITH_SYS_TREE g_clients_expired++; #endif context->clean_session = true; context->state = mosq_cs_expiring; do_disconnect(db, context); } } } expiration_check_time = time(NULL) + 3600; } if(last_timeout_check < mosquitto_time()){ /* Only check at most once per second. */ mqtt3_db_message_timeout_check(db, db->config->retry_interval); last_timeout_check = mosquitto_time(); } #ifndef WIN32 sigprocmask(SIG_SETMASK, &sigblock, &origsig); fdcount = poll(pollfds, pollfd_index, 100); sigprocmask(SIG_SETMASK, &origsig, NULL); #else fdcount = WSAPoll(pollfds, pollfd_index, 100); #endif if(fdcount == -1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error in poll: %s.", strerror(errno)); }else{ loop_handle_reads_writes(db, pollfds); for(i=0; iconfig->persistence && db->config->autosave_interval){ if(db->config->autosave_on_changes){ if(db->persistence_changes >= db->config->autosave_interval){ mqtt3_db_backup(db, false); db->persistence_changes = 0; } }else{ if(last_backup + db->config->autosave_interval < mosquitto_time()){ mqtt3_db_backup(db, false); last_backup = mosquitto_time(); } } } #endif #ifdef WITH_PERSISTENCE if(flag_db_backup){ mqtt3_db_backup(db, false); flag_db_backup = false; } #endif if(flag_reload){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Reloading config."); mqtt3_config_read(db, db->config, true); mosquitto_security_cleanup(db, true); mosquitto_security_init(db, true); mosquitto_security_apply(db); mqtt3_log_close(db->config); mqtt3_log_init(db->config); flag_reload = false; } if(flag_tree_print){ mqtt3_sub_tree_print(&db->subs, 0); flag_tree_print = false; } #ifdef WITH_WEBSOCKETS for(i=0; iconfig->listener_count; i++){ /* Extremely hacky, should be using the lws provided external poll * interface, but their interface has changed recently and ours * will soon, so for now websockets clients are second class * citizens. */ if(db->config->listeners[i].ws_context){ libwebsocket_service(db->config->listeners[i].ws_context, 0); } } if(db->config->have_websockets_listener){ temp__expire_websockets_clients(db); } #endif } if(pollfds) _mosquitto_free(pollfds); return MOSQ_ERR_SUCCESS; } void do_disconnect(struct mosquitto_db *db, struct mosquitto *context) { char *id; if(context->state == mosq_cs_disconnected){ return; } #ifdef WITH_WEBSOCKETS if(context->wsi){ if(context->state != mosq_cs_disconnecting){ context->state = mosq_cs_disconnect_ws; } if(context->wsi){ libwebsocket_callback_on_writable(context->ws_context, context->wsi); } if(context->sock != INVALID_SOCKET){ HASH_DELETE(hh_sock, db->contexts_by_sock, context); context->sock = INVALID_SOCKET; context->pollfd_index = -1; } }else #endif { if(db->config->connection_messages == true){ if(context->id){ id = context->id; }else{ id = ""; } if(context->state != mosq_cs_disconnecting){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Socket error on client %s, disconnecting.", id); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client %s disconnected.", id); } } mqtt3_context_disconnect(db, context); #ifdef WITH_BRIDGE if(context->clean_session && !context->bridge){ #else if(context->clean_session){ #endif mosquitto__add_context_to_disused(db, context); if(context->id){ HASH_DELETE(hh_id, db->contexts_by_id, context); _mosquitto_free(context->id); context->id = NULL; } } context->state = mosq_cs_disconnected; } } static void loop_handle_reads_writes(struct mosquitto_db *db, struct pollfd *pollfds) { struct mosquitto *context, *ctxt_tmp; int err; socklen_t len; HASH_ITER(hh_sock, db->contexts_by_sock, context, ctxt_tmp){ if(context->pollfd_index < 0){ continue; } assert(pollfds[context->pollfd_index].fd == context->sock); #ifdef WITH_WEBSOCKETS if(context->wsi){ struct lws_pollfd wspoll; wspoll.fd = pollfds[context->pollfd_index].fd; wspoll.events = pollfds[context->pollfd_index].events; wspoll.revents = pollfds[context->pollfd_index].revents; lws_service_fd(lws_get_context(context->wsi), &wspoll); continue; } #endif #ifdef WITH_TLS if(pollfds[context->pollfd_index].revents & POLLOUT || context->want_write || (context->ssl && context->state == mosq_cs_new)){ #else if(pollfds[context->pollfd_index].revents & POLLOUT){ #endif if(context->state == mosq_cs_connect_pending){ len = sizeof(int); if(!getsockopt(context->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &len)){ if(err == 0){ context->state = mosq_cs_new; } }else{ do_disconnect(db, context); continue; } } if(_mosquitto_packet_write(context)){ do_disconnect(db, context); continue; } } } HASH_ITER(hh_sock, db->contexts_by_sock, context, ctxt_tmp){ if(context->pollfd_index < 0){ continue; } #ifdef WITH_WEBSOCKETS if(context->wsi){ // Websocket are already handled above continue; } #endif #ifdef WITH_TLS if(pollfds[context->pollfd_index].revents & POLLIN || (context->ssl && context->state == mosq_cs_new)){ #else if(pollfds[context->pollfd_index].revents & POLLIN){ #endif do{ if(_mosquitto_packet_read(db, context)){ do_disconnect(db, context); continue; } }while(SSL_DATA_PENDING(context)); } if(context->pollfd_index >= 0 && pollfds[context->pollfd_index].revents & (POLLERR | POLLNVAL | POLLHUP)){ do_disconnect(db, context); continue; } } } mosquitto-1.4.15/src/send_server.c0000664000175000017500000000413013245550210016133 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include int _mosquitto_send_connack(struct mosquitto *context, int ack, int result) { struct _mosquitto_packet *packet = NULL; int rc; if(context){ if(context->id){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->id, ack, result); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->address, ack, result); } } packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = CONNACK; packet->remaining_length = 2; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } packet->payload[packet->pos+0] = ack; packet->payload[packet->pos+1] = result; return _mosquitto_packet_queue(context, packet); } int _mosquitto_send_suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload) { struct _mosquitto_packet *packet = NULL; int rc; _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending SUBACK to %s", context->id); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = SUBACK; packet->remaining_length = 2+payloadlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } _mosquitto_write_uint16(packet, mid); if(payloadlen){ _mosquitto_write_bytes(packet, payload, payloadlen); } return _mosquitto_packet_queue(context, packet); } mosquitto-1.4.15/src/service.c0000664000175000017500000000741113245550210015261 0ustar rogerroger/* Copyright (c) 2011-2018 Roger Light 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. */ #if defined(WIN32) || defined(__CYGWIN__) #include #include extern int run; SERVICE_STATUS_HANDLE service_handle = 0; static SERVICE_STATUS service_status; int main(int argc, char *argv[]); /* Service control callback */ void __stdcall service_handler(DWORD fdwControl) { switch(fdwControl){ case SERVICE_CONTROL_CONTINUE: /* Continue from Paused state. */ break; case SERVICE_CONTROL_PAUSE: /* Pause service. */ break; case SERVICE_CONTROL_SHUTDOWN: /* System is shutting down. */ case SERVICE_CONTROL_STOP: /* Service should stop. */ service_status.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(service_handle, &service_status); run = 0; break; } } /* Function called when started as a service. */ void __stdcall service_main(DWORD dwArgc, LPTSTR *lpszArgv) { char **argv; int argc = 1; char conf_path[MAX_PATH + 20]; int rc; service_handle = RegisterServiceCtrlHandler("mosquitto", service_handler); if(service_handle){ rc = GetEnvironmentVariable("MOSQUITTO_DIR", conf_path, MAX_PATH); if(!rc || rc == MAX_PATH){ service_status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(service_handle, &service_status); return; } strcat(conf_path, "/mosquitto.conf"); argv = _mosquitto_malloc(sizeof(char *)*3); argv[0] = "mosquitto"; argv[1] = "-c"; argv[2] = conf_path; argc = 3; service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = NO_ERROR; service_status.dwCheckPoint = 0; SetServiceStatus(service_handle, &service_status); main(argc, argv); _mosquitto_free(argv); service_status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(service_handle, &service_status); } } void service_install(void) { SC_HANDLE sc_manager, svc_handle; char exe_path[MAX_PATH + 5]; SERVICE_DESCRIPTION svc_desc; GetModuleFileName(NULL, exe_path, MAX_PATH); strcat(exe_path, " run"); sc_manager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); if(sc_manager){ svc_handle = CreateService(sc_manager, "mosquitto", "Mosquitto Broker", SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, exe_path, NULL, NULL, NULL, NULL, NULL); if(svc_handle){ svc_desc.lpDescription = "MQTT v3.1 broker"; ChangeServiceConfig2(svc_handle, SERVICE_CONFIG_DESCRIPTION, &svc_desc); CloseServiceHandle(svc_handle); } CloseServiceHandle(sc_manager); } } void service_uninstall(void) { SC_HANDLE sc_manager, svc_handle; SERVICE_STATUS status; sc_manager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); if(sc_manager){ svc_handle = OpenService(sc_manager, "mosquitto", SERVICE_QUERY_STATUS | DELETE); if(svc_handle){ if(QueryServiceStatus(svc_handle, &status)){ if(status.dwCurrentState == SERVICE_STOPPED){ DeleteService(svc_handle); } } CloseServiceHandle(svc_handle); } CloseServiceHandle(sc_manager); } } void service_run(void) { SERVICE_TABLE_ENTRY ste[] = { { "mosquitto", service_main }, { NULL, NULL } }; StartServiceCtrlDispatcher(ste); } #endif mosquitto-1.4.15/src/context.c0000664000175000017500000001432413245550210015306 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include "uthash.h" struct mosquitto *mqtt3_context_init(struct mosquitto_db *db, mosq_sock_t sock) { struct mosquitto *context; char address[1024]; context = _mosquitto_calloc(1, sizeof(struct mosquitto)); if(!context) return NULL; context->state = mosq_cs_new; context->sock = sock; context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + 60; context->keepalive = 60; /* Default to 60s */ context->clean_session = true; context->disconnect_t = 0; context->id = NULL; context->last_mid = 0; context->will = NULL; context->username = NULL; context->password = NULL; context->listener = NULL; context->acl_list = NULL; /* is_bridge records whether this client is a bridge or not. This could be * done by looking at context->bridge for bridges that we create ourself, * but incoming bridges need some other way of being recorded. */ context->is_bridge = false; context->in_packet.payload = NULL; _mosquitto_packet_cleanup(&context->in_packet); context->out_packet = NULL; context->current_out_packet = NULL; context->address = NULL; if((int)sock >= 0){ if(!_mosquitto_socket_get_address(sock, address, 1024)){ context->address = _mosquitto_strdup(address); } if(!context->address){ /* getpeername and inet_ntop failed and not a bridge */ _mosquitto_free(context); return NULL; } } context->bridge = NULL; context->msgs = NULL; context->last_msg = NULL; context->msg_count = 0; context->msg_count12 = 0; #ifdef WITH_TLS context->ssl = NULL; #endif if((int)context->sock >= 0){ HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); } return context; } /* * This will result in any outgoing packets going unsent. If we're disconnected * forcefully then it is usually an error condition and shouldn't be a problem, * but it will mean that CONNACK messages will never get sent for bad protocol * versions for example. */ void mqtt3_context_cleanup(struct mosquitto_db *db, struct mosquitto *context, bool do_free) { struct _mosquitto_packet *packet; struct mosquitto_client_msg *msg, *next; int i; if(!context) return; if(context->username){ _mosquitto_free(context->username); context->username = NULL; } if(context->password){ _mosquitto_free(context->password); context->password = NULL; } #ifdef WITH_BRIDGE if(context->bridge){ for(i=0; ibridge_count; i++){ if(db->bridges[i] == context){ db->bridges[i] = NULL; } } if(context->bridge->local_clientid){ _mosquitto_free(context->bridge->local_clientid); context->bridge->local_clientid = NULL; } if(context->bridge->remote_username){ context->bridge->remote_username = NULL; } if(context->bridge->remote_password){ context->bridge->remote_password = NULL; } if(context->bridge->local_username){ context->bridge->local_username = NULL; } if(context->bridge->local_password){ context->bridge->local_password = NULL; } if(context->bridge->local_clientid){ context->bridge->local_clientid = NULL; } } #endif _mosquitto_socket_close(db, context); if((do_free || context->clean_session) && db){ mqtt3_subs_clean_session(db, context); mqtt3_db_messages_delete(db, context); } if(context->address){ _mosquitto_free(context->address); context->address = NULL; } mqtt3_context_send_will(db, context); if(context->id){ assert(db); /* db can only be NULL here if the client hasn't sent a CONNECT and hence wouldn't have an id. */ HASH_DELETE(hh_id, db->contexts_by_id, context); _mosquitto_free(context->id); context->id = NULL; } _mosquitto_packet_cleanup(&(context->in_packet)); if(context->current_out_packet){ _mosquitto_packet_cleanup(context->current_out_packet); _mosquitto_free(context->current_out_packet); context->current_out_packet = NULL; } while(context->out_packet){ _mosquitto_packet_cleanup(context->out_packet); packet = context->out_packet; context->out_packet = context->out_packet->next; _mosquitto_free(packet); } if(do_free || context->clean_session){ msg = context->msgs; while(msg){ next = msg->next; mosquitto__db_msg_store_deref(db, &msg->store); _mosquitto_free(msg); msg = next; } context->msgs = NULL; context->last_msg = NULL; } if(do_free){ _mosquitto_free(context); } } void mqtt3_context_send_will(struct mosquitto_db *db, struct mosquitto *ctxt) { if(ctxt->state != mosq_cs_disconnecting && ctxt->will){ if(mosquitto_acl_check(db, ctxt, ctxt->will->topic, MOSQ_ACL_WRITE) == MOSQ_ERR_SUCCESS){ /* Unexpected disconnect, queue the client will. */ mqtt3_db_messages_easy_queue(db, ctxt, ctxt->will->topic, ctxt->will->qos, ctxt->will->payloadlen, ctxt->will->payload, ctxt->will->retain); } } if(ctxt->will){ if(ctxt->will->topic) _mosquitto_free(ctxt->will->topic); if(ctxt->will->payload) _mosquitto_free(ctxt->will->payload); _mosquitto_free(ctxt->will); ctxt->will = NULL; } } void mqtt3_context_disconnect(struct mosquitto_db *db, struct mosquitto *ctxt) { mqtt3_context_send_will(db, ctxt); ctxt->disconnect_t = time(NULL); _mosquitto_socket_close(db, ctxt); } void mosquitto__add_context_to_disused(struct mosquitto_db *db, struct mosquitto *context) { if(db->ll_for_free){ context->for_free_next = db->ll_for_free; db->ll_for_free = context; }else{ db->ll_for_free = context; } } void mosquitto__free_disused_contexts(struct mosquitto_db *db) { struct mosquitto *context, *next; assert(db); context = db->ll_for_free; while(context){ next = context->for_free_next; mqtt3_context_cleanup(db, context, true); context = next; } db->ll_for_free = NULL; } mosquitto-1.4.15/src/CMakeLists.txt0000664000175000017500000000747613245550210016230 0ustar rogerrogerinclude_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/src ${mosquitto_SOURCE_DIR}/lib ${OPENSSL_INCLUDE_DIR} ${STDBOOL_H_PATH} ${STDINT_H_PATH}) set (MOSQ_SRCS conf.c context.c database.c lib_load.h logging.c loop.c ../lib/memory_mosq.c ../lib/memory_mosq.h mosquitto.c mosquitto_broker.h net.c ../lib/net_mosq.c ../lib/net_mosq.h persist.c persist.h read_handle.c read_handle_client.c read_handle_server.c ../lib/read_handle_shared.c ../lib/read_handle.h subs.c security.c security_default.c ../lib/send_client_mosq.c ../lib/send_mosq.h ../lib/send_mosq.c ../lib/send_mosq.h send_server.c sys_tree.c ../lib/time_mosq.c ../lib/tls_mosq.c ../lib/util_mosq.c ../lib/util_mosq.h websockets.c ../lib/will_mosq.c ../lib/will_mosq.h) option(INC_BRIDGE_SUPPORT "Include bridge support for connecting to other brokers?" ON) if (${INC_BRIDGE_SUPPORT} STREQUAL ON) set (MOSQ_SRCS ${MOSQ_SRCS} bridge.c) add_definitions("-DWITH_BRIDGE") endif (${INC_BRIDGE_SUPPORT} STREQUAL ON) option(USE_LIBWRAP "Include tcp-wrappers support?" OFF) if (${USE_LIBWRAP} STREQUAL ON) set (MOSQ_LIBS ${MOSQ_LIBS} wrap) add_definitions("-DWITH_WRAP") endif (${USE_LIBWRAP} STREQUAL ON) option(INC_DB_UPGRADE "Include database upgrade support? (recommended)" ON) option(INC_MEMTRACK "Include memory tracking support?" ON) if (${INC_MEMTRACK} STREQUAL ON) add_definitions("-DWITH_MEMORY_TRACKING") endif (${INC_MEMTRACK} STREQUAL ON) option(WITH_PERSISTENCE "Include persistence support?" ON) if (${WITH_PERSISTENCE} STREQUAL ON) add_definitions("-DWITH_PERSISTENCE") endif (${WITH_PERSISTENCE} STREQUAL ON) option(WITH_SYS_TREE "Include $SYS tree support?" ON) if (${WITH_SYS_TREE} STREQUAL ON) add_definitions("-DWITH_SYS_TREE") endif (${WITH_SYS_TREE} STREQUAL ON) option(WITH_WEBSOCKETS "Include websockets support?" OFF) if (${WITH_WEBSOCKETS} STREQUAL ON) add_definitions("-DWITH_WEBSOCKETS") endif (${WITH_WEBSOCKETS} STREQUAL ON) if (WIN32 OR CYGWIN) set (MOSQ_SRCS ${MOSQ_SRCS} service.c) endif (WIN32 OR CYGWIN) add_definitions (-DWITH_BROKER) add_executable(mosquitto ${MOSQ_SRCS}) set (MOSQ_LIBS ${MOSQ_LIBS} ${OPENSSL_LIBRARIES}) # Check for getaddrinfo_a include(CheckLibraryExists) check_library_exists(anl getaddrinfo_a "" HAVE_GETADDRINFO_A) if (HAVE_GETADDRINFO_A) add_definitions(-DHAVE_GETADDRINFO_A) set (MOSQ_LIBS ${MOSQ_LIBS} anl) endif (HAVE_GETADDRINFO_A) if (UNIX) if (APPLE) set (MOSQ_LIBS ${MOSQ_LIBS} dl m) else (APPLE) set (MOSQ_LIBS ${MOSQ_LIBS} dl m) find_library(LIBRT rt) if (LIBRT) set (MOSQ_LIBS ${MOSQ_LIBS} rt) endif (LIBRT) endif (APPLE) endif (UNIX) if (WIN32) set (MOSQ_LIBS ${MOSQ_LIBS} ws2_32) endif (WIN32) if (${WITH_WEBSOCKETS} STREQUAL ON) set (MOSQ_LIBS ${MOSQ_LIBS} websockets) endif (${WITH_WEBSOCKETS} STREQUAL ON) # Simple detect libuuid if(NOT APPLE) FIND_PATH(UUID_HEADER uuid/uuid.h) if (UUID_HEADER) add_definitions(-DWITH_UUID) set (MOSQ_LIBS ${MOSQ_LIBS} uuid) endif (UUID_HEADER) endif(NOT APPLE) target_link_libraries(mosquitto ${MOSQ_LIBS}) if (UNIX) if (APPLE) set_target_properties(mosquitto PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list -Wl,${mosquitto_SOURCE_DIR}/src/linker-macosx.syms") else (APPLE) set_target_properties(mosquitto PROPERTIES LINK_FLAGS "-Wl,-dynamic-list=${mosquitto_SOURCE_DIR}/src/linker.syms") endif (APPLE) endif (UNIX) install(TARGETS mosquitto RUNTIME DESTINATION "${SBINDIR}" LIBRARY DESTINATION "${LIBDIR}") install(FILES mosquitto_plugin.h DESTINATION "${INCLUDEDIR}") if (${WITH_TLS} STREQUAL ON) add_executable(mosquitto_passwd mosquitto_passwd.c) target_link_libraries(mosquitto_passwd "${OPENSSL_LIBRARIES}") install(TARGETS mosquitto_passwd RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") endif (${WITH_TLS} STREQUAL ON) if (UNIX) install(CODE "EXEC_PROGRAM(/sbin/ldconfig)") endif (UNIX) mosquitto-1.4.15/src/subs.c0000664000175000017500000004545413245550210014606 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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. */ /* A note on matching topic subscriptions. * * Topics can be up to 32767 characters in length. The / character is used as a * hierarchy delimiter. Messages are published to a particular topic. * Clients may subscribe to particular topics directly, but may also use * wildcards in subscriptions. The + and # characters are used as wildcards. * The # wildcard can be used at the end of a subscription only, and is a * wildcard for the level of hierarchy at which it is placed and all subsequent * levels. * The + wildcard may be used at any point within the subscription and is a * wildcard for only the level of hierarchy at which it is placed. * Neither wildcard may be used as part of a substring. * Valid: * a/b/+ * a/+/c * a/# * a/b/# * # * +/b/c * +/+/+ * Invalid: * a/#/c * a+/b/c * Valid but non-matching: * a/b * a/+ * +/b * b/c/a * a/b/d */ #include #include #include #include #include #include #include struct _sub_token { struct _sub_token *next; char *topic; }; static int _subs_process(struct mosquitto_db *db, struct _mosquitto_subhier *hier, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store *stored, bool set_retain) { int rc = 0; int rc2; int client_qos, msg_qos; uint16_t mid; struct _mosquitto_subleaf *leaf; bool client_retain; leaf = hier->subs; if(retain && set_retain){ #ifdef WITH_PERSISTENCE if(strncmp(topic, "$SYS", 4)){ /* Retained messages count as a persistence change, but only if * they aren't for $SYS. */ db->persistence_changes++; } #endif if(hier->retained){ mosquitto__db_msg_store_deref(db, &hier->retained); #ifdef WITH_SYS_TREE db->retained_count--; #endif } if(stored->payloadlen){ hier->retained = stored; hier->retained->ref_count++; #ifdef WITH_SYS_TREE db->retained_count++; #endif }else{ hier->retained = NULL; } } while(source_id && leaf){ if(!leaf->context->id || (leaf->context->is_bridge && !strcmp(leaf->context->id, source_id))){ leaf = leaf->next; continue; } /* Check for ACL topic access. */ rc2 = mosquitto_acl_check(db, leaf->context, topic, MOSQ_ACL_READ); if(rc2 == MOSQ_ERR_ACL_DENIED){ leaf = leaf->next; continue; }else if(rc2 == MOSQ_ERR_SUCCESS){ client_qos = leaf->qos; if(db->config->upgrade_outgoing_qos){ msg_qos = client_qos; }else{ if(qos > client_qos){ msg_qos = client_qos; }else{ msg_qos = qos; } } if(msg_qos){ mid = _mosquitto_mid_generate(leaf->context); }else{ mid = 0; } if(leaf->context->is_bridge){ /* If we know the client is a bridge then we should set retain * even if the message is fresh. If we don't do this, retained * messages won't be propagated. */ client_retain = retain; }else{ /* Client is not a bridge and this isn't a stale message so * retain should be false. */ client_retain = false; } if(mqtt3_db_message_insert(db, leaf->context, mid, mosq_md_out, msg_qos, client_retain, stored) == 1) rc = 1; }else{ return 1; /* Application error */ } leaf = leaf->next; } return rc; } static struct _sub_token *_sub_topic_append(struct _sub_token **tail, struct _sub_token **topics, char *topic) { struct _sub_token *new_topic; if(!topic){ return NULL; } new_topic = _mosquitto_malloc(sizeof(struct _sub_token)); if(!new_topic){ _mosquitto_free(topic); return NULL; } new_topic->next = NULL; new_topic->topic = topic; if(*tail){ (*tail)->next = new_topic; *tail = (*tail)->next; }else{ *topics = new_topic; *tail = new_topic; } return new_topic; } static int _sub_topic_tokenise(const char *subtopic, struct _sub_token **topics) { struct _sub_token *new_topic, *tail = NULL; int len; int start, stop, tlen; int i; char *topic; assert(subtopic); assert(topics); if(subtopic[0] != '$'){ new_topic = _sub_topic_append(&tail, topics, _mosquitto_strdup("")); if(!new_topic) goto cleanup; } len = strlen(subtopic); if(subtopic[0] == '/'){ new_topic = _sub_topic_append(&tail, topics, _mosquitto_strdup("")); if(!new_topic) goto cleanup; start = 1; }else{ start = 0; } stop = 0; for(i=start; itopic) _mosquitto_free(tail->topic); new_topic = tail->next; _mosquitto_free(tail); tail = new_topic; } return 1; } static void _sub_topic_tokens_free(struct _sub_token *tokens) { struct _sub_token *tail; while(tokens){ tail = tokens->next; if(tokens->topic){ _mosquitto_free(tokens->topic); } _mosquitto_free(tokens); tokens = tail; } } static int _sub_add(struct mosquitto_db *db, struct mosquitto *context, int qos, struct _mosquitto_subhier *subhier, struct _sub_token *tokens) /* FIXME - this function has the potential to leak subhier, audit calling functions. */ { struct _mosquitto_subhier *branch, *last = NULL; struct _mosquitto_subleaf *leaf, *last_leaf; struct _mosquitto_subhier **subs; int i; if(!tokens){ if(context && context->id){ leaf = subhier->subs; last_leaf = NULL; while(leaf){ if(leaf->context && leaf->context->id && !strcmp(leaf->context->id, context->id)){ /* Client making a second subscription to same topic. Only * need to update QoS. Return -1 to indicate this to the * calling function. */ leaf->qos = qos; if(context->protocol == mosq_p_mqtt31){ return -1; }else{ /* mqttv311 requires retained messages are resent on * resubscribe. */ return 0; } } last_leaf = leaf; leaf = leaf->next; } leaf = _mosquitto_malloc(sizeof(struct _mosquitto_subleaf)); if(!leaf) return MOSQ_ERR_NOMEM; leaf->next = NULL; leaf->context = context; leaf->qos = qos; for(i=0; isub_count; i++){ if(!context->subs[i]){ context->subs[i] = subhier; break; } } if(i == context->sub_count){ subs = _mosquitto_realloc(context->subs, sizeof(struct _mosquitto_subhier *)*(context->sub_count + 1)); if(!subs){ _mosquitto_free(leaf); return MOSQ_ERR_NOMEM; } context->subs = subs; context->sub_count++; context->subs[context->sub_count-1] = subhier; } if(last_leaf){ last_leaf->next = leaf; leaf->prev = last_leaf; }else{ subhier->subs = leaf; leaf->prev = NULL; } #ifdef WITH_SYS_TREE db->subscription_count++; #endif } return MOSQ_ERR_SUCCESS; } branch = subhier->children; while(branch){ if(!strcmp(branch->topic, tokens->topic)){ return _sub_add(db, context, qos, branch, tokens->next); } last = branch; branch = branch->next; } /* Not found */ branch = _mosquitto_calloc(1, sizeof(struct _mosquitto_subhier)); if(!branch) return MOSQ_ERR_NOMEM; branch->parent = subhier; branch->topic = _mosquitto_strdup(tokens->topic); if(!branch->topic){ _mosquitto_free(branch); return MOSQ_ERR_NOMEM; } if(!last){ subhier->children = branch; }else{ last->next = branch; } return _sub_add(db, context, qos, branch, tokens->next); } static int _sub_remove(struct mosquitto_db *db, struct mosquitto *context, struct _mosquitto_subhier *subhier, struct _sub_token *tokens) { struct _mosquitto_subhier *branch, *last = NULL; struct _mosquitto_subleaf *leaf; int i; if(!tokens){ leaf = subhier->subs; while(leaf){ if(leaf->context==context){ #ifdef WITH_SYS_TREE db->subscription_count--; #endif if(leaf->prev){ leaf->prev->next = leaf->next; }else{ subhier->subs = leaf->next; } if(leaf->next){ leaf->next->prev = leaf->prev; } _mosquitto_free(leaf); /* Remove the reference to the sub that the client is keeping. * It would be nice to be able to use the reference directly, * but that would involve keeping a copy of the topic string in * each subleaf. Might be worth considering though. */ for(i=0; isub_count; i++){ if(context->subs[i] == subhier){ context->subs[i] = NULL; break; } } return MOSQ_ERR_SUCCESS; } leaf = leaf->next; } return MOSQ_ERR_SUCCESS; } branch = subhier->children; while(branch){ if(!strcmp(branch->topic, tokens->topic)){ _sub_remove(db, context, branch, tokens->next); if(!branch->children && !branch->subs && !branch->retained){ if(last){ last->next = branch->next; }else{ subhier->children = branch->next; } _mosquitto_free(branch->topic); _mosquitto_free(branch); } return MOSQ_ERR_SUCCESS; } last = branch; branch = branch->next; } return MOSQ_ERR_SUCCESS; } static void _sub_search(struct mosquitto_db *db, struct _mosquitto_subhier *subhier, struct _sub_token *tokens, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store *stored, bool set_retain) { /* FIXME - need to take into account source_id if the client is a bridge */ struct _mosquitto_subhier *branch; bool sr; branch = subhier->children; while(branch){ sr = set_retain; if(tokens && tokens->topic && (!strcmp(branch->topic, tokens->topic) || !strcmp(branch->topic, "+"))){ /* The topic matches this subscription. * Doesn't include # wildcards */ if(!strcmp(branch->topic, "+")){ /* Don't set a retained message where + is in the hierarchy. */ sr = false; } _sub_search(db, branch, tokens->next, source_id, topic, qos, retain, stored, sr); if(!tokens->next){ _subs_process(db, branch, source_id, topic, qos, retain, stored, sr); } }else if(!strcmp(branch->topic, "#") && !branch->children){ /* The topic matches due to a # wildcard - process the * subscriptions but *don't* return. Although this branch has ended * there may still be other subscriptions to deal with. */ _subs_process(db, branch, source_id, topic, qos, retain, stored, false); } branch = branch->next; } } int mqtt3_sub_add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct _mosquitto_subhier *root) { int rc = 0; struct _mosquitto_subhier *subhier, *child; struct _sub_token *tokens = NULL; assert(root); assert(sub); if(_sub_topic_tokenise(sub, &tokens)) return 1; subhier = root->children; while(subhier){ if(!strcmp(subhier->topic, tokens->topic)){ rc = _sub_add(db, context, qos, subhier, tokens); break; } subhier = subhier->next; } if(!subhier){ child = _mosquitto_malloc(sizeof(struct _mosquitto_subhier)); if(!child){ _sub_topic_tokens_free(tokens); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->parent = root; child->topic = _mosquitto_strdup(tokens->topic); if(!child->topic){ _sub_topic_tokens_free(tokens); _mosquitto_free(child); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->subs = NULL; child->children = NULL; child->retained = NULL; if(root->children){ child->next = root->children; }else{ child->next = NULL; } root->children = child; rc = _sub_add(db, context, qos, child, tokens); } _sub_topic_tokens_free(tokens); /* We aren't worried about -1 (already subscribed) return codes. */ if(rc == -1) rc = MOSQ_ERR_SUCCESS; return rc; } int mqtt3_sub_remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct _mosquitto_subhier *root) { int rc = 0; struct _mosquitto_subhier *subhier; struct _sub_token *tokens = NULL; assert(root); assert(sub); if(_sub_topic_tokenise(sub, &tokens)) return 1; subhier = root->children; while(subhier){ if(!strcmp(subhier->topic, tokens->topic)){ rc = _sub_remove(db, context, subhier, tokens); break; } subhier = subhier->next; } _sub_topic_tokens_free(tokens); return rc; } int mqtt3_db_messages_queue(struct mosquitto_db *db, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store **stored) { int rc = 0; struct _mosquitto_subhier *subhier; struct _sub_token *tokens = NULL; assert(db); assert(topic); if(_sub_topic_tokenise(topic, &tokens)) return 1; /* Protect this message until we have sent it to all clients - this is required because websockets client calls mqtt3_db_message_write(), which could remove the message if ref_count==0. */ (*stored)->ref_count++; subhier = db->subs.children; while(subhier){ if(!strcmp(subhier->topic, tokens->topic)){ if(retain){ /* We have a message that needs to be retained, so ensure that the subscription * tree for its topic exists. */ _sub_add(db, NULL, 0, subhier, tokens); } _sub_search(db, subhier, tokens, source_id, topic, qos, retain, *stored, true); } subhier = subhier->next; } _sub_topic_tokens_free(tokens); /* Remove our reference and free if needed. */ mosquitto__db_msg_store_deref(db, stored); return rc; } /* Remove a subhier element, and return its parent if that needs freeing as well. */ static struct _mosquitto_subhier *tmp_remove_subs(struct _mosquitto_subhier *sub) { struct _mosquitto_subhier *parent; struct _mosquitto_subhier *hier; struct _mosquitto_subhier *last = NULL; if(!sub || !sub->parent){ return NULL; } if(sub->children || sub->subs){ return NULL; } parent = sub->parent; hier = sub->parent->children; while(hier){ if(hier == sub){ if(last){ last->next = hier->next; }else{ parent->children = hier->next; } _mosquitto_free(sub->topic); _mosquitto_free(sub); break; } last = hier; hier = hier->next; } if(parent->subs == NULL && parent->children == NULL && parent->retained == NULL && parent->parent){ return parent; }else{ return NULL; } } /* Remove all subscriptions for a client. */ int mqtt3_subs_clean_session(struct mosquitto_db *db, struct mosquitto *context) { int i; struct _mosquitto_subleaf *leaf; struct _mosquitto_subhier *hier; for(i=0; isub_count; i++){ if(context->subs[i] == NULL){ continue; } leaf = context->subs[i]->subs; while(leaf){ if(leaf->context==context){ #ifdef WITH_SYS_TREE db->subscription_count--; #endif if(leaf->prev){ leaf->prev->next = leaf->next; }else{ context->subs[i]->subs = leaf->next; } if(leaf->next){ leaf->next->prev = leaf->prev; } _mosquitto_free(leaf); break; } leaf = leaf->next; } if(context->subs[i]->subs == NULL && context->subs[i]->children == NULL && context->subs[i]->retained == NULL && context->subs[i]->parent){ hier = context->subs[i]; context->subs[i] = NULL; do{ hier = tmp_remove_subs(hier); }while(hier); } } _mosquitto_free(context->subs); context->subs = NULL; context->sub_count = 0; return MOSQ_ERR_SUCCESS; } void mqtt3_sub_tree_print(struct _mosquitto_subhier *root, int level) { int i; struct _mosquitto_subhier *branch; struct _mosquitto_subleaf *leaf; for(i=0; itopic); leaf = root->subs; while(leaf){ if(leaf->context){ printf(" (%s, %d)", leaf->context->id, leaf->qos); }else{ printf(" (%s, %d)", "", leaf->qos); } leaf = leaf->next; } if(root->retained){ printf(" (r)"); } printf("\n"); branch = root->children; while(branch){ mqtt3_sub_tree_print(branch, level+1); branch = branch->next; } } static int _retain_process(struct mosquitto_db *db, struct mosquitto_msg_store *retained, struct mosquitto *context, const char *sub, int sub_qos) { int rc = 0; int qos; uint16_t mid; rc = mosquitto_acl_check(db, context, retained->topic, MOSQ_ACL_READ); if(rc == MOSQ_ERR_ACL_DENIED){ return MOSQ_ERR_SUCCESS; }else if(rc != MOSQ_ERR_SUCCESS){ return rc; } if (db->config->upgrade_outgoing_qos){ qos = sub_qos; } else { qos = retained->qos; if(qos > sub_qos) qos = sub_qos; } if(qos > 0){ mid = _mosquitto_mid_generate(context); }else{ mid = 0; } return mqtt3_db_message_insert(db, context, mid, mosq_md_out, qos, true, retained); } static int _retain_search(struct mosquitto_db *db, struct _mosquitto_subhier *subhier, struct _sub_token *tokens, struct mosquitto *context, const char *sub, int sub_qos, int level) { struct _mosquitto_subhier *branch; int flag = 0; branch = subhier->children; while(branch){ /* Subscriptions with wildcards in aren't really valid topics to publish to * so they can't have retained messages. */ if(!strcmp(tokens->topic, "#") && !tokens->next){ /* Set flag to indicate that we should check for retained messages * on "foo" when we are subscribing to e.g. "foo/#" and then exit * this function and return to an earlier _retain_search(). */ flag = -1; if(branch->retained){ _retain_process(db, branch->retained, context, sub, sub_qos); } if(branch->children){ _retain_search(db, branch, tokens, context, sub, sub_qos, level+1); } }else if(strcmp(branch->topic, "+") && (!strcmp(branch->topic, tokens->topic) || !strcmp(tokens->topic, "+"))){ if(tokens->next){ if(_retain_search(db, branch, tokens->next, context, sub, sub_qos, level+1) == -1 || (!branch->next && tokens->next && !strcmp(tokens->next->topic, "#") && level>0)){ if(branch->retained){ _retain_process(db, branch->retained, context, sub, sub_qos); } } }else{ if(branch->retained){ _retain_process(db, branch->retained, context, sub, sub_qos); } } } branch = branch->next; } return flag; } int mqtt3_retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos) { struct _mosquitto_subhier *subhier; struct _sub_token *tokens = NULL, *tail; assert(db); assert(context); assert(sub); if(_sub_topic_tokenise(sub, &tokens)) return 1; subhier = db->subs.children; while(subhier){ if(!strcmp(subhier->topic, tokens->topic)){ _retain_search(db, subhier, tokens, context, sub, sub_qos, 0); break; } subhier = subhier->next; } while(tokens){ tail = tokens->next; _mosquitto_free(tokens->topic); _mosquitto_free(tokens); tokens = tail; } return MOSQ_ERR_SUCCESS; } mosquitto-1.4.15/src/mosquitto.c0000664000175000017500000002665313245550210015676 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #ifndef WIN32 /* For initgroups() */ # define _BSD_SOURCE # include # include # include #endif #ifndef WIN32 #include #else #include #include #include #endif #ifndef WIN32 # include #endif #include #include #include #include #ifdef WITH_WRAP #include #endif #ifdef WITH_WEBSOCKETS # include #endif #include #include #include "util_mosq.h" struct mosquitto_db int_db; bool flag_reload = false; #ifdef WITH_PERSISTENCE bool flag_db_backup = false; #endif bool flag_tree_print = false; int run; #ifdef WITH_WRAP #include int allow_severity = LOG_INFO; int deny_severity = LOG_INFO; #endif void handle_sigint(int signal); void handle_sigusr1(int signal); void handle_sigusr2(int signal); struct mosquitto_db *_mosquitto_get_db(void) { return &int_db; } /* mosquitto shouldn't run as root. * This function will attempt to change to an unprivileged user and group if * running as root. The user is given in config->user. * Returns 1 on failure (unknown user, setuid/setgid failure) * Returns 0 on success. * Note that setting config->user to "root" does not produce an error, but it * strongly discouraged. */ int drop_privileges(struct mqtt3_config *config, bool temporary) { #if !defined(__CYGWIN__) && !defined(WIN32) struct passwd *pwd; char err[256]; int rc; if(geteuid() == 0){ if(config->user && strcmp(config->user, "root")){ pwd = getpwnam(config->user); if(!pwd){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid user '%s'.", config->user); return 1; } if(initgroups(config->user, pwd->pw_gid) == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error setting groups whilst dropping privileges: %s.", err); return 1; } if(temporary){ rc = setegid(pwd->pw_gid); }else{ rc = setgid(pwd->pw_gid); } if(rc == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error setting gid whilst dropping privileges: %s.", err); return 1; } if(temporary){ rc = seteuid(pwd->pw_uid); }else{ rc = setuid(pwd->pw_uid); } if(rc == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error setting uid whilst dropping privileges: %s.", err); return 1; } } if(geteuid() == 0 || getegid() == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Mosquitto should not be run as root/administrator."); } } #endif return MOSQ_ERR_SUCCESS; } int restore_privileges(void) { #if !defined(__CYGWIN__) && !defined(WIN32) char err[256]; int rc; if(getuid() == 0){ rc = setegid(0); if(rc == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error setting gid whilst restoring privileges: %s.", err); return 1; } rc = seteuid(0); if(rc == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error setting uid whilst restoring privileges: %s.", err); return 1; } } #endif return MOSQ_ERR_SUCCESS; } #ifdef SIGHUP /* Signal handler for SIGHUP - flag a config reload. */ void handle_sighup(int signal) { flag_reload = true; } #endif /* Signal handler for SIGINT and SIGTERM - just stop gracefully. */ void handle_sigint(int signal) { run = 0; } /* Signal handler for SIGUSR1 - backup the db. */ void handle_sigusr1(int signal) { #ifdef WITH_PERSISTENCE flag_db_backup = true; #endif } void mosquitto__daemonise(void) { #ifndef WIN32 char err[256]; pid_t pid; pid = fork(); if(pid < 0){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error in fork: %s", err); exit(1); } if(pid > 0){ exit(0); } if(setsid() < 0){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error in setsid: %s", err); exit(1); } assert(freopen("/dev/null", "r", stdin)); assert(freopen("/dev/null", "w", stdout)); assert(freopen("/dev/null", "w", stderr)); #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Can't start in daemon mode in Windows."); #endif } /* Signal handler for SIGUSR2 - vacuum the db. */ void handle_sigusr2(int signal) { flag_tree_print = true; } int main(int argc, char *argv[]) { mosq_sock_t *listensock = NULL; int listensock_count = 0; int listensock_index = 0; struct mqtt3_config config; #ifdef WITH_SYS_TREE char buf[1024]; #endif int i, j; FILE *pid; int listener_max; int rc; #ifdef WIN32 SYSTEMTIME st; #else struct timeval tv; #endif struct mosquitto *ctxt, *ctxt_tmp; #if defined(WIN32) || defined(__CYGWIN__) if(argc == 2){ if(!strcmp(argv[1], "run")){ service_run(); return 0; }else if(!strcmp(argv[1], "install")){ service_install(); return 0; }else if(!strcmp(argv[1], "uninstall")){ service_uninstall(); return 0; } } #endif #ifdef WIN32 GetSystemTime(&st); srand(st.wSecond + st.wMilliseconds); #else gettimeofday(&tv, NULL); srand(tv.tv_sec + tv.tv_usec); #endif memset(&int_db, 0, sizeof(struct mosquitto_db)); _mosquitto_net_init(); mqtt3_config_init(&int_db, &config); rc = mqtt3_config_parse_args(&int_db, &config, argc, argv); if(rc != MOSQ_ERR_SUCCESS) return rc; int_db.config = &config; if(config.daemon){ mosquitto__daemonise(); } if(config.daemon && config.pid_file){ pid = _mosquitto_fopen(config.pid_file, "wt", false); if(pid){ fprintf(pid, "%d", getpid()); fclose(pid); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to write pid file."); return 1; } } rc = mqtt3_db_open(&config, &int_db); if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Couldn't open database."); return rc; } /* Initialise logging only after initialising the database in case we're * logging to topics */ if(mqtt3_log_init(&config)){ rc = 1; return rc; } _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "mosquitto version %s (build date %s) starting", VERSION, TIMESTAMP); if(int_db.config_file){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Config loaded from %s.", int_db.config_file); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Using default config."); } rc = mosquitto_security_module_init(&int_db); if(rc) return rc; rc = mosquitto_security_init(&int_db, false); if(rc) return rc; #ifdef WITH_SYS_TREE if(config.sys_interval > 0){ /* Set static $SYS messages */ snprintf(buf, 1024, "mosquitto version %s", VERSION); mqtt3_db_messages_easy_queue(&int_db, NULL, "$SYS/broker/version", 2, strlen(buf), buf, 1); snprintf(buf, 1024, "%s", TIMESTAMP); mqtt3_db_messages_easy_queue(&int_db, NULL, "$SYS/broker/timestamp", 2, strlen(buf), buf, 1); } #endif listener_max = -1; listensock_index = 0; for(i=0; i listener_max){ listener_max = listensock[listensock_index]; } listensock_index++; } }else if(config.listeners[i].protocol == mp_websockets){ #ifdef WITH_WEBSOCKETS config.listeners[i].ws_context = mosq_websockets_init(&config.listeners[i], config.websockets_log_level); if(!config.listeners[i].ws_context){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create websockets listener on port %d.", config.listeners[i].port); return 1; } #endif } } rc = drop_privileges(&config, false); if(rc != MOSQ_ERR_SUCCESS) return rc; signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); #ifdef SIGHUP signal(SIGHUP, handle_sighup); #endif #ifndef WIN32 signal(SIGUSR1, handle_sigusr1); signal(SIGUSR2, handle_sigusr2); signal(SIGPIPE, SIG_IGN); #endif #ifdef WITH_BRIDGE for(i=0; ilistener_count; i++){ if(int_db.config->listeners[i].ws_context){ libwebsocket_context_destroy(int_db.config->listeners[i].ws_context); } if(int_db.config->listeners[i].ws_protocol){ _mosquitto_free(int_db.config->listeners[i].ws_protocol); } } #endif HASH_ITER(hh_id, int_db.contexts_by_id, ctxt, ctxt_tmp){ mqtt3_context_send_will(&int_db, ctxt); } #ifdef WITH_PERSISTENCE if(config.persistence){ mqtt3_db_backup(&int_db, true); } #endif HASH_ITER(hh_id, int_db.contexts_by_id, ctxt, ctxt_tmp){ #ifdef WITH_WEBSOCKETS if(!ctxt->wsi){ mqtt3_context_cleanup(&int_db, ctxt, true); } #else mqtt3_context_cleanup(&int_db, ctxt, true); #endif } HASH_ITER(hh_sock, int_db.contexts_by_sock, ctxt, ctxt_tmp){ mqtt3_context_cleanup(&int_db, ctxt, true); } #ifdef WITH_BRIDGE for(i=0; i 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 #ifdef WITH_PERSISTENCE #ifndef WIN32 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "util_mosq.h" static uint32_t db_version; static int _db_restore_sub(struct mosquitto_db *db, const char *client_id, const char *sub, int qos); static struct mosquitto *_db_find_or_add_context(struct mosquitto_db *db, const char *client_id, uint16_t last_mid) { struct mosquitto *context; context = NULL; HASH_FIND(hh_id, db->contexts_by_id, client_id, strlen(client_id), context); if(!context){ context = mqtt3_context_init(db, -1); if(!context) return NULL; context->id = _mosquitto_strdup(client_id); if(!context->id){ _mosquitto_free(context); return NULL; } context->clean_session = false; HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, context->id, strlen(context->id), context); } if(last_mid){ context->last_mid = last_mid; } return context; } static int mqtt3_db_client_messages_write(struct mosquitto_db *db, FILE *db_fptr, struct mosquitto *context) { uint32_t length; dbid_t i64temp; uint16_t i16temp, slen; uint8_t i8temp; struct mosquitto_client_msg *cmsg; assert(db); assert(db_fptr); assert(context); cmsg = context->msgs; while(cmsg){ if(!strncmp(cmsg->store->topic, "$SYS", 4) && cmsg->store->ref_count <= 1 && cmsg->store->dest_id_count == 0){ /* This $SYS message won't have been persisted, so we can't persist * this client message. */ cmsg = cmsg->next; continue; } slen = strlen(context->id); length = htonl(sizeof(dbid_t) + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + 2+slen); i16temp = htons(DB_CHUNK_CLIENT_MSG); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, context->id, slen); i64temp = cmsg->store->db_id; write_e(db_fptr, &i64temp, sizeof(dbid_t)); i16temp = htons(cmsg->mid); write_e(db_fptr, &i16temp, sizeof(uint16_t)); i8temp = (uint8_t )cmsg->qos; write_e(db_fptr, &i8temp, sizeof(uint8_t)); i8temp = (uint8_t )cmsg->retain; write_e(db_fptr, &i8temp, sizeof(uint8_t)); i8temp = (uint8_t )cmsg->direction; write_e(db_fptr, &i8temp, sizeof(uint8_t)); i8temp = (uint8_t )cmsg->state; write_e(db_fptr, &i8temp, sizeof(uint8_t)); i8temp = (uint8_t )cmsg->dup; write_e(db_fptr, &i8temp, sizeof(uint8_t)); cmsg = cmsg->next; } return MOSQ_ERR_SUCCESS; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); return 1; } static int mqtt3_db_message_store_write(struct mosquitto_db *db, FILE *db_fptr) { uint32_t length; dbid_t i64temp; uint32_t i32temp; uint16_t i16temp, slen, tlen; uint8_t i8temp; struct mosquitto_msg_store *stored; bool force_no_retain; assert(db); assert(db_fptr); stored = db->msg_store; while(stored){ if(stored->topic && !strncmp(stored->topic, "$SYS", 4)){ if(stored->ref_count <= 1 && stored->dest_id_count == 0){ /* $SYS messages that are only retained shouldn't be persisted. */ stored = stored->next; continue; } /* Don't save $SYS messages as retained otherwise they can give * misleading information when reloaded. They should still be saved * because a disconnected durable client may have them in their * queue. */ force_no_retain = true; }else{ force_no_retain = false; } if(stored->topic){ tlen = strlen(stored->topic); }else{ tlen = 0; } length = htonl(sizeof(dbid_t) + 2+strlen(stored->source_id) + sizeof(uint16_t) + sizeof(uint16_t) + 2+tlen + sizeof(uint32_t) + stored->payloadlen + sizeof(uint8_t) + sizeof(uint8_t)); i16temp = htons(DB_CHUNK_MSG_STORE); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); i64temp = stored->db_id; write_e(db_fptr, &i64temp, sizeof(dbid_t)); slen = strlen(stored->source_id); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); if(slen){ write_e(db_fptr, stored->source_id, slen); } i16temp = htons(stored->source_mid); write_e(db_fptr, &i16temp, sizeof(uint16_t)); i16temp = htons(stored->mid); write_e(db_fptr, &i16temp, sizeof(uint16_t)); i16temp = htons(tlen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); if(tlen){ write_e(db_fptr, stored->topic, tlen); } i8temp = (uint8_t )stored->qos; write_e(db_fptr, &i8temp, sizeof(uint8_t)); if(force_no_retain == false){ i8temp = (uint8_t )stored->retain; }else{ i8temp = 0; } write_e(db_fptr, &i8temp, sizeof(uint8_t)); i32temp = htonl(stored->payloadlen); write_e(db_fptr, &i32temp, sizeof(uint32_t)); if(stored->payloadlen){ write_e(db_fptr, stored->payload, (unsigned int)stored->payloadlen); } stored = stored->next; } return MOSQ_ERR_SUCCESS; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); return 1; } static int mqtt3_db_client_write(struct mosquitto_db *db, FILE *db_fptr) { struct mosquitto *context, *ctxt_tmp; uint16_t i16temp, slen; uint32_t length; time_t disconnect_t; assert(db); assert(db_fptr); HASH_ITER(hh_id, db->contexts_by_id, context, ctxt_tmp){ if(context && context->clean_session == false){ length = htonl(2+strlen(context->id) + sizeof(uint16_t) + sizeof(time_t)); i16temp = htons(DB_CHUNK_CLIENT); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); slen = strlen(context->id); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, context->id, slen); i16temp = htons(context->last_mid); write_e(db_fptr, &i16temp, sizeof(uint16_t)); if(context->disconnect_t){ disconnect_t = context->disconnect_t; }else{ disconnect_t = time(NULL); } write_e(db_fptr, &disconnect_t, sizeof(time_t)); if(mqtt3_db_client_messages_write(db, db_fptr, context)) return 1; } } return MOSQ_ERR_SUCCESS; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); return 1; } static int _db_subs_retain_write(struct mosquitto_db *db, FILE *db_fptr, struct _mosquitto_subhier *node, const char *topic, int level) { struct _mosquitto_subhier *subhier; struct _mosquitto_subleaf *sub; char *thistopic; uint32_t length; uint16_t i16temp; uint8_t i8temp; dbid_t i64temp; size_t slen; slen = strlen(topic) + strlen(node->topic) + 2; thistopic = _mosquitto_malloc(sizeof(char)*slen); if(!thistopic) return MOSQ_ERR_NOMEM; if(level > 1 || strlen(topic)){ snprintf(thistopic, slen, "%s/%s", topic, node->topic); }else{ snprintf(thistopic, slen, "%s", node->topic); } sub = node->subs; while(sub){ if(sub->context->clean_session == false){ length = htonl(2+strlen(sub->context->id) + 2+strlen(thistopic) + sizeof(uint8_t)); i16temp = htons(DB_CHUNK_SUB); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); slen = strlen(sub->context->id); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, sub->context->id, slen); slen = strlen(thistopic); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, thistopic, slen); i8temp = (uint8_t )sub->qos; write_e(db_fptr, &i8temp, sizeof(uint8_t)); } sub = sub->next; } if(node->retained){ if(strncmp(node->retained->topic, "$SYS", 4)){ /* Don't save $SYS messages. */ length = htonl(sizeof(dbid_t)); i16temp = htons(DB_CHUNK_RETAIN); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); i64temp = node->retained->db_id; write_e(db_fptr, &i64temp, sizeof(dbid_t)); } } subhier = node->children; while(subhier){ _db_subs_retain_write(db, db_fptr, subhier, thistopic, level+1); subhier = subhier->next; } _mosquitto_free(thistopic); return MOSQ_ERR_SUCCESS; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); return 1; } static int mqtt3_db_subs_retain_write(struct mosquitto_db *db, FILE *db_fptr) { struct _mosquitto_subhier *subhier; subhier = db->subs.children; while(subhier){ if(subhier->children){ _db_subs_retain_write(db, db_fptr, subhier->children, "", 0); } subhier = subhier->next; } return MOSQ_ERR_SUCCESS; } int mqtt3_db_backup(struct mosquitto_db *db, bool shutdown) { int rc = 0; FILE *db_fptr = NULL; uint32_t db_version_w = htonl(MOSQ_DB_VERSION); uint32_t crc = htonl(0); dbid_t i64temp; uint32_t i32temp; uint16_t i16temp; uint8_t i8temp; char err[256]; char *outfile = NULL; int len; if(!db || !db->config || !db->config->persistence_filepath) return MOSQ_ERR_INVAL; _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Saving in-memory database to %s.", db->config->persistence_filepath); len = strlen(db->config->persistence_filepath)+5; outfile = _mosquitto_malloc(len+1); if(!outfile){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Error saving in-memory database, out of memory."); return MOSQ_ERR_NOMEM; } snprintf(outfile, len, "%s.new", db->config->persistence_filepath); outfile[len] = '\0'; #ifndef WIN32 /** * * If a system lost power during the rename operation at the * end of this file the filesystem could potentially be left * with a directory that looks like this after powerup: * * 24094 -rw-r--r-- 2 root root 4099 May 30 16:27 mosquitto.db * 24094 -rw-r--r-- 2 root root 4099 May 30 16:27 mosquitto.db.new * * The 24094 shows that mosquitto.db.new is hard-linked to the * same file as mosquitto.db. If fopen(outfile, "wb") is naively * called then mosquitto.db will be truncated and the database * potentially corrupted. * * Any existing mosquitto.db.new file must be removed prior to * opening to guarantee that it is not hard-linked to * mosquitto.db. * */ rc = unlink(outfile); if (rc != 0) { if (errno != ENOENT) { _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Error saving in-memory database, unable to remove %s.", outfile); goto error; } } #endif db_fptr = _mosquitto_fopen(outfile, "wb", true); if(db_fptr == NULL){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Error saving in-memory database, unable to open %s for writing.", outfile); goto error; } /* Header */ write_e(db_fptr, magic, 15); write_e(db_fptr, &crc, sizeof(uint32_t)); write_e(db_fptr, &db_version_w, sizeof(uint32_t)); /* DB config */ i16temp = htons(DB_CHUNK_CFG); write_e(db_fptr, &i16temp, sizeof(uint16_t)); /* chunk length */ i32temp = htonl(sizeof(dbid_t) + sizeof(uint8_t) + sizeof(uint8_t)); write_e(db_fptr, &i32temp, sizeof(uint32_t)); /* db written at broker shutdown or not */ i8temp = shutdown; write_e(db_fptr, &i8temp, sizeof(uint8_t)); i8temp = sizeof(dbid_t); write_e(db_fptr, &i8temp, sizeof(uint8_t)); /* last db mid */ i64temp = db->last_db_id; write_e(db_fptr, &i64temp, sizeof(dbid_t)); if(mqtt3_db_message_store_write(db, db_fptr)){ goto error; } mqtt3_db_client_write(db, db_fptr); mqtt3_db_subs_retain_write(db, db_fptr); #ifndef WIN32 /** * * Closing a file does not guarantee that the contents are * written to disk. Need to flush to send data from app to OS * buffers, then fsync to deliver data from OS buffers to disk * (as well as disk hardware permits). * * man close (http://linux.die.net/man/2/close, 2016-06-20): * * "successful close does not guarantee that the data has * been successfully saved to disk, as the kernel defers * writes. It is not common for a filesystem to flush * the buffers when the stream is closed. If you need * to be sure that the data is physically stored, use * fsync(2). (It will depend on the disk hardware at this * point." * * This guarantees that the new state file will not overwrite * the old state file before its contents are valid. * */ fflush(db_fptr); fsync(fileno(db_fptr)); #endif fclose(db_fptr); #ifdef WIN32 if(remove(db->config->persistence_filepath) != 0){ if(errno != ENOENT){ goto error; } } #endif if(rename(outfile, db->config->persistence_filepath) != 0){ goto error; } _mosquitto_free(outfile); outfile = NULL; return rc; error: if(outfile) _mosquitto_free(outfile); strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); if(db_fptr) fclose(db_fptr); return 1; } static int _db_client_msg_restore(struct mosquitto_db *db, const char *client_id, uint16_t mid, uint8_t qos, uint8_t retain, uint8_t direction, uint8_t state, uint8_t dup, uint64_t store_id) { struct mosquitto_client_msg *cmsg; struct mosquitto_msg_store_load *load; struct mosquitto *context; cmsg = _mosquitto_malloc(sizeof(struct mosquitto_client_msg)); if(!cmsg){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } cmsg->next = NULL; cmsg->store = NULL; cmsg->mid = mid; cmsg->qos = qos; cmsg->retain = retain; cmsg->timestamp = 0; cmsg->direction = direction; cmsg->state = state; cmsg->dup = dup; HASH_FIND(hh, db->msg_store_load, &store_id, sizeof(dbid_t), load); if(!load){ _mosquitto_free(cmsg); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error restoring persistent database, message store corrupt."); return 1; } cmsg->store = load->store; cmsg->store->ref_count++; context = _db_find_or_add_context(db, client_id, 0); if(!context){ _mosquitto_free(cmsg); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error restoring persistent database, message store corrupt."); return 1; } if(context->msgs){ context->last_msg->next = cmsg; }else{ context->msgs = cmsg; } context->last_msg = cmsg; return MOSQ_ERR_SUCCESS; } static int _db_client_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) { uint16_t i16temp, slen, last_mid; char *client_id = NULL; int rc = 0; struct mosquitto *context; time_t disconnect_t; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(!slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Corrupt persistent database."); fclose(db_fptr); return 1; } client_id = _mosquitto_malloc(slen+1); if(!client_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, client_id, slen); client_id[slen] = '\0'; read_e(db_fptr, &i16temp, sizeof(uint16_t)); last_mid = ntohs(i16temp); if(db_version == 2){ disconnect_t = time(NULL); }else{ read_e(db_fptr, &disconnect_t, sizeof(time_t)); } context = _db_find_or_add_context(db, client_id, last_mid); if(context){ context->disconnect_t = disconnect_t; }else{ rc = 1; } _mosquitto_free(client_id); return rc; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); if(client_id) _mosquitto_free(client_id); return 1; } static int _db_client_msg_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; uint16_t i16temp, slen, mid; uint8_t qos, retain, direction, state, dup; char *client_id = NULL; int rc; char err[256]; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(!slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Corrupt persistent database."); fclose(db_fptr); return 1; } client_id = _mosquitto_malloc(slen+1); if(!client_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, client_id, slen); client_id[slen] = '\0'; read_e(db_fptr, &i64temp, sizeof(dbid_t)); store_id = i64temp; read_e(db_fptr, &i16temp, sizeof(uint16_t)); mid = ntohs(i16temp); read_e(db_fptr, &qos, sizeof(uint8_t)); read_e(db_fptr, &retain, sizeof(uint8_t)); read_e(db_fptr, &direction, sizeof(uint8_t)); read_e(db_fptr, &state, sizeof(uint8_t)); read_e(db_fptr, &dup, sizeof(uint8_t)); rc = _db_client_msg_restore(db, client_id, mid, qos, retain, direction, state, dup, store_id); _mosquitto_free(client_id); return rc; error: strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); fclose(db_fptr); if(client_id) _mosquitto_free(client_id); return 1; } static int _db_msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; uint32_t i32temp, payloadlen; uint16_t i16temp, slen, source_mid; uint8_t qos, retain, *payload = NULL; char *source_id = NULL; char *topic = NULL; int rc = 0; struct mosquitto_msg_store *stored = NULL; struct mosquitto_msg_store_load *load; char err[256]; load = _mosquitto_malloc(sizeof(struct mosquitto_msg_store_load)); if(!load){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, &i64temp, sizeof(dbid_t)); store_id = i64temp; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ source_id = _mosquitto_malloc(slen+1); if(!source_id){ _mosquitto_free(load); fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, source_id, slen); source_id[slen] = '\0'; } read_e(db_fptr, &i16temp, sizeof(uint16_t)); source_mid = ntohs(i16temp); /* This is the mid - don't need it */ read_e(db_fptr, &i16temp, sizeof(uint16_t)); read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ topic = _mosquitto_malloc(slen+1); if(!topic){ _mosquitto_free(load); fclose(db_fptr); if(source_id) _mosquitto_free(source_id); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, topic, slen); topic[slen] = '\0'; }else{ topic = NULL; } read_e(db_fptr, &qos, sizeof(uint8_t)); read_e(db_fptr, &retain, sizeof(uint8_t)); read_e(db_fptr, &i32temp, sizeof(uint32_t)); payloadlen = ntohl(i32temp); if(payloadlen){ payload = _mosquitto_malloc(payloadlen); if(!payload){ _mosquitto_free(load); fclose(db_fptr); if(source_id) _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, payload, payloadlen); } rc = mqtt3_db_message_store(db, source_id, source_mid, topic, qos, payloadlen, payload, retain, &stored, store_id); load->db_id = stored->db_id; load->store = stored; HASH_ADD(hh, db->msg_store_load, db_id, sizeof(dbid_t), load); if(source_id) _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_free(payload); return rc; error: strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); fclose(db_fptr); if(source_id) _mosquitto_free(source_id); if(topic) _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return 1; } static int _db_retain_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; struct mosquitto_msg_store_load *load; char err[256]; if(fread(&i64temp, sizeof(dbid_t), 1, db_fptr) != 1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); fclose(db_fptr); return 1; } store_id = i64temp; HASH_FIND(hh, db->msg_store_load, &store_id, sizeof(dbid_t), load); if(load){ mqtt3_db_messages_queue(db, NULL, load->store->topic, load->store->qos, load->store->retain, &load->store); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Corrupt database whilst restoring a retained message."); return MOSQ_ERR_INVAL; } return MOSQ_ERR_SUCCESS; } static int _db_sub_chunk_restore(struct mosquitto_db *db, FILE *db_fptr) { uint16_t i16temp, slen; uint8_t qos; char *client_id; char *topic; int rc = 0; char err[256]; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); client_id = _mosquitto_malloc(slen+1); if(!client_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, client_id, slen); client_id[slen] = '\0'; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); topic = _mosquitto_malloc(slen+1); if(!topic){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); _mosquitto_free(client_id); return MOSQ_ERR_NOMEM; } read_e(db_fptr, topic, slen); topic[slen] = '\0'; read_e(db_fptr, &qos, sizeof(uint8_t)); if(_db_restore_sub(db, client_id, topic, qos)){ rc = 1; } _mosquitto_free(client_id); _mosquitto_free(topic); return rc; error: strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); fclose(db_fptr); return 1; } int mqtt3_db_restore(struct mosquitto_db *db) { FILE *fptr; char header[15]; int rc = 0; uint32_t crc; dbid_t i64temp; uint32_t i32temp, length; uint16_t i16temp, chunk; uint8_t i8temp; ssize_t rlen; char err[256]; struct mosquitto_msg_store_load *load, *load_tmp; assert(db); assert(db->config); assert(db->config->persistence_filepath); db->msg_store_load = NULL; fptr = _mosquitto_fopen(db->config->persistence_filepath, "rb", false); if(fptr == NULL) return MOSQ_ERR_SUCCESS; rlen = fread(&header, 1, 15, fptr); if(rlen == 0){ fclose(fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Persistence file is empty."); return 0; }else if(rlen != 15){ goto error; } if(!memcmp(header, magic, 15)){ // Restore DB as normal read_e(fptr, &crc, sizeof(uint32_t)); read_e(fptr, &i32temp, sizeof(uint32_t)); db_version = ntohl(i32temp); /* IMPORTANT - this is where compatibility checks are made. * Is your DB change still compatible with previous versions? */ if(db_version > MOSQ_DB_VERSION && db_version != 0){ if(db_version == 2){ /* Addition of disconnect_t to client chunk in v3. */ }else{ fclose(fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unsupported persistent database format version %d (need version %d).", db_version, MOSQ_DB_VERSION); return 1; } } while(rlen = fread(&i16temp, sizeof(uint16_t), 1, fptr), rlen == 1){ chunk = ntohs(i16temp); read_e(fptr, &i32temp, sizeof(uint32_t)); length = ntohl(i32temp); switch(chunk){ case DB_CHUNK_CFG: read_e(fptr, &i8temp, sizeof(uint8_t)); // shutdown read_e(fptr, &i8temp, sizeof(uint8_t)); // sizeof(dbid_t) if(i8temp != sizeof(dbid_t)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Incompatible database configuration (dbid size is %d bytes, expected %lu)", i8temp, (unsigned long)sizeof(dbid_t)); fclose(fptr); return 1; } read_e(fptr, &i64temp, sizeof(dbid_t)); db->last_db_id = i64temp; break; case DB_CHUNK_MSG_STORE: if(_db_msg_store_chunk_restore(db, fptr)) return 1; break; case DB_CHUNK_CLIENT_MSG: if(_db_client_msg_chunk_restore(db, fptr)) return 1; break; case DB_CHUNK_RETAIN: if(_db_retain_chunk_restore(db, fptr)) return 1; break; case DB_CHUNK_SUB: if(_db_sub_chunk_restore(db, fptr)) return 1; break; case DB_CHUNK_CLIENT: if(_db_client_chunk_restore(db, fptr)) return 1; break; default: _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Unsupported chunk \"%d\" in persistent database file. Ignoring.", chunk); fseek(fptr, length, SEEK_CUR); break; } } if(rlen < 0) goto error; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to restore persistent database. Unrecognised file format."); rc = 1; } fclose(fptr); HASH_ITER(hh, db->msg_store_load, load, load_tmp){ HASH_DELETE(hh, db->msg_store_load, load); _mosquitto_free(load); } return rc; error: strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", err); if(fptr) fclose(fptr); return 1; } static int _db_restore_sub(struct mosquitto_db *db, const char *client_id, const char *sub, int qos) { struct mosquitto *context; assert(db); assert(client_id); assert(sub); context = _db_find_or_add_context(db, client_id, 0); if(!context) return 1; return mqtt3_sub_add(db, context, sub, qos, &db->subs); } #endif mosquitto-1.4.15/src/persist.h0000664000175000017500000000203213245550210015311 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 PERSIST_H #define PERSIST_H #define MOSQ_DB_VERSION 3 /* DB read/write */ const unsigned char magic[15] = {0x00, 0xB5, 0x00, 'm','o','s','q','u','i','t','t','o',' ','d','b'}; #define DB_CHUNK_CFG 1 #define DB_CHUNK_MSG_STORE 2 #define DB_CHUNK_CLIENT_MSG 3 #define DB_CHUNK_RETAIN 4 #define DB_CHUNK_SUB 5 #define DB_CHUNK_CLIENT 6 /* End DB read/write */ #define read_e(f, b, c) if(fread(b, 1, c, f) != c){ goto error; } #define write_e(f, b, c) if(fwrite(b, 1, c, f) != c){ goto error; } #endif mosquitto-1.4.15/src/websockets.c0000664000175000017500000004653513245550210016004 0ustar rogerroger/* Copyright (c) 2014-2018 Roger Light All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of mosquitto nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef WITH_WEBSOCKETS #include #include "mosquitto_internal.h" #include "mosquitto_broker.h" #include "mqtt3_protocol.h" #include "memory_mosq.h" #include #include #include #ifdef WITH_SYS_TREE extern uint64_t g_bytes_received; extern uint64_t g_bytes_sent; extern unsigned long g_msgs_received; extern unsigned long g_msgs_sent; extern unsigned long g_pub_msgs_received; extern unsigned long g_pub_msgs_sent; #endif extern struct mosquitto_db int_db; #if defined(LWS_LIBRARY_VERSION_NUMBER) static int callback_mqtt( #else static int callback_mqtt(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len); #if defined(LWS_LIBRARY_VERSION_NUMBER) static int callback_http( #else static int callback_http(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len); enum mosq_ws_protocols { PROTOCOL_HTTP = 0, PROTOCOL_MQTT, DEMO_PROTOCOL_COUNT }; struct libws_http_data { FILE *fptr; }; #ifndef LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG /* This is libwebsockets 1.2.x or earlier, we have to degrade our capabilities. * Once lws 1.3 is widely available this should be removed. */ # define LWS_IS_OLD # define HTTP_STATUS_FORBIDDEN 403 # define HTTP_STATUS_NOT_FOUND 404 # define HTTP_STATUS_METHOD_NOT_ALLOWED 405 # define HTTP_STATUS_REQ_URI_TOO_LONG 414 # define HTTP_STATUS_INTERNAL_SERVER_ERROR 500 # define libwebsockets_return_http_status(A, B, C, D) #endif static struct libwebsocket_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", callback_http, sizeof (struct libws_http_data), 0, #ifdef LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD 0, #endif NULL, #if !defined(LWS_LIBRARY_VERSION_NUMBER) 0 #endif }, { "mqtt", callback_mqtt, sizeof(struct libws_mqtt_data), 0, #ifdef LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD 1, #endif NULL, #if !defined(LWS_LIBRARY_VERSION_NUMBER) 0 #endif }, { "mqttv3.1", callback_mqtt, sizeof(struct libws_mqtt_data), 0, #ifdef LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD 1, #endif NULL, #if !defined(LWS_LIBRARY_VERSION_NUMBER) 0 #endif }, #ifdef LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD # if defined(LWS_LIBRARY_VERSION_NUMBER) { NULL, NULL, 0, 0, 0, NULL} # else { NULL, NULL, 0, 0, 0, NULL, 0} # endif #else { NULL, NULL, 0, 0, NULL, 0} #endif }; static void easy_address(int sock, struct mosquitto *mosq) { char address[1024]; if(!_mosquitto_socket_get_address(sock, address, 1024)){ mosq->address = _mosquitto_strdup(address); } } #if defined(LWS_LIBRARY_VERSION_NUMBER) static int callback_mqtt( #else static int callback_mqtt(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { struct mosquitto_db *db; struct mosquitto *mosq = NULL; struct _mosquitto_packet *packet; int count, i, j; const struct libwebsocket_protocols *p; struct libws_mqtt_data *u = (struct libws_mqtt_data *)user; size_t pos; uint8_t *buf; int rc; uint8_t byte; db = &int_db; switch (reason) { case LWS_CALLBACK_ESTABLISHED: mosq = mqtt3_context_init(db, WEBSOCKET_CLIENT); if(mosq){ p = libwebsockets_get_protocol(wsi); for (i=0; iconfig->listener_count; i++){ if (db->config->listeners[i].protocol == mp_websockets) { for (j=0; db->config->listeners[i].ws_protocol[j].name; j++){ if (p == &db->config->listeners[i].ws_protocol[j]){ mosq->listener = &db->config->listeners[i]; mosq->listener->client_count++; } } } } if(!mosq->listener){ _mosquitto_free(mosq); return -1; } #if !defined(LWS_LIBRARY_VERSION_NUMBER) mosq->ws_context = context; #endif mosq->wsi = wsi; if(in){ mosq->ssl = (SSL *)in; if(!mosq->listener->ssl_ctx){ mosq->listener->ssl_ctx = SSL_get_SSL_CTX(mosq->ssl); } } u->mosq = mosq; }else{ return -1; } easy_address(libwebsocket_get_socket_fd(wsi), mosq); if(!mosq->address){ /* getpeername and inet_ntop failed and not a bridge */ _mosquitto_free(mosq); u->mosq = NULL; return -1; } if(mosq->listener->max_connections > 0 && mosq->listener->client_count > mosq->listener->max_connections){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address); _mosquitto_free(mosq); u->mosq = NULL; return -1; } mosq->sock = libwebsocket_get_socket_fd(wsi); HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(mosq->sock), mosq); break; case LWS_CALLBACK_CLOSED: if(!u){ return -1; } mosq = u->mosq; if(mosq){ if(mosq->sock > 0){ HASH_DELETE(hh_sock, db->contexts_by_sock, mosq); mosq->sock = INVALID_SOCKET; mosq->pollfd_index = -1; } mosq->wsi = NULL; mosq->ssl = NULL; do_disconnect(db, mosq); } break; case LWS_CALLBACK_SERVER_WRITEABLE: if(!u){ return -1; } mosq = u->mosq; if(!mosq){ return -1; } mqtt3_db_message_write(db, mosq); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } if(mosq->current_out_packet && !lws_send_pipe_choked(mosq->wsi)){ packet = mosq->current_out_packet; if(packet->pos == 0 && packet->to_process == packet->packet_length){ /* First time this packet has been dealt with. * libwebsockets requires that the payload has * LWS_SEND_BUFFER_PRE_PADDING space available before the * actual data and LWS_SEND_BUFFER_POST_PADDING afterwards. * We've already made the payload big enough to allow this, * but need to move it into position here. */ memmove(&packet->payload[LWS_SEND_BUFFER_PRE_PADDING], packet->payload, packet->packet_length); packet->pos += LWS_SEND_BUFFER_PRE_PADDING; } count = libwebsocket_write(wsi, &packet->payload[packet->pos], packet->to_process, LWS_WRITE_BINARY); #ifdef LWS_IS_OLD /* lws < 1.3 doesn't return a valid count, assume everything sent. */ count = packet->to_process; #endif if(count < 0){ if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } return 0; } #ifdef WITH_SYS_TREE g_bytes_sent += count; #endif packet->to_process -= count; packet->pos += count; if(packet->to_process > 0){ if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } break; } #ifdef WITH_SYS_TREE g_msgs_sent++; if(((packet->command)&0xF6) == PUBLISH){ g_pub_msgs_sent++; } #endif /* Free data and reset values */ 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; } } _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); mosq->next_msg_out = mosquitto_time() + mosq->keepalive; } if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } if(mosq->current_out_packet){ libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); } break; case LWS_CALLBACK_RECEIVE: if(!u || !u->mosq){ return -1; } mosq = u->mosq; pos = 0; buf = (uint8_t *)in; #ifdef WITH_SYS_TREE g_bytes_received += len; #endif while(pos < len){ if(!mosq->in_packet.command){ mosq->in_packet.command = buf[pos]; pos++; /* Clients must send CONNECT as their first command. */ if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CONNECT){ return -1; } } if(mosq->in_packet.remaining_count <= 0){ do{ if(pos == len){ return 0; } byte = buf[pos]; pos++; mosq->in_packet.remaining_count--; /* Max 4 bytes length for remaining length as defined by protocol. * Anything more likely means a broken/malicious client. */ if(mosq->in_packet.remaining_count < -4){ return -1; } mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult; mosq->in_packet.remaining_mult *= 128; }while((byte & 128) != 0); mosq->in_packet.remaining_count *= -1; if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = _mosquitto_malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload){ return -1; } mosq->in_packet.to_process = mosq->in_packet.remaining_length; } } if(mosq->in_packet.to_process>0){ if(len - pos >= mosq->in_packet.to_process){ memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], mosq->in_packet.to_process); mosq->in_packet.pos += mosq->in_packet.to_process; pos += mosq->in_packet.to_process; mosq->in_packet.to_process = 0; }else{ memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], len-pos); mosq->in_packet.pos += len-pos; mosq->in_packet.to_process -= len-pos; return 0; } } /* All data for this packet is read. */ mosq->in_packet.pos = 0; #ifdef WITH_SYS_TREE g_msgs_received++; if(((mosq->in_packet.command)&0xF5) == PUBLISH){ g_pub_msgs_received++; } #endif rc = mqtt3_packet_handle(db, mosq); /* Free data and reset values */ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->last_msg_in = mosquitto_time(); if(rc && (mosq->out_packet || mosq->current_out_packet)) { if(mosq->state != mosq_cs_disconnecting){ mosq->state = mosq_cs_disconnect_ws; } libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); } else if (rc) { do_disconnect(db, mosq); return -1; } } break; default: break; } return 0; } #if defined(LWS_LIBRARY_VERSION_NUMBER) static int callback_http( #else static int callback_http(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { struct libws_http_data *u = (struct libws_http_data *)user; struct libws_mqtt_hack *hack; char *http_dir; size_t buflen, slen; #ifndef LWS_IS_OLD size_t wlen; #endif char *filename, *filename_canonical; unsigned char buf[4096]; struct stat filestat; struct mosquitto_db *db = &int_db; struct mosquitto *mosq; struct lws_pollargs *pollargs = (struct lws_pollargs *)in; /* FIXME - ssl cert verification is done here. */ switch (reason) { case LWS_CALLBACK_HTTP: if(!u){ return -1; } #if defined(LWS_LIBRARY_VERSION_NUMBER) hack = (struct libws_mqtt_hack *)lws_context_user(lws_get_context(wsi)); #else hack = (struct libws_mqtt_hack *)libwebsocket_context_user(context); #endif if(!hack){ return -1; } http_dir = hack->http_dir; if(!http_dir){ /* http disabled */ return -1; } #ifndef LWS_IS_OLD /* Forbid POST */ if(lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL); return -1; } #endif if(!strcmp((char *)in, "/")){ slen = strlen(http_dir) + strlen("/index.html") + 2; }else{ slen = strlen(http_dir) + strlen((char *)in) + 2; } filename = _mosquitto_malloc(slen); if(!filename){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); return -1; } if(!strcmp((char *)in, "/")){ snprintf(filename, slen, "%s/index.html", http_dir); }else{ snprintf(filename, slen, "%s%s", http_dir, (char *)in); } /* Get canonical path and check it is within our http_dir */ #ifdef WIN32 filename_canonical = _fullpath(NULL, filename, 0); if(!filename_canonical){ _mosquitto_free(filename); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); return -1; } #else filename_canonical = realpath(filename, NULL); if(!filename_canonical){ _mosquitto_free(filename); if(errno == EACCES){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); }else if(errno == EINVAL || errno == EIO || errno == ELOOP){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); }else if(errno == ENAMETOOLONG){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_REQ_URI_TOO_LONG, NULL); }else if(errno == ENOENT || errno == ENOTDIR){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_NOT_FOUND, NULL); } return -1; } #endif if(strncmp(http_dir, filename_canonical, strlen(http_dir))){ /* Requested file isn't within http_dir, deny access. */ free(filename_canonical); _mosquitto_free(filename); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); return -1; } free(filename_canonical); _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "http serving file \"%s\".", filename); u->fptr = fopen(filename, "rb"); _mosquitto_free(filename); if(!u->fptr){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_NOT_FOUND, NULL); return -1; } if(fstat(fileno(u->fptr), &filestat) < 0){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); fclose(u->fptr); u->fptr = NULL; return -1; } #ifdef WIN32 if((filestat.st_mode & S_IFREG) != S_IFREG){ #else if(!S_ISREG(filestat.st_mode)){ #endif libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); fclose(u->fptr); u->fptr = NULL; return -1; } buflen = snprintf((char *)buf, 4096, "HTTP/1.0 200 OK\r\n" "Server: mosquitto\r\n" "Content-Length: %u\r\n\r\n", (unsigned int)filestat.st_size); if(libwebsocket_write(wsi, buf, buflen, LWS_WRITE_HTTP) < 0){ fclose(u->fptr); u->fptr = NULL; return -1; } libwebsocket_callback_on_writable(context, wsi); break; #ifndef LWS_IS_OLD case LWS_CALLBACK_HTTP_BODY: /* For extra POST data? */ return -1; case LWS_CALLBACK_HTTP_BODY_COMPLETION: /* For end of extra POST data? */ return -1; case LWS_CALLBACK_FILTER_HTTP_CONNECTION: /* Access control here */ return 0; case LWS_CALLBACK_HTTP_WRITEABLE: /* Send our data here */ if(u && u->fptr){ do{ buflen = fread(buf, 1, sizeof(buf), u->fptr); if(buflen < 1){ fclose(u->fptr); u->fptr = NULL; return -1; } wlen = libwebsocket_write(wsi, buf, buflen, LWS_WRITE_HTTP); if(wlen < buflen){ if(fseek(u->fptr, buflen-wlen, SEEK_CUR) < 0){ fclose(u->fptr); u->fptr = NULL; return -1; } }else{ if(buflen < sizeof(buf)){ fclose(u->fptr); u->fptr = NULL; } } }while(u->fptr && !lws_send_pipe_choked(wsi)); libwebsocket_callback_on_writable(context, wsi); }else{ return -1; } break; case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLOSED_HTTP: case LWS_CALLBACK_HTTP_FILE_COMPLETION: if(u && u->fptr){ fclose(u->fptr); u->fptr = NULL; } break; #endif case LWS_CALLBACK_ADD_POLL_FD: case LWS_CALLBACK_DEL_POLL_FD: case LWS_CALLBACK_CHANGE_MODE_POLL_FD: HASH_FIND(hh_sock, db->contexts_by_sock, &pollargs->fd, sizeof(pollargs->fd), mosq); if(mosq && (pollargs->events & POLLOUT)){ mosq->ws_want_write = true; } break; default: return 0; } return 0; } static void log_wrap(int level, const char *line) { char *l = (char *)line; l[strlen(line)-1] = '\0'; // Remove \n _mosquitto_log_printf(NULL, MOSQ_LOG_WEBSOCKETS, "%s", l); } struct libwebsocket_context *mosq_websockets_init(struct _mqtt3_listener *listener, int log_level) { struct lws_context_creation_info info; struct libwebsocket_protocols *p; int protocol_count; int i; struct libws_mqtt_hack *user; /* Count valid protocols */ for(protocol_count=0; protocols[protocol_count].name; protocol_count++); p = _mosquitto_calloc(protocol_count+1, sizeof(struct libwebsocket_protocols)); if(!p){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Out of memory."); return NULL; } for(i=0; protocols[i].name; i++){ p[i].name = protocols[i].name; p[i].callback = protocols[i].callback; p[i].per_session_data_size = protocols[i].per_session_data_size; p[i].rx_buffer_size = protocols[i].rx_buffer_size; } memset(&info, 0, sizeof(info)); info.iface = listener->host; info.port = listener->port; info.protocols = p; info.gid = -1; info.uid = -1; #ifdef WITH_TLS info.ssl_ca_filepath = listener->cafile; info.ssl_cert_filepath = listener->certfile; info.ssl_private_key_filepath = listener->keyfile; #ifndef LWS_IS_OLD info.ssl_cipher_list = listener->ciphers; #endif if(listener->require_certificate){ info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; } #endif #ifndef LWS_IS_OLD info.options |= LWS_SERVER_OPTION_DISABLE_IPV6; #endif #if LWS_LIBRARY_VERSION_MAJOR>1 info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; #endif user = _mosquitto_calloc(1, sizeof(struct libws_mqtt_hack)); if(!user){ _mosquitto_free(p); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Out of memory."); return NULL; } if(listener->http_dir){ #ifdef WIN32 user->http_dir = _fullpath(NULL, listener->http_dir, 0); #else user->http_dir = realpath(listener->http_dir, NULL); #endif if(!user->http_dir){ _mosquitto_free(user); _mosquitto_free(p); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open http dir \"%s\".", listener->http_dir); return NULL; } } info.user = user; listener->ws_protocol = p; lws_set_log_level(log_level, log_wrap); _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening websockets listen socket on port %d.", listener->port); return libwebsocket_create_context(&info); } #endif mosquitto-1.4.15/src/read_handle.c0000664000175000017500000001754613245550210016061 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include #include #include #include #ifdef WITH_SYS_TREE extern uint64_t g_pub_bytes_received; #endif int mqtt3_packet_handle(struct mosquitto_db *db, struct mosquitto *context) { if(!context) return MOSQ_ERR_INVAL; switch((context->in_packet.command)&0xF0){ case PINGREQ: return _mosquitto_handle_pingreq(context); case PINGRESP: return _mosquitto_handle_pingresp(context); case PUBACK: return _mosquitto_handle_pubackcomp(db, context, "PUBACK"); case PUBCOMP: return _mosquitto_handle_pubackcomp(db, context, "PUBCOMP"); case PUBLISH: return mqtt3_handle_publish(db, context); case PUBREC: return _mosquitto_handle_pubrec(context); case PUBREL: return _mosquitto_handle_pubrel(db, context); case CONNECT: return mqtt3_handle_connect(db, context); case DISCONNECT: return mqtt3_handle_disconnect(db, context); case SUBSCRIBE: return mqtt3_handle_subscribe(db, context); case UNSUBSCRIBE: return mqtt3_handle_unsubscribe(db, context); #ifdef WITH_BRIDGE case CONNACK: return mqtt3_handle_connack(db, context); case SUBACK: return _mosquitto_handle_suback(context); case UNSUBACK: return _mosquitto_handle_unsuback(context); #endif default: /* If we don't recognise the command, return an error straight away. */ return MOSQ_ERR_PROTOCOL; } } int mqtt3_handle_publish(struct mosquitto_db *db, struct mosquitto *context) { char *topic; void *payload = NULL; uint32_t payloadlen; uint8_t dup, qos, retain; uint16_t mid = 0; int rc = 0; uint8_t header = context->in_packet.command; int res = 0; struct mosquitto_msg_store *stored = NULL; int len; char *topic_mount; #ifdef WITH_BRIDGE char *topic_temp; int i; struct _mqtt3_bridge_topic *cur_topic; bool match; #endif dup = (header & 0x08)>>3; qos = (header & 0x06)>>1; if(qos == 3){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid QoS in PUBLISH from %s, disconnecting.", context->id); return 1; } retain = (header & 0x01); if(_mosquitto_read_string(&context->in_packet, &topic)) return 1; if(STREMPTY(topic)){ /* Invalid publish topic, disconnect client. */ _mosquitto_free(topic); return 1; } #ifdef WITH_BRIDGE if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ for(i=0; ibridge->topic_count; i++){ cur_topic = &context->bridge->topics[i]; if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) && (cur_topic->remote_prefix || cur_topic->local_prefix)){ /* Topic mapping required on this topic if the message matches */ rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, topic, &match); if(rc){ _mosquitto_free(topic); return rc; } if(match){ if(cur_topic->remote_prefix){ /* This prefix needs removing. */ if(!strncmp(cur_topic->remote_prefix, topic, strlen(cur_topic->remote_prefix))){ topic_temp = _mosquitto_strdup(topic+strlen(cur_topic->remote_prefix)); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } _mosquitto_free(topic); topic = topic_temp; } } if(cur_topic->local_prefix){ /* This prefix needs adding. */ len = strlen(topic) + strlen(cur_topic->local_prefix)+1; topic_temp = _mosquitto_malloc(len+1); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, topic); topic_temp[len] = '\0'; _mosquitto_free(topic); topic = topic_temp; } break; } } } } #endif if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ /* Invalid publish topic, just swallow it. */ _mosquitto_free(topic); return 1; } if(qos > 0){ if(_mosquitto_read_uint16(&context->in_packet, &mid)){ _mosquitto_free(topic); return 1; } } payloadlen = context->in_packet.remaining_length - context->in_packet.pos; #ifdef WITH_SYS_TREE g_pub_bytes_received += payloadlen; #endif if(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + strlen(topic) + 1; topic_mount = _mosquitto_malloc(len+1); if(!topic_mount){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); topic_mount[len] = '\0'; _mosquitto_free(topic); topic = topic_mount; } if(payloadlen){ if(db->config->message_size_limit && payloadlen > db->config->message_size_limit){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Dropped too large PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", context->id, dup, qos, retain, mid, topic, (long)payloadlen); goto process_bad_message; } payload = _mosquitto_calloc(payloadlen+1, 1); if(!payload){ _mosquitto_free(topic); return 1; } if(_mosquitto_read_bytes(&context->in_packet, payload, payloadlen)){ _mosquitto_free(topic); _mosquitto_free(payload); return 1; } } /* Check for topic access */ rc = mosquitto_acl_check(db, context, topic, MOSQ_ACL_WRITE); if(rc == MOSQ_ERR_ACL_DENIED){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Denied PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", context->id, dup, qos, retain, mid, topic, (long)payloadlen); goto process_bad_message; }else if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", context->id, dup, qos, retain, mid, topic, (long)payloadlen); if(qos > 0){ mqtt3_db_message_store_find(context, mid, &stored); } if(!stored){ dup = 0; if(mqtt3_db_message_store(db, context->id, mid, topic, qos, payloadlen, payload, retain, &stored, 0)){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return 1; } }else{ dup = 1; } switch(qos){ case 0: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, &stored)) rc = 1; break; case 1: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, &stored)) rc = 1; if(_mosquitto_send_puback(context, mid)) rc = 1; break; case 2: if(!dup){ res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, retain, stored); }else{ res = 0; } /* mqtt3_db_message_insert() returns 2 to indicate dropped message * due to queue. This isn't an error so don't disconnect them. */ if(!res){ if(_mosquitto_send_pubrec(context, mid)) rc = 1; }else if(res == 1){ rc = 1; } break; } _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; process_bad_message: _mosquitto_free(topic); if(payload) _mosquitto_free(payload); switch(qos){ case 0: return MOSQ_ERR_SUCCESS; case 1: return _mosquitto_send_puback(context, mid); case 2: mqtt3_db_message_store_find(context, mid, &stored); if(!stored){ if(mqtt3_db_message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0)){ return 1; } res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, false, stored); }else{ res = 0; } if(!res){ res = _mosquitto_send_pubrec(context, mid); } return res; } return 1; } mosquitto-1.4.15/src/Makefile0000664000175000017500000001032013245550210015106 0ustar rogerrogerinclude ../config.mk .PHONY: all install uninstall clean reallyclean ifeq ($(WITH_TLS),yes) all : mosquitto mosquitto_passwd else all : mosquitto endif mosquitto : mosquitto.o bridge.o conf.o context.o database.o logging.o loop.o memory_mosq.o persist.o net.o net_mosq.o read_handle.o read_handle_client.o read_handle_server.o read_handle_shared.o security.o security_default.o send_client_mosq.o send_mosq.o send_server.o service.o subs.o sys_tree.o time_mosq.o tls_mosq.o util_mosq.o websockets.o will_mosq.o ${CROSS_COMPILE}${CC} $^ -o $@ ${LDFLAGS} $(BROKER_LIBS) mosquitto.o : mosquitto.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ bridge.o : bridge.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ conf.o : conf.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ context.o : context.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ database.o : database.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ logging.o : logging.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ loop.o : loop.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ memory_mosq.o : ../lib/memory_mosq.c ../lib/memory_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ net.o : net.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ net_mosq.o : ../lib/net_mosq.c ../lib/net_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ persist.o : persist.c persist.h mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ read_handle.o : read_handle.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ read_handle_client.o : read_handle_client.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ read_handle_server.o : read_handle_server.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ read_handle_shared.o : ../lib/read_handle_shared.c ../lib/read_handle.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ security.o : security.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ security_default.o : security_default.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ send_client_mosq.o : ../lib/send_client_mosq.c ../lib/send_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ send_mosq.o : ../lib/send_mosq.c ../lib/send_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ send_server.o : send_server.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ service.o : service.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ subs.o : subs.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ sys_tree.o : sys_tree.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ time_mosq.o : ../lib/time_mosq.c ../lib/time_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ tls_mosq.o : ../lib/tls_mosq.c ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ util_mosq.o : ../lib/util_mosq.c ../lib/util_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ websockets.o : websockets.c mosquitto_broker.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ will_mosq.o : ../lib/will_mosq.c ../lib/will_mosq.h ${CROSS_COMPILE}${CC} $(BROKER_CFLAGS) -c $< -o $@ mosquitto_passwd : mosquitto_passwd.o ${CROSS_COMPILE}${CC} $^ -o $@ ${LDFLAGS} $(PASSWD_LIBS) mosquitto_passwd.o : mosquitto_passwd.c ${CROSS_COMPILE}${CC} $(CFLAGS) ${CPPFLAGS} -c $< -o $@ install : all $(INSTALL) -d ${DESTDIR}$(prefix)/sbin $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} mosquitto ${DESTDIR}${prefix}/sbin/mosquitto $(INSTALL) -d ${DESTDIR}$(prefix)/include $(INSTALL) mosquitto_plugin.h ${DESTDIR}${prefix}/include/mosquitto_plugin.h ifeq ($(WITH_TLS),yes) $(INSTALL) -d ${DESTDIR}$(prefix)/bin $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} mosquitto_passwd ${DESTDIR}${prefix}/bin/mosquitto_passwd endif uninstall : -rm -f ${DESTDIR}${prefix}/sbin/mosquitto -rm -f ${DESTDIR}${prefix}/include/mosquitto_plugin.h -rm -f ${DESTDIR}${prefix}/bin/mosquitto_passwd clean : -rm -f *.o mosquitto mosquitto_passwd reallyclean : clean -rm -rf *.orig *.db mosquitto-1.4.15/src/read_handle_client.c0000664000175000017500000001020113245550210017374 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include #include int mqtt3_handle_connack(struct mosquitto_db *db, struct mosquitto *context) { uint8_t byte; uint8_t rc; int i; char *notification_topic; int notification_topic_len; char notification_payload; if(!context){ return MOSQ_ERR_INVAL; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received CONNACK on connection %s.", context->id); if(_mosquitto_read_byte(&context->in_packet, &byte)) return 1; // Reserved byte, not used if(_mosquitto_read_byte(&context->in_packet, &rc)) return 1; switch(rc){ case CONNACK_ACCEPTED: if(context->bridge){ if(context->bridge->notifications){ notification_payload = '1'; if(context->bridge->notification_topic){ if(_mosquitto_send_real_publish(context, _mosquitto_mid_generate(context), context->bridge->notification_topic, 1, ¬ification_payload, 1, true, 0)){ return 1; } mqtt3_db_messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); }else{ notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state"); notification_topic = _mosquitto_malloc(sizeof(char)*(notification_topic_len+1)); if(!notification_topic) return MOSQ_ERR_NOMEM; snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid); notification_payload = '1'; if(_mosquitto_send_real_publish(context, _mosquitto_mid_generate(context), notification_topic, 1, ¬ification_payload, 1, true, 0)){ _mosquitto_free(notification_topic); return 1; } mqtt3_db_messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); _mosquitto_free(notification_topic); } } for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_in || context->bridge->topics[i].direction == bd_both){ if(_mosquitto_send_subscribe(context, NULL, context->bridge->topics[i].remote_topic, context->bridge->topics[i].qos)){ return 1; } }else{ if(context->bridge->attempt_unsubscribe){ if(_mosquitto_send_unsubscribe(context, NULL, context->bridge->topics[i].remote_topic)){ /* direction = inwards only. This means we should not be subscribed * to the topic. It is possible that we used to be subscribed to * this topic so unsubscribe. */ return 1; } } } } } context->state = mosq_cs_connected; return MOSQ_ERR_SUCCESS; case CONNACK_REFUSED_PROTOCOL_VERSION: if(context->bridge){ context->bridge->try_private_accepted = false; } _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unacceptable protocol version"); return 1; case CONNACK_REFUSED_IDENTIFIER_REJECTED: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Connection Refused: identifier rejected"); return 1; case CONNACK_REFUSED_SERVER_UNAVAILABLE: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable"); return 1; case CONNACK_REFUSED_BAD_USERNAME_PASSWORD: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable"); return 1; case CONNACK_REFUSED_NOT_AUTHORIZED: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Connection Refused: not authorised"); return 1; default: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unknown reason"); return 1; } return 1; } mosquitto-1.4.15/src/bridge.c0000664000175000017500000003515613245550210015064 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #ifndef WIN32 #include #include #else #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_BRIDGE int mqtt3_bridge_new(struct mosquitto_db *db, struct _mqtt3_bridge *bridge) { struct mosquitto *new_context = NULL; struct mosquitto **bridges; char hostname[256]; int len; char *id, *local_id; assert(db); assert(bridge); if(!bridge->remote_clientid){ if(!gethostname(hostname, 256)){ len = strlen(hostname) + strlen(bridge->name) + 2; id = _mosquitto_malloc(len); if(!id){ return MOSQ_ERR_NOMEM; } snprintf(id, len, "%s.%s", hostname, bridge->name); }else{ return 1; } bridge->remote_clientid = id; } if(bridge->local_clientid){ local_id = _mosquitto_strdup(bridge->local_clientid); if(!local_id){ return MOSQ_ERR_NOMEM; } }else{ len = strlen(bridge->remote_clientid) + strlen("local.") + 2; local_id = _mosquitto_malloc(len); if(!local_id){ return MOSQ_ERR_NOMEM; } snprintf(local_id, len, "local.%s", bridge->remote_clientid); bridge->local_clientid = _mosquitto_strdup(local_id); if(!bridge->local_clientid){ _mosquitto_free(local_id); return MOSQ_ERR_NOMEM; } } HASH_FIND(hh_id, db->contexts_by_id, local_id, strlen(local_id), new_context); if(new_context){ /* (possible from persistent db) */ _mosquitto_free(local_id); }else{ /* id wasn't found, so generate a new context */ new_context = mqtt3_context_init(db, -1); if(!new_context){ _mosquitto_free(local_id); return MOSQ_ERR_NOMEM; } new_context->id = local_id; HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, new_context->id, strlen(new_context->id), new_context); } new_context->bridge = bridge; new_context->is_bridge = true; new_context->username = new_context->bridge->remote_username; new_context->password = new_context->bridge->remote_password; #ifdef WITH_TLS new_context->tls_cafile = new_context->bridge->tls_cafile; new_context->tls_capath = new_context->bridge->tls_capath; new_context->tls_certfile = new_context->bridge->tls_certfile; new_context->tls_keyfile = new_context->bridge->tls_keyfile; new_context->tls_cert_reqs = SSL_VERIFY_PEER; new_context->tls_version = new_context->bridge->tls_version; new_context->tls_insecure = new_context->bridge->tls_insecure; #ifdef REAL_WITH_TLS_PSK new_context->tls_psk_identity = new_context->bridge->tls_psk_identity; new_context->tls_psk = new_context->bridge->tls_psk; #endif #endif bridge->try_private_accepted = true; new_context->protocol = bridge->protocol_version; bridges = _mosquitto_realloc(db->bridges, (db->bridge_count+1)*sizeof(struct mosquitto *)); if(bridges){ db->bridges = bridges; db->bridge_count++; db->bridges[db->bridge_count-1] = new_context; }else{ return MOSQ_ERR_NOMEM; } #if defined(__GLIBC__) && defined(WITH_ADNS) new_context->bridge->restart_t = 1; /* force quick restart of bridge */ return mqtt3_bridge_connect_step1(db, new_context); #else return mqtt3_bridge_connect(db, new_context); #endif } #if defined(__GLIBC__) && defined(WITH_ADNS) int mqtt3_bridge_connect_step1(struct mosquitto_db *db, struct mosquitto *context) { int rc; int i; char *notification_topic; int notification_topic_len; uint8_t notification_payload; if(!context || !context->bridge) return MOSQ_ERR_INVAL; context->state = mosq_cs_new; context->sock = INVALID_SOCKET; context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + context->bridge->keepalive; context->keepalive = context->bridge->keepalive; context->clean_session = context->bridge->clean_session; context->in_packet.payload = NULL; context->ping_t = 0; context->bridge->lazy_reconnect = false; mqtt3_bridge_packet_cleanup(context); mqtt3_db_message_reconnect_reset(db, context); if(context->clean_session){ mqtt3_db_messages_delete(db, context); } /* Delete all local subscriptions even for clean_session==false. We don't * remove any messages and the next loop carries out the resubscription * anyway. This means any unwanted subs will be removed. */ mqtt3_subs_clean_session(db, context); for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); if(mqtt3_sub_add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; } } if(context->bridge->notifications){ if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ notification_payload = '0'; mqtt3_db_messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } notification_payload = '0'; rc = _mosquitto_will_set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true); if(rc != MOSQ_ERR_SUCCESS){ return rc; } }else{ notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state"); notification_topic = _mosquitto_malloc(sizeof(char)*(notification_topic_len+1)); if(!notification_topic) return MOSQ_ERR_NOMEM; snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid); if(!context->bridge->initial_notification_done){ notification_payload = '0'; mqtt3_db_messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } notification_payload = '0'; rc = _mosquitto_will_set(context, notification_topic, 1, ¬ification_payload, 1, true); _mosquitto_free(notification_topic); if(rc != MOSQ_ERR_SUCCESS){ return rc; } } } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port); rc = _mosquitto_try_connect_step1(context, context->bridge->addresses[context->bridge->cur_address].address); if(rc > 0 ){ if(rc == MOSQ_ERR_TLS){ _mosquitto_socket_close(db, context); return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; } return MOSQ_ERR_SUCCESS; } int mqtt3_bridge_connect_step2(struct mosquitto_db *db, struct mosquitto *context) { int rc; if(!context || !context->bridge) return MOSQ_ERR_INVAL; _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port); rc = _mosquitto_try_connect_step2(context, context->bridge->addresses[context->bridge->cur_address].port, &context->sock); if(rc > 0 ){ if(rc == MOSQ_ERR_TLS){ _mosquitto_socket_close(db, context); return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; } rc = _mosquitto_socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false); if(rc > 0 ){ if(rc == MOSQ_ERR_TLS){ _mosquitto_socket_close(db, context); return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; } HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); if(rc == MOSQ_ERR_CONN_PENDING){ context->state = mosq_cs_connect_pending; } rc = _mosquitto_send_connect(context, context->keepalive, context->clean_session); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ return MOSQ_ERR_SUCCESS; }else{ if(rc == MOSQ_ERR_TLS){ return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } _mosquitto_socket_close(db, context); return rc; } } #else int mqtt3_bridge_connect(struct mosquitto_db *db, struct mosquitto *context) { int rc; int i; char *notification_topic; int notification_topic_len; uint8_t notification_payload; if(!context || !context->bridge) return MOSQ_ERR_INVAL; context->state = mosq_cs_new; context->sock = INVALID_SOCKET; context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + context->bridge->keepalive; context->keepalive = context->bridge->keepalive; context->clean_session = context->bridge->clean_session; context->in_packet.payload = NULL; context->ping_t = 0; context->bridge->lazy_reconnect = false; mqtt3_bridge_packet_cleanup(context); mqtt3_db_message_reconnect_reset(db, context); if(context->clean_session){ mqtt3_db_messages_delete(db, context); } /* Delete all local subscriptions even for clean_session==false. We don't * remove any messages and the next loop carries out the resubscription * anyway. This means any unwanted subs will be removed. */ mqtt3_subs_clean_session(db, context); for(i=0; ibridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); if(mqtt3_sub_add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; } } if(context->bridge->notifications){ if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ notification_payload = '0'; mqtt3_db_messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } notification_payload = '0'; rc = _mosquitto_will_set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true); if(rc != MOSQ_ERR_SUCCESS){ return rc; } }else{ notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state"); notification_topic = _mosquitto_malloc(sizeof(char)*(notification_topic_len+1)); if(!notification_topic) return MOSQ_ERR_NOMEM; snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid); if(!context->bridge->initial_notification_done){ notification_payload = '0'; mqtt3_db_messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } notification_payload = '0'; rc = _mosquitto_will_set(context, notification_topic, 1, ¬ification_payload, 1, true); _mosquitto_free(notification_topic); if(rc != MOSQ_ERR_SUCCESS){ return rc; } } } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port); rc = _mosquitto_socket_connect(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false); if(rc > 0 ){ if(rc == MOSQ_ERR_TLS){ _mosquitto_socket_close(db, context); return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; } HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); if(rc == MOSQ_ERR_CONN_PENDING){ context->state = mosq_cs_connect_pending; } rc = _mosquitto_send_connect(context, context->keepalive, context->clean_session); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ return MOSQ_ERR_SUCCESS; }else{ if(rc == MOSQ_ERR_TLS){ return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } _mosquitto_socket_close(db, context); return rc; } } #endif void mqtt3_bridge_packet_cleanup(struct mosquitto *context) { struct _mosquitto_packet *packet; if(!context) return; if(context->current_out_packet){ _mosquitto_packet_cleanup(context->current_out_packet); _mosquitto_free(context->current_out_packet); context->current_out_packet = NULL; } while(context->out_packet){ _mosquitto_packet_cleanup(context->out_packet); packet = context->out_packet; context->out_packet = context->out_packet->next; _mosquitto_free(packet); } context->out_packet = NULL; context->out_packet_last = NULL; _mosquitto_packet_cleanup(&(context->in_packet)); } #endif mosquitto-1.4.15/src/mosquitto_broker.h0000664000175000017500000004401713245550210017241 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 MQTT3_H #define MQTT3_H #include #include #ifdef WITH_WEBSOCKETS # include # if defined(LWS_LIBRARY_VERSION_NUMBER) # define libwebsocket_callback_on_writable(A, B) lws_callback_on_writable((B)) # define libwebsocket_service(A, B) lws_service((A), (B)) # define libwebsocket_create_context(A) lws_create_context((A)) # define libwebsocket_context_destroy(A) lws_context_destroy((A)) # define libwebsocket_write(A, B, C, D) lws_write((A), (B), (C), (D)) # define libwebsocket_get_socket_fd(A) lws_get_socket_fd((A)) # define libwebsockets_return_http_status(A, B, C, D) lws_return_http_status((B), (C), (D)) # define libwebsockets_get_protocol(A) lws_get_protocol((A)) # define libwebsocket_context lws_context # define libwebsocket_protocols lws_protocols # define libwebsocket_callback_reasons lws_callback_reasons # define libwebsocket lws # endif #endif #include #include #include #include "tls_mosq.h" #include "uthash.h" #ifndef __GNUC__ #define __attribute__(attrib) #endif /* Log destinations */ #define MQTT3_LOG_NONE 0x00 #define MQTT3_LOG_SYSLOG 0x01 #define MQTT3_LOG_FILE 0x02 #define MQTT3_LOG_STDOUT 0x04 #define MQTT3_LOG_STDERR 0x08 #define MQTT3_LOG_TOPIC 0x10 #define MQTT3_LOG_ALL 0xFF #define WEBSOCKET_CLIENT -2 enum mosquitto_protocol { mp_mqtt, mp_mqttsn, mp_websockets }; typedef uint64_t dbid_t; struct _mqtt3_listener { int fd; char *host; uint16_t port; int max_connections; char *mount_point; mosq_sock_t *socks; int sock_count; int client_count; enum mosquitto_protocol protocol; bool use_username_as_clientid; #ifdef WITH_TLS char *cafile; char *capath; char *certfile; char *keyfile; char *ciphers; char *psk_hint; bool require_certificate; SSL_CTX *ssl_ctx; char *crlfile; bool use_identity_as_username; char *tls_version; #endif #ifdef WITH_WEBSOCKETS struct libwebsocket_context *ws_context; char *http_dir; struct libwebsocket_protocols *ws_protocol; #endif }; struct mqtt3_config { char *acl_file; bool allow_anonymous; bool allow_duplicate_messages; bool allow_zero_length_clientid; bool auth_plugin_deny_special_chars; char *auto_id_prefix; int auto_id_prefix_len; int autosave_interval; bool autosave_on_changes; char *clientid_prefixes; bool connection_messages; bool daemon; struct _mqtt3_listener default_listener; struct _mqtt3_listener *listeners; int listener_count; int log_dest; int log_facility; int log_type; bool log_timestamp; char *log_file; FILE *log_fptr; uint32_t message_size_limit; char *password_file; bool persistence; char *persistence_location; char *persistence_file; char *persistence_filepath; time_t persistent_client_expiration; char *pid_file; char *psk_file; bool queue_qos0_messages; int retry_interval; int sys_interval; bool upgrade_outgoing_qos; char *user; #ifdef WITH_WEBSOCKETS int websockets_log_level; bool have_websockets_listener; #endif #ifdef WITH_BRIDGE struct _mqtt3_bridge *bridges; int bridge_count; #endif char *auth_plugin; struct mosquitto_auth_opt *auth_options; int auth_option_count; }; struct _mosquitto_subleaf { struct _mosquitto_subleaf *prev; struct _mosquitto_subleaf *next; struct mosquitto *context; int qos; }; struct _mosquitto_subhier { struct _mosquitto_subhier *parent; struct _mosquitto_subhier *children; struct _mosquitto_subhier *next; struct _mosquitto_subleaf *subs; char *topic; struct mosquitto_msg_store *retained; }; struct mosquitto_msg_store_load{ UT_hash_handle hh; dbid_t db_id; struct mosquitto_msg_store *store; }; struct mosquitto_msg_store{ struct mosquitto_msg_store *next; struct mosquitto_msg_store *prev; dbid_t db_id; char *source_id; char **dest_ids; int dest_id_count; int ref_count; char *topic; void *payload; uint32_t payloadlen; uint16_t source_mid; uint16_t mid; uint8_t qos; bool retain; }; struct mosquitto_client_msg{ struct mosquitto_client_msg *next; struct mosquitto_msg_store *store; time_t timestamp; uint16_t mid; uint8_t qos; bool retain; enum mosquitto_msg_direction direction; enum mosquitto_msg_state state; bool dup; }; struct _mosquitto_unpwd{ char *username; char *password; #ifdef WITH_TLS unsigned int password_len; unsigned int salt_len; unsigned char *salt; #endif UT_hash_handle hh; }; struct _mosquitto_acl{ struct _mosquitto_acl *next; char *topic; int access; int ucount; int ccount; }; struct _mosquitto_acl_user{ struct _mosquitto_acl_user *next; char *username; struct _mosquitto_acl *acl; }; struct _mosquitto_auth_plugin{ void *lib; void *user_data; int (*plugin_version)(void); int (*plugin_init)(void **user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count); int (*plugin_cleanup)(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count); int (*security_init)(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload); int (*security_cleanup)(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload); int (*acl_check)(void *user_data, const char *clientid, const char *username, const char *topic, int access); int (*unpwd_check)(void *user_data, const char *username, const char *password); int (*psk_key_get)(void *user_data, const char *hint, const char *identity, char *key, int max_key_len); }; struct mosquitto_db{ dbid_t last_db_id; struct _mosquitto_subhier subs; struct _mosquitto_unpwd *unpwd; struct _mosquitto_acl_user *acl_list; struct _mosquitto_acl *acl_patterns; struct _mosquitto_unpwd *psk_id; struct mosquitto *contexts_by_id; struct mosquitto *contexts_by_sock; struct mosquitto *contexts_for_free; #ifdef WITH_BRIDGE struct mosquitto **bridges; #endif struct _clientid_index_hash *clientid_index_hash; struct mosquitto_msg_store *msg_store; struct mosquitto_msg_store_load *msg_store_load; #ifdef WITH_BRIDGE int bridge_count; #endif int msg_store_count; char *config_file; struct mqtt3_config *config; int persistence_changes; struct _mosquitto_auth_plugin auth_plugin; bool verbose; #ifdef WITH_SYS_TREE int subscription_count; int retained_count; #endif struct mosquitto *ll_for_free; }; enum mqtt3_bridge_direction{ bd_out = 0, bd_in = 1, bd_both = 2 }; enum mosquitto_bridge_start_type{ bst_automatic = 0, bst_lazy = 1, bst_manual = 2, bst_once = 3 }; struct _mqtt3_bridge_topic{ char *topic; int qos; enum mqtt3_bridge_direction direction; char *local_prefix; char *remote_prefix; char *local_topic; /* topic prefixed with local_prefix */ char *remote_topic; /* topic prefixed with remote_prefix */ }; struct bridge_address{ char *address; int port; }; struct _mqtt3_bridge{ char *name; struct bridge_address *addresses; int cur_address; int address_count; time_t primary_retry; bool round_robin; bool try_private; bool try_private_accepted; bool clean_session; int keepalive; struct _mqtt3_bridge_topic *topics; int topic_count; bool topic_remapping; enum _mosquitto_protocol protocol_version; time_t restart_t; char *remote_clientid; char *remote_username; char *remote_password; char *local_clientid; char *local_username; char *local_password; bool notifications; char *notification_topic; enum mosquitto_bridge_start_type start_type; int idle_timeout; int restart_timeout; int threshold; bool lazy_reconnect; bool attempt_unsubscribe; bool initial_notification_done; #ifdef WITH_TLS char *tls_cafile; char *tls_capath; char *tls_certfile; char *tls_keyfile; bool tls_insecure; char *tls_version; # ifdef REAL_WITH_TLS_PSK char *tls_psk_identity; char *tls_psk; # endif #endif }; #ifdef WITH_WEBSOCKETS struct libws_mqtt_hack { char *http_dir; }; struct libws_mqtt_data { struct mosquitto *mosq; }; #endif #include /* ============================================================ * Main functions * ============================================================ */ int mosquitto_main_loop(struct mosquitto_db *db, mosq_sock_t *listensock, int listensock_count, int listener_max); struct mosquitto_db *_mosquitto_get_db(void); /* ============================================================ * Config functions * ============================================================ */ /* Initialise config struct to default values. */ void mqtt3_config_init(struct mosquitto_db *db, struct mqtt3_config *config); /* Parse command line options into config. */ int mqtt3_config_parse_args(struct mosquitto_db *db, struct mqtt3_config *config, int argc, char *argv[]); /* Read configuration data from config->config_file into config. * If reload is true, don't process config options that shouldn't be reloaded (listeners etc) * Returns 0 on success, 1 if there is a configuration error or if a file cannot be opened. */ int mqtt3_config_read(struct mosquitto_db *db, struct mqtt3_config *config, bool reload); /* Free all config data. */ void mqtt3_config_cleanup(struct mqtt3_config *config); int drop_privileges(struct mqtt3_config *config, bool temporary); int restore_privileges(void); /* ============================================================ * Server send functions * ============================================================ */ int _mosquitto_send_connack(struct mosquitto *context, int ack, int result); int _mosquitto_send_suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload); /* ============================================================ * Network functions * ============================================================ */ int mqtt3_socket_accept(struct mosquitto_db *db, mosq_sock_t listensock); int mqtt3_socket_listen(struct _mqtt3_listener *listener); int _mosquitto_socket_get_address(mosq_sock_t sock, char *buf, int len); /* ============================================================ * Read handling functions * ============================================================ */ int mqtt3_packet_handle(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_handle_connack(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_handle_disconnect(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_handle_publish(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_handle_subscribe(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_handle_unsubscribe(struct mosquitto_db *db, struct mosquitto *context); /* ============================================================ * Database handling * ============================================================ */ int mqtt3_db_open(struct mqtt3_config *config, struct mosquitto_db *db); int mqtt3_db_close(struct mosquitto_db *db); #ifdef WITH_PERSISTENCE int mqtt3_db_backup(struct mosquitto_db *db, bool shutdown); int mqtt3_db_restore(struct mosquitto_db *db); #endif void mqtt3_db_limits_set(int inflight, int queued); /* Return the number of in-flight messages in count. */ int mqtt3_db_message_count(int *count); int mqtt3_db_message_delete(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); int mqtt3_db_message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored); int mqtt3_db_message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir); int mqtt3_db_message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state); int mqtt3_db_message_write(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_db_messages_delete(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_db_messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain); int mqtt3_db_messages_queue(struct mosquitto_db *db, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store **stored); int mqtt3_db_message_store(struct mosquitto_db *db, const char *source, uint16_t source_mid, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain, struct mosquitto_msg_store **stored, dbid_t store_id); int mqtt3_db_message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); void mosquitto__db_msg_store_add(struct mosquitto_db *db, struct mosquitto_msg_store *store); void mosquitto__db_msg_store_remove(struct mosquitto_db *db, struct mosquitto_msg_store *store); void mosquitto__db_msg_store_deref(struct mosquitto_db *db, struct mosquitto_msg_store **store); void mosquitto__db_msg_store_clean(struct mosquitto_db *db); /* Check all messages waiting on a client reply and resend if timeout has been exceeded. */ int mqtt3_db_message_timeout_check(struct mosquitto_db *db, unsigned int timeout); int mqtt3_db_message_reconnect_reset(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_retain_queue(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int sub_qos); void mqtt3_db_sys_update(struct mosquitto_db *db, int interval, time_t start_time); void mqtt3_db_vacuum(void); /* ============================================================ * Subscription functions * ============================================================ */ int mqtt3_sub_add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct _mosquitto_subhier *root); int mqtt3_sub_remove(struct mosquitto_db *db, struct mosquitto *context, const char *sub, struct _mosquitto_subhier *root); int mqtt3_sub_search(struct mosquitto_db *db, struct _mosquitto_subhier *root, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store *stored); void mqtt3_sub_tree_print(struct _mosquitto_subhier *root, int level); int mqtt3_subs_clean_session(struct mosquitto_db *db, struct mosquitto *context); /* ============================================================ * Context functions * ============================================================ */ struct mosquitto *mqtt3_context_init(struct mosquitto_db *db, mosq_sock_t sock); void mqtt3_context_cleanup(struct mosquitto_db *db, struct mosquitto *context, bool do_free); void mqtt3_context_disconnect(struct mosquitto_db *db, struct mosquitto *context); void mosquitto__add_context_to_disused(struct mosquitto_db *db, struct mosquitto *context); void mosquitto__free_disused_contexts(struct mosquitto_db *db); void mqtt3_context_send_will(struct mosquitto_db *db, struct mosquitto *context); /* ============================================================ * Logging functions * ============================================================ */ int mqtt3_log_init(struct mqtt3_config *config); int mqtt3_log_close(struct mqtt3_config *config); int _mosquitto_log_printf(struct mosquitto *mosq, int level, const char *fmt, ...) __attribute__((format(printf, 3, 4))); /* ============================================================ * Bridge functions * ============================================================ */ #ifdef WITH_BRIDGE int mqtt3_bridge_new(struct mosquitto_db *db, struct _mqtt3_bridge *bridge); int mqtt3_bridge_connect(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_bridge_connect_step1(struct mosquitto_db *db, struct mosquitto *context); int mqtt3_bridge_connect_step2(struct mosquitto_db *db, struct mosquitto *context); void mqtt3_bridge_packet_cleanup(struct mosquitto *context); #endif /* ============================================================ * Security related functions * ============================================================ */ int mosquitto_security_module_init(struct mosquitto_db *db); int mosquitto_security_module_cleanup(struct mosquitto_db *db); int mosquitto_security_init(struct mosquitto_db *db, bool reload); int mosquitto_security_apply(struct mosquitto_db *db); int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload); int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access); int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const char *password); int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len); int mosquitto_security_init_default(struct mosquitto_db *db, bool reload); int mosquitto_security_apply_default(struct mosquitto_db *db); int mosquitto_security_cleanup_default(struct mosquitto_db *db, bool reload); int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access); int mosquitto_unpwd_check_default(struct mosquitto_db *db, const char *username, const char *password); int mosquitto_psk_key_get_default(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len); /* ============================================================ * Window service related functions * ============================================================ */ #if defined(WIN32) || defined(__CYGWIN__) void service_install(void); void service_uninstall(void); void service_run(void); #endif /* ============================================================ * Websockets related functions * ============================================================ */ #ifdef WITH_WEBSOCKETS # if defined(LWS_LIBRARY_VERSION_NUMBER) struct lws_context *mosq_websockets_init(struct _mqtt3_listener *listener, int log_level); # else struct libwebsocket_context *mosq_websockets_init(struct _mqtt3_listener *listener, int log_level); # endif #endif void do_disconnect(struct mosquitto_db *db, struct mosquitto *context); #endif mosquitto-1.4.15/src/linker.syms0000664000175000017500000000003413245550210015650 0ustar rogerroger{ mosquitto_log_printf; }; mosquitto-1.4.15/src/mosquitto_plugin.h0000664000175000017500000001764513245550210017262 0ustar rogerroger/* Copyright (c) 2012-2018 Roger Light 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 MOSQUITTO_PLUGIN_H #define MOSQUITTO_PLUGIN_H #define MOSQ_AUTH_PLUGIN_VERSION 2 #define MOSQ_ACL_NONE 0x00 #define MOSQ_ACL_READ 0x01 #define MOSQ_ACL_WRITE 0x02 struct mosquitto_auth_opt { char *key; char *value; }; /* * To create an authentication plugin you must include this file then implement * the functions listed below. The resulting code should then be compiled as a * shared library. Using gcc this can be achieved as follows: * * gcc -I -fPIC -shared plugin.c -o plugin.so * * On Mac OS X: * * gcc -I -fPIC -shared plugin.c -undefined dynamic_lookup -o plugin.so * */ /* ========================================================================= * * Utility Functions * * Use these functions from within your plugin. * * There are also very useful functions in libmosquitto. * * ========================================================================= */ /* * Function: mosquitto_log_printf * * Write a log message using the broker configured logging. * * Parameters: * level - Log message priority. Can currently be one of: * * MOSQ_LOG_INFO * MOSQ_LOG_NOTICE * MOSQ_LOG_WARNING * MOSQ_LOG_ERR * MOSQ_LOG_DEBUG * MOSQ_LOG_SUBSCRIBE (not recommended for use by plugins) * MOSQ_LOG_UNSUBSCRIBE (not recommended for use by plugins) * * These values are defined in mosquitto.h. * * fmt, ... - printf style format and arguments. */ void mosquitto_log_printf(int level, const char *fmt, ...); /* ========================================================================= * * Plugin Functions * * You must implement these functions in your plugin. * * ========================================================================= */ /* * Function: mosquitto_auth_plugin_version * * The broker will call this function immediately after loading the plugin to * check it is a supported plugin version. Your code must simply return * MOSQ_AUTH_PLUGIN_VERSION. */ int mosquitto_auth_plugin_version(void); /* * Function: mosquitto_auth_plugin_init * * Called after the plugin has been loaded and * has been called. This will only ever be called once and can be used to * initialise the plugin. * * Parameters: * * user_data : The pointer set here will be passed to the other plugin * functions. Use to hold connection information for example. * auth_opts : Pointer to an array of struct mosquitto_auth_opt, which * provides the plugin options defined in the configuration file. * auth_opt_count : The number of elements in the auth_opts array. * * Return value: * Return 0 on success * Return >0 on failure. */ int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count); /* * Function: mosquitto_auth_plugin_cleanup * * Called when the broker is shutting down. This will only ever be called once. * Note that will be called directly before * this function. * * Parameters: * * user_data : The pointer provided in . * auth_opts : Pointer to an array of struct mosquitto_auth_opt, which * provides the plugin options defined in the configuration file. * auth_opt_count : The number of elements in the auth_opts array. * * Return value: * Return 0 on success * Return >0 on failure. */ int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count); /* * Function: mosquitto_auth_security_init * * Called when the broker initialises the security functions when it starts up. * If the broker is requested to reload its configuration whilst running, * will be called, followed by this function. * In this situation, the reload parameter will be true. * * Parameters: * * user_data : The pointer provided in . * auth_opts : Pointer to an array of struct mosquitto_auth_opt, which * provides the plugin options defined in the configuration file. * auth_opt_count : The number of elements in the auth_opts array. * reload : If set to false, this is the first time the function has * been called. If true, the broker has received a signal * asking to reload its configuration. * * Return value: * Return 0 on success * Return >0 on failure. */ int mosquitto_auth_security_init(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload); /* * Function: mosquitto_auth_security_cleanup * * Called when the broker cleans up the security functions when it shuts down. * If the broker is requested to reload its configuration whilst running, * this function will be called, followed by . * In this situation, the reload parameter will be true. * * Parameters: * * user_data : The pointer provided in . * auth_opts : Pointer to an array of struct mosquitto_auth_opt, which * provides the plugin options defined in the configuration file. * auth_opt_count : The number of elements in the auth_opts array. * reload : If set to false, this is the first time the function has * been called. If true, the broker has received a signal * asking to reload its configuration. * * Return value: * Return 0 on success * Return >0 on failure. */ int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload); /* * Function: mosquitto_auth_acl_check * * Called by the broker when topic access must be checked. access will be one * of MOSQ_ACL_READ (for subscriptions) or MOSQ_ACL_WRITE (for publish). Return * MOSQ_ERR_SUCCESS if access was granted, MOSQ_ERR_ACL_DENIED if access was * not granted, or MOSQ_ERR_UNKNOWN for an application specific error. */ int mosquitto_auth_acl_check(void *user_data, const char *clientid, const char *username, const char *topic, int access); /* * Function: mosquitto_auth_unpwd_check * * Called by the broker when a username/password must be checked. Return * MOSQ_ERR_SUCCESS if the user is authenticated, MOSQ_ERR_AUTH if * authentication failed, or MOSQ_ERR_UNKNOWN for an application specific * error. */ int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char *password); /* * Function: mosquitto_psk_key_get * * Called by the broker when a client connects to a listener using TLS/PSK. * This is used to retrieve the pre-shared-key associated with a client * identity. * * Examine hint and identity to determine the required PSK (which must be a * hexadecimal string with no leading "0x") and copy this string into key. * * Parameters: * user_data : the pointer provided in . * hint : the psk_hint for the listener the client is connecting to. * identity : the identity string provided by the client * key : a string where the hex PSK should be copied * max_key_len : the size of key * * Return value: * Return 0 on success. * Return >0 on failure. * Return >0 if this function is not required. */ int mosquitto_auth_psk_key_get(void *user_data, const char *hint, const char *identity, char *key, int max_key_len); #endif mosquitto-1.4.15/src/sys_tree.c0000664000175000017500000003242113245550210015455 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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. */ #ifdef WITH_SYS_TREE #include #include #include #include #include #include #define BUFLEN 100 uint64_t g_bytes_received = 0; uint64_t g_bytes_sent = 0; uint64_t g_pub_bytes_received = 0; uint64_t g_pub_bytes_sent = 0; unsigned long g_msgs_received = 0; unsigned long g_msgs_sent = 0; unsigned long g_pub_msgs_received = 0; unsigned long g_pub_msgs_sent = 0; unsigned long g_msgs_dropped = 0; int g_clients_expired = 0; unsigned int g_socket_connections = 0; unsigned int g_connection_count = 0; static void _sys_update_clients(struct mosquitto_db *db, char *buf) { static unsigned int client_count = -1; static int clients_expired = -1; static unsigned int client_max = 0; static unsigned int disconnected_count = -1; static unsigned int connected_count = -1; unsigned int count_total, count_by_sock; count_total = HASH_CNT(hh_id, db->contexts_by_id); count_by_sock = HASH_CNT(hh_sock, db->contexts_by_sock); if(client_count != count_total){ client_count = count_total; snprintf(buf, BUFLEN, "%d", client_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/total", 2, strlen(buf), buf, 1); if(client_count > client_max){ client_max = client_count; snprintf(buf, BUFLEN, "%d", client_max); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/maximum", 2, strlen(buf), buf, 1); } } if(disconnected_count != count_total-count_by_sock){ disconnected_count = count_total-count_by_sock; snprintf(buf, BUFLEN, "%d", disconnected_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/inactive", 2, strlen(buf), buf, 1); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/disconnected", 2, strlen(buf), buf, 1); } if(connected_count != count_by_sock){ connected_count = count_by_sock; snprintf(buf, BUFLEN, "%d", connected_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/active", 2, strlen(buf), buf, 1); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/connected", 2, strlen(buf), buf, 1); } if(g_clients_expired != clients_expired){ clients_expired = g_clients_expired; snprintf(buf, BUFLEN, "%d", clients_expired); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/clients/expired", 2, strlen(buf), buf, 1); } } #ifdef REAL_WITH_MEMORY_TRACKING static void _sys_update_memory(struct mosquitto_db *db, char *buf) { static unsigned long current_heap = -1; static unsigned long max_heap = -1; unsigned long value_ul; value_ul = _mosquitto_memory_used(); if(current_heap != value_ul){ current_heap = value_ul; snprintf(buf, BUFLEN, "%lu", current_heap); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/heap/current", 2, strlen(buf), buf, 1); } value_ul =_mosquitto_max_memory_used(); if(max_heap != value_ul){ max_heap = value_ul; snprintf(buf, BUFLEN, "%lu", max_heap); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/heap/maximum", 2, strlen(buf), buf, 1); } } #endif static void calc_load(struct mosquitto_db *db, char *buf, const char *topic, double exponent, double interval, double *current) { double new_value; new_value = interval + exponent*((*current) - interval); if(fabs(new_value - (*current)) >= 0.01){ snprintf(buf, BUFLEN, "%.2f", new_value); mqtt3_db_messages_easy_queue(db, NULL, topic, 2, strlen(buf), buf, 1); } (*current) = new_value; } /* Send messages for the $SYS hierarchy if the last update is longer than * 'interval' seconds ago. * 'interval' is the amount of seconds between updates. If 0, then no periodic * messages are sent for the $SYS hierarchy. * 'start_time' is the result of time() that the broker was started at. */ void mqtt3_db_sys_update(struct mosquitto_db *db, int interval, time_t start_time) { static time_t last_update = 0; time_t now; time_t uptime; char buf[BUFLEN]; static int msg_store_count = -1; static unsigned long msgs_received = -1; static unsigned long msgs_sent = -1; static unsigned long publish_dropped = -1; static unsigned long pub_msgs_received = -1; static unsigned long pub_msgs_sent = -1; static unsigned long long bytes_received = -1; static unsigned long long bytes_sent = -1; static unsigned long long pub_bytes_received = -1; static unsigned long long pub_bytes_sent = -1; static int subscription_count = -1; static int retained_count = -1; static double msgs_received_load1 = 0; static double msgs_received_load5 = 0; static double msgs_received_load15 = 0; static double msgs_sent_load1 = 0; static double msgs_sent_load5 = 0; static double msgs_sent_load15 = 0; static double publish_dropped_load1 = 0; static double publish_dropped_load5 = 0; static double publish_dropped_load15 = 0; double msgs_received_interval, msgs_sent_interval, publish_dropped_interval; static double publish_received_load1 = 0; static double publish_received_load5 = 0; static double publish_received_load15 = 0; static double publish_sent_load1 = 0; static double publish_sent_load5 = 0; static double publish_sent_load15 = 0; double publish_received_interval, publish_sent_interval; static double bytes_received_load1 = 0; static double bytes_received_load5 = 0; static double bytes_received_load15 = 0; static double bytes_sent_load1 = 0; static double bytes_sent_load5 = 0; static double bytes_sent_load15 = 0; double bytes_received_interval, bytes_sent_interval; static double socket_load1 = 0; static double socket_load5 = 0; static double socket_load15 = 0; double socket_interval; static double connection_load1 = 0; static double connection_load5 = 0; static double connection_load15 = 0; double connection_interval; double exponent; double i_mult; now = mosquitto_time(); if(interval && now - interval > last_update){ uptime = now - start_time; snprintf(buf, BUFLEN, "%d seconds", (int)uptime); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/uptime", 2, strlen(buf), buf, 1); _sys_update_clients(db, buf); if(last_update > 0){ i_mult = 60.0/(double)(now-last_update); msgs_received_interval = (g_msgs_received - msgs_received)*i_mult; msgs_sent_interval = (g_msgs_sent - msgs_sent)*i_mult; publish_dropped_interval = (g_msgs_dropped - publish_dropped)*i_mult; publish_received_interval = (g_pub_msgs_received - pub_msgs_received)*i_mult; publish_sent_interval = (g_pub_msgs_sent - pub_msgs_sent)*i_mult; bytes_received_interval = (g_bytes_received - bytes_received)*i_mult; bytes_sent_interval = (g_bytes_sent - bytes_sent)*i_mult; socket_interval = g_socket_connections*i_mult; g_socket_connections = 0; connection_interval = g_connection_count*i_mult; g_connection_count = 0; /* 1 minute load */ exponent = exp(-1.0*(now-last_update)/60.0); calc_load(db, buf, "$SYS/broker/load/messages/received/1min", exponent, msgs_received_interval, &msgs_received_load1); calc_load(db, buf, "$SYS/broker/load/messages/sent/1min", exponent, msgs_sent_interval, &msgs_sent_load1); calc_load(db, buf, "$SYS/broker/load/publish/dropped/1min", exponent, publish_dropped_interval, &publish_dropped_load1); calc_load(db, buf, "$SYS/broker/load/publish/received/1min", exponent, publish_received_interval, &publish_received_load1); calc_load(db, buf, "$SYS/broker/load/publish/sent/1min", exponent, publish_sent_interval, &publish_sent_load1); calc_load(db, buf, "$SYS/broker/load/bytes/received/1min", exponent, bytes_received_interval, &bytes_received_load1); calc_load(db, buf, "$SYS/broker/load/bytes/sent/1min", exponent, bytes_sent_interval, &bytes_sent_load1); calc_load(db, buf, "$SYS/broker/load/sockets/1min", exponent, socket_interval, &socket_load1); calc_load(db, buf, "$SYS/broker/load/connections/1min", exponent, connection_interval, &connection_load1); /* 5 minute load */ exponent = exp(-1.0*(now-last_update)/300.0); calc_load(db, buf, "$SYS/broker/load/messages/received/5min", exponent, msgs_received_interval, &msgs_received_load5); calc_load(db, buf, "$SYS/broker/load/messages/sent/5min", exponent, msgs_sent_interval, &msgs_sent_load5); calc_load(db, buf, "$SYS/broker/load/publish/dropped/5min", exponent, publish_dropped_interval, &publish_dropped_load5); calc_load(db, buf, "$SYS/broker/load/publish/received/5min", exponent, publish_received_interval, &publish_received_load5); calc_load(db, buf, "$SYS/broker/load/publish/sent/5min", exponent, publish_sent_interval, &publish_sent_load5); calc_load(db, buf, "$SYS/broker/load/bytes/received/5min", exponent, bytes_received_interval, &bytes_received_load5); calc_load(db, buf, "$SYS/broker/load/bytes/sent/5min", exponent, bytes_sent_interval, &bytes_sent_load5); calc_load(db, buf, "$SYS/broker/load/sockets/5min", exponent, socket_interval, &socket_load5); calc_load(db, buf, "$SYS/broker/load/connections/5min", exponent, connection_interval, &connection_load5); /* 15 minute load */ exponent = exp(-1.0*(now-last_update)/900.0); calc_load(db, buf, "$SYS/broker/load/messages/received/15min", exponent, msgs_received_interval, &msgs_received_load15); calc_load(db, buf, "$SYS/broker/load/messages/sent/15min", exponent, msgs_sent_interval, &msgs_sent_load15); calc_load(db, buf, "$SYS/broker/load/publish/dropped/15min", exponent, publish_dropped_interval, &publish_dropped_load15); calc_load(db, buf, "$SYS/broker/load/publish/received/15min", exponent, publish_received_interval, &publish_received_load15); calc_load(db, buf, "$SYS/broker/load/publish/sent/15min", exponent, publish_sent_interval, &publish_sent_load15); calc_load(db, buf, "$SYS/broker/load/bytes/received/15min", exponent, bytes_received_interval, &bytes_received_load15); calc_load(db, buf, "$SYS/broker/load/bytes/sent/15min", exponent, bytes_sent_interval, &bytes_sent_load15); calc_load(db, buf, "$SYS/broker/load/sockets/15min", exponent, socket_interval, &socket_load15); calc_load(db, buf, "$SYS/broker/load/connections/15min", exponent, connection_interval, &connection_load15); } if(db->msg_store_count != msg_store_count){ msg_store_count = db->msg_store_count; snprintf(buf, BUFLEN, "%d", msg_store_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/messages/stored", 2, strlen(buf), buf, 1); } if(db->subscription_count != subscription_count){ subscription_count = db->subscription_count; snprintf(buf, BUFLEN, "%d", subscription_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/subscriptions/count", 2, strlen(buf), buf, 1); } if(db->retained_count != retained_count){ retained_count = db->retained_count; snprintf(buf, BUFLEN, "%d", retained_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/retained messages/count", 2, strlen(buf), buf, 1); } #ifdef REAL_WITH_MEMORY_TRACKING _sys_update_memory(db, buf); #endif if(msgs_received != g_msgs_received){ msgs_received = g_msgs_received; snprintf(buf, BUFLEN, "%lu", msgs_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/messages/received", 2, strlen(buf), buf, 1); } if(msgs_sent != g_msgs_sent){ msgs_sent = g_msgs_sent; snprintf(buf, BUFLEN, "%lu", msgs_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/messages/sent", 2, strlen(buf), buf, 1); } if(publish_dropped != g_msgs_dropped){ publish_dropped = g_msgs_dropped; snprintf(buf, BUFLEN, "%lu", publish_dropped); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/dropped", 2, strlen(buf), buf, 1); } if(pub_msgs_received != g_pub_msgs_received){ pub_msgs_received = g_pub_msgs_received; snprintf(buf, BUFLEN, "%lu", pub_msgs_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/received", 2, strlen(buf), buf, 1); } if(pub_msgs_sent != g_pub_msgs_sent){ pub_msgs_sent = g_pub_msgs_sent; snprintf(buf, BUFLEN, "%lu", pub_msgs_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/sent", 2, strlen(buf), buf, 1); } if(bytes_received != g_bytes_received){ bytes_received = g_bytes_received; snprintf(buf, BUFLEN, "%llu", bytes_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/bytes/received", 2, strlen(buf), buf, 1); } if(bytes_sent != g_bytes_sent){ bytes_sent = g_bytes_sent; snprintf(buf, BUFLEN, "%llu", bytes_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/bytes/sent", 2, strlen(buf), buf, 1); } if(pub_bytes_received != g_pub_bytes_received){ pub_bytes_received = g_pub_bytes_received; snprintf(buf, BUFLEN, "%llu", pub_bytes_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/received", 2, strlen(buf), buf, 1); } if(pub_bytes_sent != g_pub_bytes_sent){ pub_bytes_sent = g_pub_bytes_sent; snprintf(buf, BUFLEN, "%llu", pub_bytes_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/sent", 2, strlen(buf), buf, 1); } last_update = mosquitto_time(); } } #endif mosquitto-1.4.15/src/security.c0000664000175000017500000002144013245550210015466 0ustar rogerroger/* Copyright (c) 2011-2018 Roger Light 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 #include #include #include #include "mosquitto_plugin.h" #include #include "lib_load.h" typedef int (*FUNC_auth_plugin_version)(void); typedef int (*FUNC_auth_plugin_init)(void **, struct mosquitto_auth_opt *, int); typedef int (*FUNC_auth_plugin_cleanup)(void *, struct mosquitto_auth_opt *, int); typedef int (*FUNC_auth_plugin_security_init)(void *, struct mosquitto_auth_opt *, int, bool); typedef int (*FUNC_auth_plugin_security_cleanup)(void *, struct mosquitto_auth_opt *, int, bool); typedef int (*FUNC_auth_plugin_acl_check)(void *, const char *, const char *, const char *, int); typedef int (*FUNC_auth_plugin_unpwd_check)(void *, const char *, const char *); typedef int (*FUNC_auth_plugin_psk_key_get)(void *, const char *, const char *, char *, int); void LIB_ERROR(void) { #ifdef WIN32 char *buf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, NULL, GetLastError(), LANG_NEUTRAL, &buf, 0, NULL); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Load error: %s", buf); LocalFree(buf); #else _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Load error: %s", dlerror()); #endif } int mosquitto_security_module_init(struct mosquitto_db *db) { void *lib; int (*plugin_version)(void) = NULL; int version; int rc; if(db->config->auth_plugin){ lib = LIB_LOAD(db->config->auth_plugin); if(!lib){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin \"%s\".", db->config->auth_plugin); LIB_ERROR(); return 1; } db->auth_plugin.lib = NULL; if(!(plugin_version = (FUNC_auth_plugin_version)LIB_SYM(lib, "mosquitto_auth_plugin_version"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_plugin_version()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } version = plugin_version(); if(version != MOSQ_AUTH_PLUGIN_VERSION){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Incorrect auth plugin version (got %d, expected %d).", version, MOSQ_AUTH_PLUGIN_VERSION); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.plugin_init = (FUNC_auth_plugin_init)LIB_SYM(lib, "mosquitto_auth_plugin_init"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_plugin_init()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.plugin_cleanup = (FUNC_auth_plugin_cleanup)LIB_SYM(lib, "mosquitto_auth_plugin_cleanup"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_plugin_cleanup()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.security_init = (FUNC_auth_plugin_security_init)LIB_SYM(lib, "mosquitto_auth_security_init"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_security_init()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.security_cleanup = (FUNC_auth_plugin_security_cleanup)LIB_SYM(lib, "mosquitto_auth_security_cleanup"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_security_cleanup()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.acl_check = (FUNC_auth_plugin_acl_check)LIB_SYM(lib, "mosquitto_auth_acl_check"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_acl_check()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.unpwd_check = (FUNC_auth_plugin_unpwd_check)LIB_SYM(lib, "mosquitto_auth_unpwd_check"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_unpwd_check()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } if(!(db->auth_plugin.psk_key_get = (FUNC_auth_plugin_psk_key_get)LIB_SYM(lib, "mosquitto_auth_psk_key_get"))){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load auth plugin function mosquitto_auth_psk_key_get()."); LIB_ERROR(); LIB_CLOSE(lib); return 1; } db->auth_plugin.lib = lib; db->auth_plugin.user_data = NULL; if(db->auth_plugin.plugin_init){ rc = db->auth_plugin.plugin_init(&db->auth_plugin.user_data, db->config->auth_options, db->config->auth_option_count); if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Authentication plugin returned %d when initialising.", rc); } return rc; } }else{ db->auth_plugin.lib = NULL; db->auth_plugin.plugin_init = NULL; db->auth_plugin.plugin_cleanup = NULL; db->auth_plugin.security_init = NULL; db->auth_plugin.security_cleanup = NULL; db->auth_plugin.acl_check = NULL; db->auth_plugin.unpwd_check = NULL; db->auth_plugin.psk_key_get = NULL; } return MOSQ_ERR_SUCCESS; } int mosquitto_security_module_cleanup(struct mosquitto_db *db) { mosquitto_security_cleanup(db, false); if(db->auth_plugin.plugin_cleanup){ db->auth_plugin.plugin_cleanup(db->auth_plugin.user_data, db->config->auth_options, db->config->auth_option_count); } if(db->config->auth_plugin){ if(db->auth_plugin.lib){ LIB_CLOSE(db->auth_plugin.lib); } } db->auth_plugin.lib = NULL; db->auth_plugin.plugin_init = NULL; db->auth_plugin.plugin_cleanup = NULL; db->auth_plugin.security_init = NULL; db->auth_plugin.security_cleanup = NULL; db->auth_plugin.acl_check = NULL; db->auth_plugin.unpwd_check = NULL; db->auth_plugin.psk_key_get = NULL; return MOSQ_ERR_SUCCESS; } int mosquitto_security_init(struct mosquitto_db *db, bool reload) { if(!db->auth_plugin.lib){ return mosquitto_security_init_default(db, reload); }else{ return db->auth_plugin.security_init(db->auth_plugin.user_data, db->config->auth_options, db->config->auth_option_count, reload); } } /* Apply security settings after a reload. * Includes: * - Disconnecting anonymous users if appropriate * - Disconnecting users with invalid passwords * - Reapplying ACLs */ int mosquitto_security_apply(struct mosquitto_db *db) { if(!db->auth_plugin.lib){ return mosquitto_security_apply_default(db); } return MOSQ_ERR_SUCCESS; } int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload) { if(!db->auth_plugin.lib){ return mosquitto_security_cleanup_default(db, reload); }else{ return db->auth_plugin.security_cleanup(db->auth_plugin.user_data, db->config->auth_options, db->config->auth_option_count, reload); } } int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access) { char *username; if(!context->id){ return MOSQ_ERR_ACL_DENIED; } if(!db->auth_plugin.lib){ return mosquitto_acl_check_default(db, context, topic, access); }else{ #ifdef WITH_BRIDGE if(context->bridge){ username = context->bridge->local_username; }else #endif { username = context->username; } if(db->config->auth_plugin_deny_special_chars == true){ /* Check whether the client id or username contains a + or # and if * so deny access. * * Do this check for every message regardless, we have to protect the * plugins against possible pattern based attacks. */ if(username && strpbrk(username, "+#")){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous username \"%s\"", username); return MOSQ_ERR_ACL_DENIED; } if(context->id && strpbrk(context->id, "+#")){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "ACL denying access to client with dangerous client id \"%s\"", context->id); return MOSQ_ERR_ACL_DENIED; } } return db->auth_plugin.acl_check(db->auth_plugin.user_data, context->id, username, topic, access); } } int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const char *password) { if(!db->auth_plugin.lib){ return mosquitto_unpwd_check_default(db, username, password); }else{ return db->auth_plugin.unpwd_check(db->auth_plugin.user_data, username, password); } } int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len) { if(!db->auth_plugin.lib){ return mosquitto_psk_key_get_default(db, hint, identity, key, max_key_len); }else{ return db->auth_plugin.psk_key_get(db->auth_plugin.user_data, hint, identity, key, max_key_len); } } mosquitto-1.4.15/src/read_handle_server.c0000664000175000017500000005474413245550210017450 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include #include #include #include #ifdef WITH_UUID # include #endif #ifdef WITH_WEBSOCKETS # include #endif #ifdef WITH_SYS_TREE extern unsigned int g_connection_count; #endif static char *client_id_gen(struct mosquitto_db *db) { char *client_id; #ifdef WITH_UUID uuid_t uuid; #else int i; #endif #ifdef WITH_UUID client_id = (char *)_mosquitto_calloc(37 + db->config->auto_id_prefix_len, sizeof(char)); if(!client_id){ return NULL; } if(db->config->auto_id_prefix){ memcpy(client_id, db->config->auto_id_prefix, db->config->auto_id_prefix_len); } uuid_generate_random(uuid); uuid_unparse_lower(uuid, &client_id[db->config->auto_id_prefix_len]); #else client_id = (char *)_mosquitto_calloc(65 + db->config->auto_id_prefix_len, sizeof(char)); if(!client_id){ return NULL; } if(db->config->auto_id_prefix){ memcpy(client_id, db->config->auto_id_prefix, db->config->auto_id_prefix_len); } for(i=0; i<64; i++){ client_id[i+db->config->auto_id_prefix_len] = (rand()%73)+48; } client_id[i] = '\0'; #endif return client_id; } int mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context) { char *protocol_name = NULL; uint8_t protocol_version; uint8_t connect_flags; uint8_t connect_ack = 0; char *client_id = NULL; char *will_payload = NULL, *will_topic = NULL; char *will_topic_mount; uint16_t will_payloadlen; struct mosquitto_message *will_struct = NULL; uint8_t will, will_retain, will_qos, clean_session; uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; int rc; struct _mosquitto_acl_user *acl_tail; struct mosquitto_client_msg *msg_tail, *msg_prev; struct mosquitto *found_context; int slen; struct _mosquitto_subleaf *leaf; int i; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; X509_NAME_ENTRY *name_entry; #endif #ifdef WITH_SYS_TREE g_connection_count++; #endif /* Don't accept multiple CONNECT commands. */ if(context->state != mosq_cs_new){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &protocol_name)){ rc = 1; goto handle_connect_error; return 1; } if(!protocol_name){ rc = 3; goto handle_connect_error; return 3; } if(_mosquitto_read_byte(&context->in_packet, &protocol_version)){ rc = 1; goto handle_connect_error; return 1; } if(!strcmp(protocol_name, PROTOCOL_NAME_v31)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v31){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } context->protocol = mosq_p_mqtt31; }else if(!strcmp(protocol_name, PROTOCOL_NAME_v311)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v311){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } if((context->in_packet.command&0x0F) != 0x00){ /* Reserved flags not set to 0, must disconnect. */ _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } context->protocol = mosq_p_mqtt311; }else{ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol \"%s\" in CONNECT from %s.", protocol_name, context->address); } _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } _mosquitto_free(protocol_name); if(_mosquitto_read_byte(&context->in_packet, &connect_flags)){ rc = 1; goto handle_connect_error; } if(context->protocol == mosq_p_mqtt311){ if((connect_flags & 0x01) != 0x00){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } clean_session = (connect_flags & 0x02) >> 1; will = connect_flags & 0x04; will_qos = (connect_flags & 0x18) >> 3; if(will_qos == 3){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid Will QoS in CONNECT from %s.", context->address); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } will_retain = ((connect_flags & 0x20) == 0x20); // Temporary hack because MSVC<1800 doesn't have stdbool.h. password_flag = connect_flags & 0x40; username_flag = connect_flags & 0x80; if(_mosquitto_read_uint16(&context->in_packet, &(context->keepalive))){ rc = 1; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &client_id)){ rc = 1; goto handle_connect_error; } slen = strlen(client_id); if(slen == 0){ if(context->protocol == mosq_p_mqtt31){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ /* mqtt311 */ _mosquitto_free(client_id); client_id = NULL; if(clean_session == 0 || db->config->allow_zero_length_clientid == false){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ client_id = client_id_gen(db); if(!client_id){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } } } } /* clientid_prefixes check */ if(db->config->clientid_prefixes){ if(strncmp(db->config->clientid_prefixes, client_id, strlen(db->config->clientid_prefixes))){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } } if(will){ will_struct = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!will_struct){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &will_topic)){ rc = 1; goto handle_connect_error; } if(STREMPTY(will_topic)){ rc = 1; goto handle_connect_error; } if(context->listener && context->listener->mount_point){ slen = strlen(context->listener->mount_point) + strlen(will_topic) + 1; will_topic_mount = _mosquitto_malloc(slen+1); if(!will_topic_mount){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } snprintf(will_topic_mount, slen, "%s%s", context->listener->mount_point, will_topic); will_topic_mount[slen] = '\0'; _mosquitto_free(will_topic); will_topic = will_topic_mount; } if(mosquitto_pub_topic_check(will_topic)){ rc = 1; goto handle_connect_error; } if(_mosquitto_read_uint16(&context->in_packet, &will_payloadlen)){ rc = 1; goto handle_connect_error; } if(will_payloadlen > 0){ will_payload = _mosquitto_malloc(will_payloadlen); if(!will_payload){ rc = 1; goto handle_connect_error; } rc = _mosquitto_read_bytes(&context->in_packet, will_payload, will_payloadlen); if(rc){ rc = 1; goto handle_connect_error; } } }else{ if(context->protocol == mosq_p_mqtt311){ if(will_qos != 0 || will_retain != 0){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } if(username_flag){ rc = _mosquitto_read_string(&context->in_packet, &username); if(rc == MOSQ_ERR_SUCCESS){ if(password_flag){ rc = _mosquitto_read_string(&context->in_packet, &password); if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else if(rc == MOSQ_ERR_PROTOCOL){ if(context->protocol == mosq_p_mqtt31){ /* Password flag given, but no password. Ignore. */ password_flag = 0; }else if(context->protocol == mosq_p_mqtt311){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } }else if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else{ if(context->protocol == mosq_p_mqtt31){ /* Username flag given, but no username. Ignore. */ username_flag = 0; }else if(context->protocol == mosq_p_mqtt311){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } }else{ if(context->protocol == mosq_p_mqtt311){ if(password_flag){ /* username_flag == 0 && password_flag == 1 is forbidden */ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } #ifdef WITH_TLS if(context->listener && context->listener->ssl_ctx && context->listener->use_identity_as_username){ /* Don't need the username or password if provided */ _mosquitto_free(username); username = NULL; _mosquitto_free(password); password = NULL; if(!context->ssl){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } #ifdef REAL_WITH_TLS_PSK if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } }else{ #endif /* REAL_WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name = X509_get_subject_name(client_cert); if(!name){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); if(i == -1){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name_entry = X509_NAME_get_entry(name, i); context->username = _mosquitto_strdup((char *)ASN1_STRING_data(X509_NAME_ENTRY_get_data(name_entry))); if(!context->username){ rc = 1; goto handle_connect_error; } X509_free(client_cert); client_cert = NULL; #ifdef REAL_WITH_TLS_PSK } #endif /* REAL_WITH_TLS_PSK */ }else{ #endif /* WITH_TLS */ if(username_flag){ rc = mosquitto_unpwd_check(db, username, password); switch(rc){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_AUTH: _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; break; default: mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; break; } context->username = username; context->password = password; username = NULL; /* Avoid free() in error: below. */ password = NULL; } if(!username_flag && db->config->allow_anonymous == false){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } #ifdef WITH_TLS } #endif if(context->listener && context->listener->use_username_as_clientid){ if(context->username){ _mosquitto_free(client_id); client_id = _mosquitto_strdup(context->username); if(!client_id){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } }else{ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } } /* Find if this client already has an entry. This must be done *after* any security checks. */ HASH_FIND(hh_id, db->contexts_by_id, client_id, strlen(client_id), found_context); if(found_context){ /* Found a matching client */ if(found_context->sock == INVALID_SOCKET){ /* Client is reconnecting after a disconnect */ /* FIXME - does anything need to be done here? */ }else{ /* Client is already connected, disconnect old version. This is * done in mqtt3_context_cleanup() below. */ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Client %s already connected, closing old connection.", client_id); } } if(context->protocol == mosq_p_mqtt311){ if(clean_session == 0){ connect_ack |= 0x01; } } context->clean_session = clean_session; if(context->clean_session == false && found_context->clean_session == false){ if(found_context->msgs){ context->msgs = found_context->msgs; found_context->msgs = NULL; mqtt3_db_message_reconnect_reset(db, context); } context->subs = found_context->subs; found_context->subs = NULL; context->sub_count = found_context->sub_count; found_context->sub_count = 0; context->last_mid = found_context->last_mid; for(i=0; isub_count; i++){ if(context->subs[i]){ leaf = context->subs[i]->subs; while(leaf){ if(leaf->context == found_context){ leaf->context = context; } leaf = leaf->next; } } } } found_context->clean_session = true; found_context->state = mosq_cs_disconnecting; do_disconnect(db, found_context); } /* Associate user with its ACL, assuming we have ACLs loaded. */ if(db->acl_list){ acl_tail = db->acl_list; while(acl_tail){ if(context->username){ if(acl_tail->username && !strcmp(context->username, acl_tail->username)){ context->acl_list = acl_tail; break; } }else{ if(acl_tail->username == NULL){ context->acl_list = acl_tail; break; } } acl_tail = acl_tail->next; } }else{ context->acl_list = NULL; } if(will_struct){ context->will = will_struct; context->will->topic = will_topic; if(will_payload){ context->will->payload = will_payload; context->will->payloadlen = will_payloadlen; }else{ context->will->payload = NULL; context->will->payloadlen = 0; } context->will->qos = will_qos; context->will->retain = will_retain; } if(db->config->connection_messages == true){ if(context->is_bridge){ if(context->username){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); } }else{ if(context->username){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); } } } context->id = client_id; client_id = NULL; context->clean_session = clean_session; context->ping_t = 0; context->is_dropping = false; if((protocol_version&0x80) == 0x80){ context->is_bridge = true; } /* Remove any queued messages that are no longer allowed through ACL, * assuming a possible change of username. */ msg_tail = context->msgs; msg_prev = NULL; while(msg_tail){ if(msg_tail->direction == mosq_md_out){ if(mosquitto_acl_check(db, context, msg_tail->store->topic, MOSQ_ACL_READ) != MOSQ_ERR_SUCCESS){ mosquitto__db_msg_store_deref(db, &msg_tail->store); if(msg_prev){ msg_prev->next = msg_tail->next; _mosquitto_free(msg_tail); msg_tail = msg_prev->next; }else{ context->msgs = context->msgs->next; if(context->last_msg == msg_tail){ context->last_msg = NULL; } _mosquitto_free(msg_tail); msg_tail = context->msgs; } }else{ msg_prev = msg_tail; msg_tail = msg_tail->next; } }else{ msg_prev = msg_tail; msg_tail = msg_tail->next; } } HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, context->id, strlen(context->id), context); #ifdef WITH_PERSISTENCE if(!clean_session){ db->persistence_changes++; } #endif context->state = mosq_cs_connected; return _mosquitto_send_connack(context, connect_ack, CONNACK_ACCEPTED); handle_connect_error: if(client_id) _mosquitto_free(client_id); if(username) _mosquitto_free(username); if(password) _mosquitto_free(password); if(will_payload) _mosquitto_free(will_payload); if(will_topic) _mosquitto_free(will_topic); if(will_struct) _mosquitto_free(will_struct); #ifdef WITH_TLS if(client_cert) X509_free(client_cert); #endif /* We return an error here which means the client is freed later on. */ return rc; } int mqtt3_handle_disconnect(struct mosquitto_db *db, struct mosquitto *context) { if(!context){ return MOSQ_ERR_INVAL; } if(context->in_packet.remaining_length != 0){ return MOSQ_ERR_PROTOCOL; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received DISCONNECT from %s", context->id); if(context->protocol == mosq_p_mqtt311){ if((context->in_packet.command&0x0F) != 0x00){ do_disconnect(db, context); return MOSQ_ERR_PROTOCOL; } } context->state = mosq_cs_disconnecting; do_disconnect(db, context); return MOSQ_ERR_SUCCESS; } int mqtt3_handle_subscribe(struct mosquitto_db *db, struct mosquitto *context) { int rc = 0; int rc2; uint16_t mid; char *sub; uint8_t qos; uint8_t *payload = NULL, *tmp_payload; uint32_t payloadlen = 0; int len; char *sub_mount; if(!context) return MOSQ_ERR_INVAL; _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->id); /* FIXME - plenty of potential for memory leaks here */ if(context->protocol == mosq_p_mqtt311){ if((context->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } } if(_mosquitto_read_uint16(&context->in_packet, &mid)) return 1; while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; if(_mosquitto_read_string(&context->in_packet, &sub)){ if(payload) _mosquitto_free(payload); return 1; } if(sub){ if(!strlen(sub)){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Empty subscription string from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(mosquitto_sub_topic_check(sub)){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid subscription string from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(_mosquitto_read_byte(&context->in_packet, &qos)){ _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(qos > 2){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid QoS in subscription command from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + strlen(sub) + 1; sub_mount = _mosquitto_malloc(len+1); if(!sub_mount){ _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return MOSQ_ERR_NOMEM; } snprintf(sub_mount, len, "%s%s", context->listener->mount_point, sub); sub_mount[len] = '\0'; _mosquitto_free(sub); sub = sub_mount; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "\t%s (QoS %d)", sub, qos); #if 0 /* FIXME * This section has been disabled temporarily. mosquitto_acl_check * calls mosquitto_topic_matches_sub, which can't cope with * checking subscriptions that have wildcards against ACLs that * have wildcards. Bug #1374291 is related. * * It's a very difficult problem when an ACL looks like foo/+/bar * and a subscription request to foo/# is made. * * This should be changed to using MOSQ_ACL_SUBSCRIPTION in the * future anyway. */ if(context->protocol == mosq_p_mqtt311){ rc = mosquitto_acl_check(db, context, sub, MOSQ_ACL_READ); switch(rc){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_ACL_DENIED: qos = 0x80; break; default: _mosquitto_free(sub); return rc; } } #endif if(qos != 0x80){ rc2 = mqtt3_sub_add(db, context, sub, qos, &db->subs); if(rc2 == MOSQ_ERR_SUCCESS){ if(mqtt3_retain_queue(db, context, sub, qos)) rc = 1; }else if(rc2 != -1){ rc = rc2; } _mosquitto_log_printf(NULL, MOSQ_LOG_SUBSCRIBE, "%s %d %s", context->id, qos, sub); } _mosquitto_free(sub); tmp_payload = _mosquitto_realloc(payload, payloadlen + 1); if(tmp_payload){ payload = tmp_payload; payload[payloadlen] = qos; payloadlen++; }else{ if(payload) _mosquitto_free(payload); return MOSQ_ERR_NOMEM; } } } if(context->protocol == mosq_p_mqtt311){ if(payloadlen == 0){ /* No subscriptions specified, protocol error. */ return MOSQ_ERR_PROTOCOL; } } if(_mosquitto_send_suback(context, mid, payloadlen, payload)) rc = 1; _mosquitto_free(payload); #ifdef WITH_PERSISTENCE db->persistence_changes++; #endif return rc; } int mqtt3_handle_unsubscribe(struct mosquitto_db *db, struct mosquitto *context) { uint16_t mid; char *sub; if(!context) return MOSQ_ERR_INVAL; _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBSCRIBE from %s", context->id); if(context->protocol == mosq_p_mqtt311){ if((context->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } } if(_mosquitto_read_uint16(&context->in_packet, &mid)) return 1; while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; if(_mosquitto_read_string(&context->in_packet, &sub)){ return 1; } if(sub){ if(!strlen(sub)){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Empty unsubscription string from %s, disconnecting.", context->id); _mosquitto_free(sub); return 1; } if(mosquitto_sub_topic_check(sub)){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid unsubscription string from %s, disconnecting.", context->id); _mosquitto_free(sub); return 1; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub); mqtt3_sub_remove(db, context, sub, &db->subs); _mosquitto_log_printf(NULL, MOSQ_LOG_UNSUBSCRIBE, "%s %s", context->id, sub); _mosquitto_free(sub); } } #ifdef WITH_PERSISTENCE db->persistence_changes++; #endif return _mosquitto_send_command_with_mid(context, UNSUBACK, mid, false); } mosquitto-1.4.15/src/linker-macosx.syms0000664000175000017500000000002613245550210017141 0ustar rogerroger_mosquitto_log_printf mosquitto-1.4.15/src/db_dump/0000775000175000017500000000000013245550210015064 5ustar rogerrogermosquitto-1.4.15/src/db_dump/Makefile0000664000175000017500000000052213245550210016523 0ustar rogerrogerinclude ../../config.mk CFLAGS_FINAL=${CFLAGS} -I.. -I../../lib -I../.. .PHONY: all clean reallyclean all : mosquitto_db_dump mosquitto_db_dump : db_dump.o ${CROSS_COMPILE}${CC} $^ -o $@ ${LDFLAGS} ${LIBS} db_dump.o : db_dump.c ../persist.h ${CROSS_COMPILE}${CC} $(CFLAGS_FINAL) -c $< -o $@ clean : -rm -f *.o mosquitto_db_dump mosquitto-1.4.15/src/db_dump/db_dump.c0000664000175000017500000002554213245550210016652 0ustar rogerroger/* Copyright (c) 2010-2012 Roger Light 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 #include #include #include #include #include #include #include #include #include #include #include static uint32_t db_version; static int stats = 0; static int _db_client_chunk_restore(struct mosquitto_db *db, FILE *db_fd) { uint16_t i16temp, slen, last_mid; char *client_id = NULL; int rc = 0; time_t disconnect_t; read_e(db_fd, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(!slen){ fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); return 1; } client_id = calloc(slen+1, sizeof(char)); if(!client_id){ fclose(db_fd); fprintf(stderr, "Error: Out of memory."); return 1; } read_e(db_fd, client_id, slen); if(!stats) printf("\tClient ID: %s\n", client_id); read_e(db_fd, &i16temp, sizeof(uint16_t)); last_mid = ntohs(i16temp); if(!stats) printf("\tLast MID: %d\n", last_mid); if(db_version == 2){ disconnect_t = time(NULL); }else{ read_e(db_fd, &disconnect_t, sizeof(time_t)); if(!stats) printf("\tDisconnect time: %ld\n", disconnect_t); } free(client_id); return rc; error: fprintf(stderr, "Error: %s.", strerror(errno)); if(db_fd >= 0) fclose(db_fd); if(client_id) free(client_id); return 1; } static int _db_client_msg_chunk_restore(struct mosquitto_db *db, FILE *db_fd) { dbid_t i64temp, store_id; uint16_t i16temp, slen, mid; uint8_t qos, retain, direction, state, dup; char *client_id = NULL; read_e(db_fd, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(!slen){ fprintf(stderr, "Error: Corrupt persistent database."); fclose(db_fd); return 1; } client_id = calloc(slen+1, sizeof(char)); if(!client_id){ fclose(db_fd); fprintf(stderr, "Error: Out of memory."); return 1; } read_e(db_fd, client_id, slen); if(!stats) printf("\tClient ID: %s\n", client_id); read_e(db_fd, &i64temp, sizeof(dbid_t)); store_id = i64temp; if(!stats) printf("\tStore ID: %ld\n", (long )store_id); read_e(db_fd, &i16temp, sizeof(uint16_t)); mid = ntohs(i16temp); if(!stats) printf("\tMID: %d\n", mid); read_e(db_fd, &qos, sizeof(uint8_t)); if(!stats) printf("\tQoS: %d\n", qos); read_e(db_fd, &retain, sizeof(uint8_t)); if(!stats) printf("\tRetain: %d\n", retain); read_e(db_fd, &direction, sizeof(uint8_t)); if(!stats) printf("\tDirection: %d\n", direction); read_e(db_fd, &state, sizeof(uint8_t)); if(!stats) printf("\tState: %d\n", state); read_e(db_fd, &dup, sizeof(uint8_t)); if(!stats) printf("\tDup: %d\n", dup); free(client_id); return 0; error: fprintf(stderr, "Error: %s.", strerror(errno)); if(db_fd >= 0) fclose(db_fd); if(client_id) free(client_id); return 1; } static int _db_msg_store_chunk_restore(struct mosquitto_db *db, FILE *db_fd) { dbid_t i64temp, store_id; uint32_t i32temp, payloadlen; uint16_t i16temp, slen, source_mid, mid; uint8_t qos, retain, *payload = NULL; char *source_id = NULL; char *topic = NULL; int rc = 0; bool binary; int i; read_e(db_fd, &i64temp, sizeof(dbid_t)); store_id = i64temp; if(!stats) printf("\tStore ID: %ld\n", (long)store_id); read_e(db_fd, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ source_id = calloc(slen+1, sizeof(char)); if(!source_id){ fclose(db_fd); fprintf(stderr, "Error: Out of memory."); return 1; } if(fread(source_id, 1, slen, db_fd) != slen){ fprintf(stderr, "Error: %s.", strerror(errno)); fclose(db_fd); free(source_id); return 1; } if(!stats) printf("\tSource ID: %s\n", source_id); free(source_id); } read_e(db_fd, &i16temp, sizeof(uint16_t)); source_mid = ntohs(i16temp); if(!stats) printf("\tSource MID: %d\n", source_mid); read_e(db_fd, &i16temp, sizeof(uint16_t)); mid = ntohs(i16temp); if(!stats) printf("\tMID: %d\n", mid); read_e(db_fd, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ topic = calloc(slen+1, sizeof(char)); if(!topic){ fclose(db_fd); free(source_id); fprintf(stderr, "Error: Out of memory."); return 1; } if(fread(topic, 1, slen, db_fd) != slen){ fprintf(stderr, "Error: %s.", strerror(errno)); fclose(db_fd); free(source_id); free(topic); return 1; } if(!stats) printf("\tTopic: %s\n", topic); free(topic); }else{ fprintf(stderr, "Error: Invalid msg_store chunk when restoring persistent database."); fclose(db_fd); free(source_id); return 1; } read_e(db_fd, &qos, sizeof(uint8_t)); if(!stats) printf("\tQoS: %d\n", qos); read_e(db_fd, &retain, sizeof(uint8_t)); if(!stats) printf("\tRetain: %d\n", retain); read_e(db_fd, &i32temp, sizeof(uint32_t)); payloadlen = ntohl(i32temp); if(!stats) printf("\tPayload Length: %d\n", payloadlen); if(payloadlen){ payload = malloc(payloadlen+1); if(!payload){ fclose(db_fd); free(source_id); free(topic); fprintf(stderr, "Error: Out of memory."); return 1; } memset(payload, 0, payloadlen+1); if(fread(payload, 1, payloadlen, db_fd) != payloadlen){ fprintf(stderr, "Error: %s.", strerror(errno)); fclose(db_fd); free(source_id); free(topic); free(payload); return 1; } binary = false; for(i=0; i= 0) fclose(db_fd); if(source_id) free(source_id); if(topic) free(topic); return 1; } static int _db_retain_chunk_restore(struct mosquitto_db *db, FILE *db_fd) { dbid_t i64temp, store_id; if(fread(&i64temp, sizeof(dbid_t), 1, db_fd) != 1){ fprintf(stderr, "Error: %s.", strerror(errno)); fclose(db_fd); return 1; } store_id = i64temp; if(!stats) printf("\tStore ID: %ld\n", (long int)store_id); return 0; } static int _db_sub_chunk_restore(struct mosquitto_db *db, FILE *db_fd) { uint16_t i16temp, slen; uint8_t qos; char *client_id; char *topic; int rc = 0; read_e(db_fd, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); client_id = calloc(slen+1, sizeof(char)); if(!client_id){ fclose(db_fd); fprintf(stderr, "Error: Out of memory."); return 1; } read_e(db_fd, client_id, slen); if(!stats) printf("\tClient ID: %s\n", client_id); read_e(db_fd, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); topic = calloc(slen+1, sizeof(char)); if(!topic){ fclose(db_fd); fprintf(stderr, "Error: Out of memory."); free(client_id); return 1; } read_e(db_fd, topic, slen); if(!stats) printf("\tTopic: %s\n", topic); read_e(db_fd, &qos, sizeof(uint8_t)); if(!stats) printf("\tQoS: %d\n", qos); free(client_id); free(topic); return rc; error: fprintf(stderr, "Error: %s.", strerror(errno)); if(db_fd >= 0) fclose(db_fd); return 1; } int main(int argc, char *argv[]) { FILE *fd; char header[15]; int rc = 0; uint32_t crc; dbid_t i64temp; uint32_t i32temp, length; uint16_t i16temp, chunk; uint8_t i8temp; ssize_t rlen; struct mosquitto_db db; char *filename; long cfg_count = 0; long msg_store_count = 0; long client_msg_count = 0; long retain_count = 0; long sub_count = 0; long client_count = 0; if(argc == 2){ filename = argv[1]; }else if(argc == 3 && !strcmp(argv[1], "--stats")){ stats = 1; filename = argv[2]; }else{ fprintf(stderr, "Usage: db_dump [--stats] \n"); return 1; } memset(&db, 0, sizeof(struct mosquitto_db)); fd = fopen(filename, "rb"); if(!fd) return 0; read_e(fd, &header, 15); if(!memcmp(header, magic, 15)){ if(!stats) printf("Mosquitto DB dump\n"); // Restore DB as normal read_e(fd, &crc, sizeof(uint32_t)); if(!stats) printf("CRC: %d\n", crc); read_e(fd, &i32temp, sizeof(uint32_t)); db_version = ntohl(i32temp); if(!stats) printf("DB version: %d\n", db_version); while(rlen = fread(&i16temp, sizeof(uint16_t), 1, fd), rlen == 1){ chunk = ntohs(i16temp); read_e(fd, &i32temp, sizeof(uint32_t)); length = ntohl(i32temp); switch(chunk){ case DB_CHUNK_CFG: cfg_count++; if(!stats) printf("DB_CHUNK_CFG:\n"); if(!stats) printf("\tLength: %d\n", length); read_e(fd, &i8temp, sizeof(uint8_t)); // shutdown if(!stats) printf("\tShutdown: %d\n", i8temp); read_e(fd, &i8temp, sizeof(uint8_t)); // sizeof(dbid_t) if(!stats) printf("\tDB ID size: %d\n", i8temp); if(i8temp != sizeof(dbid_t)){ fprintf(stderr, "Error: Incompatible database configuration (dbid size is %d bytes, expected %ld)", i8temp, sizeof(dbid_t)); fclose(fd); return 1; } read_e(fd, &i64temp, sizeof(dbid_t)); if(!stats) printf("\tLast DB ID: %ld\n", (long)i64temp); break; case DB_CHUNK_MSG_STORE: msg_store_count++; if(!stats) printf("DB_CHUNK_MSG_STORE:\n"); if(!stats) printf("\tLength: %d\n", length); if(_db_msg_store_chunk_restore(&db, fd)) return 1; break; case DB_CHUNK_CLIENT_MSG: client_msg_count++; if(!stats) printf("DB_CHUNK_CLIENT_MSG:\n"); if(!stats) printf("\tLength: %d\n", length); if(_db_client_msg_chunk_restore(&db, fd)) return 1; break; case DB_CHUNK_RETAIN: retain_count++; if(!stats) printf("DB_CHUNK_RETAIN:\n"); if(!stats) printf("\tLength: %d\n", length); if(_db_retain_chunk_restore(&db, fd)) return 1; break; case DB_CHUNK_SUB: sub_count++; if(!stats) printf("DB_CHUNK_SUB:\n"); if(!stats) printf("\tLength: %d\n", length); if(_db_sub_chunk_restore(&db, fd)) return 1; break; case DB_CHUNK_CLIENT: client_count++; if(!stats) printf("DB_CHUNK_CLIENT:\n"); if(!stats) printf("\tLength: %d\n", length); if(_db_client_chunk_restore(&db, fd)) return 1; break; default: fprintf(stderr, "Warning: Unsupported chunk \"%d\" in persistent database file. Ignoring.", chunk); fseek(fd, length, SEEK_CUR); break; } } if(rlen < 0) goto error; }else{ fprintf(stderr, "Error: Unrecognised file format."); rc = 1; } fclose(fd); if(stats){ printf("DB_CHUNK_CFG: %ld\n", cfg_count); printf("DB_CHUNK_MSG_STORE: %ld\n", msg_store_count); printf("DB_CHUNK_CLIENT_MSG: %ld\n", client_msg_count); printf("DB_CHUNK_RETAIN: %ld\n", retain_count); printf("DB_CHUNK_SUB: %ld\n", sub_count); printf("DB_CHUNK_CLIENT: %ld\n", client_count); } return rc; error: fprintf(stderr, "Error: %s.", strerror(errno)); if(fd >= 0) fclose(fd); return 1; } mosquitto-1.4.15/src/uthash.h0000664000175000017500000016751613245550210015137 0ustar rogerroger/* Copyright (c) 2003-2013, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTHASH_H #define UTHASH_H #include /* memcmp,strlen */ #include /* ptrdiff_t */ #include /* exit() */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #ifdef _MSC_VER /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define DECLTYPE(x) #endif #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #ifdef NO_DECLTYPE #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while(0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } while(0) #endif /* a number of the hash function use uint32_t which isn't defined on win32 */ #ifdef _MSC_VER typedef unsigned int uint32_t; typedef unsigned char uint8_t; #else #include /* uint32_t */ #endif #define UTHASH_VERSION 1.9.8 #ifndef uthash_fatal #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #endif #ifndef uthash_noexpand_fyi #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi #define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhe */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ unsigned _hf_bkt,_hf_hashv; \ out=NULL; \ if (head) { \ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ keyptr,keylen,out); \ } \ } \ } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) #define HASH_BLOOM_MAKE(tbl) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } while (0) #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) #else #define HASH_BLOOM_MAKE(tbl) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_BYTELEN 0 #endif #define HASH_MAKE_TABLE(hh,head) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ sizeof(UT_hash_table)); \ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl->buckets, 0, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl); \ (head)->hh.tbl->signature = HASH_SIGNATURE; \ } while(0) #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ do { \ replaced=NULL; \ HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ if (replaced!=NULL) { \ HASH_DELETE(hh,head,replaced); \ }; \ HASH_ADD(hh,head,fieldname,keylen_in,add); \ } while(0) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_bkt; \ (add)->hh.next = NULL; \ (add)->hh.key = (char*)keyptr; \ (add)->hh.keylen = (unsigned)keylen_in; \ if (!(head)) { \ head = (add); \ (head)->hh.prev = NULL; \ HASH_MAKE_TABLE(hh,head); \ } else { \ (head)->hh.tbl->tail->next = (add); \ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ (head)->hh.tbl->tail = &((add)->hh); \ } \ (head)->hh.tbl->num_items++; \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ (add)->hh.hashv, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ HASH_FSCK(hh,head); \ } while(0) #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ do { \ bkt = ((hashv) & ((num_bkts) - 1)); \ } while(0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ do { \ unsigned _hd_bkt; \ struct UT_hash_handle *_hd_hh_del; \ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ head = NULL; \ } else { \ _hd_hh_del = &((delptr)->hh); \ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ (head)->hh.tbl->tail = \ (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho); \ } \ if ((delptr)->hh.prev) { \ ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ } else { \ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ } \ if (_hd_hh_del->next) { \ ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ (head)->hh.tbl->hho))->prev = \ _hd_hh_del->prev; \ } \ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh,head); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ HASH_FIND(hh,head,findstr,strlen(findstr),out) #define HASH_ADD_STR(head,strfield,add) \ HASH_ADD(hh,head,strfield,strlen(add->strfield),add) #define HASH_REPLACE_STR(head,strfield,add,replaced) \ HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_REPLACE_INT(head,intfield,add,replaced) \ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_REPLACE_PTR(head,ptrfield,add) \ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ unsigned _bkt_i; \ unsigned _count, _bkt_count; \ char *_prev; \ struct UT_hash_handle *_thh; \ if (head) { \ _count = 0; \ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("invalid hh_prev %p, actual %p\n", \ _thh->hh_prev, _prev ); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("invalid bucket count %d, actual %d\n", \ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid hh item count %d, actual %d\n", \ (head)->hh.tbl->num_items, _count ); \ } \ /* traverse hh in app order; check next/prev integrity, count */ \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev !=(char*)(_thh->prev)) { \ HASH_OOPS("invalid prev %p, actual %p\n", \ _thh->prev, _prev ); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ (head)->hh.tbl->hho) : NULL ); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid app item count %d, actual %d\n", \ (head)->hh.tbl->num_items, _count ); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, fieldlen); \ } while (0) #else #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ #ifdef HASH_FUNCTION #define HASH_FCN HASH_FUNCTION #else #define HASH_FCN HASH_JEN #endif /* The Bernstein hash function, used in Perl prior to v5.6 */ #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _hb_keylen=keylen; \ char *_hb_key=(char*)(key); \ (hashv) = 0; \ while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ bkt = (hashv) & (num_bkts-1); \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _sx_i; \ char *_hs_key=(char*)(key); \ hashv = 0; \ for(_sx_i=0; _sx_i < keylen; _sx_i++) \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ bkt = hashv & (num_bkts-1); \ } while (0) #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _fn_i; \ char *_hf_key=(char*)(key); \ hashv = 2166136261UL; \ for(_fn_i=0; _fn_i < keylen; _fn_i++) \ hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ bkt = hashv & (num_bkts-1); \ } while(0) #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _ho_i; \ char *_ho_key=(char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ bkt = hashv & (num_bkts-1); \ } while(0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ unsigned char *_hj_key=(unsigned char*)(key); \ hashv = 0xfeedbeef; \ _hj_i = _hj_j = 0x9e3779b9; \ _hj_k = (unsigned)keylen; \ while (_hj_k >= 12) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12; \ } \ hashv += keylen; \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ case 5: _hj_j += _hj_key[4]; \ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ case 1: _hj_i += _hj_key[0]; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ bkt = hashv & (num_bkts-1); \ } while(0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned char *_sfh_key=(unsigned char*)(key); \ uint32_t _sfh_tmp, _sfh_len = keylen; \ \ int _sfh_rem = _sfh_len & 3; \ _sfh_len >>= 2; \ hashv = 0xcafebabe; \ \ /* Main loop */ \ for (;_sfh_len > 0; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ bkt = hashv & (num_bkts-1); \ } while(0) #ifdef HASH_USING_NO_STRICT_ALIASING /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * MurmurHash uses the faster approach only on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) #define MUR_GETBLOCK(p,i) p[i] #else /* non intel */ #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) #else /* assume little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) #endif #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ MUR_ONE_THREE(p)))) #endif #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define MUR_FMIX(_h) \ do { \ _h ^= _h >> 16; \ _h *= 0x85ebca6b; \ _h ^= _h >> 13; \ _h *= 0xc2b2ae35l; \ _h ^= _h >> 16; \ } while(0) #define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ do { \ const uint8_t *_mur_data = (const uint8_t*)(key); \ const int _mur_nblocks = (keylen) / 4; \ uint32_t _mur_h1 = 0xf88D5353; \ uint32_t _mur_c1 = 0xcc9e2d51; \ uint32_t _mur_c2 = 0x1b873593; \ uint32_t _mur_k1 = 0; \ const uint8_t *_mur_tail; \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ int _mur_i; \ for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ \ _mur_h1 ^= _mur_k1; \ _mur_h1 = MUR_ROTL32(_mur_h1,13); \ _mur_h1 = _mur_h1*5+0xe6546b64; \ } \ _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ _mur_k1=0; \ switch((keylen) & 3) { \ case 3: _mur_k1 ^= _mur_tail[2] << 16; \ case 2: _mur_k1 ^= _mur_tail[1] << 8; \ case 1: _mur_k1 ^= _mur_tail[0]; \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ _mur_h1 ^= _mur_k1; \ } \ _mur_h1 ^= (keylen); \ MUR_FMIX(_mur_h1); \ hashv = _mur_h1; \ bkt = hashv & (num_bkts-1); \ } while(0) #endif /* HASH_USING_NO_STRICT_ALIASING */ /* key comparison function; return 0 if keys equal */ #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ do { \ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ else out=NULL; \ while (out) { \ if ((out)->hh.keylen == keylen_in) { \ if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ } \ if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ else out = NULL; \ } \ } while(0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,addhh) \ do { \ head.count++; \ (addhh)->hh_next = head.hh_head; \ (addhh)->hh_prev = NULL; \ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ (head).hh_head=addhh; \ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ && (addhh)->tbl->noexpand != 1) { \ HASH_EXPAND_BUCKETS((addhh)->tbl); \ } \ } while(0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(hh,head,hh_del) \ (head).count--; \ if ((head).hh_head == hh_del) { \ (head).hh_head = hh_del->hh_next; \ } \ if (hh_del->hh_prev) { \ hh_del->hh_prev->hh_next = hh_del->hh_next; \ } \ if (hh_del->hh_next) { \ hh_del->hh_next->hh_prev = hh_del->hh_prev; \ } /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(tbl) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ memset(_he_new_buckets, 0, \ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ tbl->ideal_chain_maxlen = \ (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ tbl->nonideal_items = 0; \ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ { \ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ tbl->nonideal_items++; \ _he_newbkt->expand_mult = _he_newbkt->count / \ tbl->ideal_chain_maxlen; \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ _he_thh; \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ tbl->num_buckets *= 2; \ tbl->log2_num_buckets++; \ tbl->buckets = _he_new_buckets; \ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ (tbl->ineff_expands+1) : 0; \ if (tbl->ineff_expands > 1) { \ tbl->noexpand=1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } while(0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ _hs_psize++; \ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ if (! (_hs_q) ) break; \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ if (_hs_psize == 0) { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ _hs_e = _hs_p; \ if (_hs_p){ \ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else if (( \ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ ) <= 0) { \ _hs_e = _hs_p; \ if (_hs_p){ \ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail ) { \ _hs_tail->next = ((_hs_e) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ if (_hs_e) { \ _hs_e->prev = ((_hs_tail) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ } \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ if (_hs_tail){ \ _hs_tail->next = NULL; \ } \ if ( _hs_nmerges <= 1 ) { \ _hs_looping=0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2; \ } \ HASH_FSCK(hh,head); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt=NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if (src) { \ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ if (!dst) { \ DECLTYPE_ASSIGN(dst,_elt); \ HASH_MAKE_TABLE(hh_dst,dst); \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ (dst)->hh_dst.tbl->num_items++; \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst,dst); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if (head) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)=NULL; \ } \ } while(0) #define HASH_OVERHEAD(hh,head) \ (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ (sizeof(UT_hash_table)) + \ (HASH_BLOOM_BYTELEN))) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) #else #define HASH_ITER(hh,head,el,tmp) \ for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1 #define HASH_BLOOM_SIGNATURE 0xb12220f2 typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; char bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ mosquitto-1.4.15/src/conf.c0000664000175000017500000022650413245550210014554 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #ifdef WIN32 #else # include #endif #ifndef WIN32 # include # include #else # include # include #endif #if !defined(WIN32) && !defined(__CYGWIN__) # include #endif #include #include #include "tls_mosq.h" #include "util_mosq.h" #include "mqtt3_protocol.h" struct config_recurse { int log_dest; int log_dest_set; int log_type; int log_type_set; int max_inflight_messages; int max_queued_messages; }; #if defined(WIN32) || defined(__CYGWIN__) #include extern SERVICE_STATUS_HANDLE service_handle; #endif static int _conf_parse_bool(char **token, const char *name, bool *value, char *saveptr); static int _conf_parse_int(char **token, const char *name, int *value, char *saveptr); static int _conf_parse_string(char **token, const char *name, char **value, char *saveptr); static int _config_read_file(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *config_tmp, int level, int *lineno); static char *fgets_extending(char **buf, int *buflen, FILE *stream) { char *rc; char endchar; int offset = 0; char *newbuf; do{ rc = fgets(&((*buf)[offset]), *buflen-offset, stream); if(feof(stream)){ return rc; } endchar = (*buf)[strlen(*buf)-1]; if(endchar == '\n'){ return rc; } /* No EOL char found, so extend buffer */ offset = *buflen-1; *buflen += 1000; newbuf = realloc(*buf, *buflen); if(!newbuf){ return NULL; } *buf = newbuf; }while(1); } static int _conf_attempt_resolve(const char *host, const char *text, int log, const char *msg) { struct addrinfo gai_hints; struct addrinfo *gai_res; int rc; memset(&gai_hints, 0, sizeof(struct addrinfo)); gai_hints.ai_family = PF_UNSPEC; gai_hints.ai_flags = AI_ADDRCONFIG; gai_hints.ai_socktype = SOCK_STREAM; gai_res = NULL; rc = getaddrinfo(host, NULL, &gai_hints, &gai_res); if(gai_res){ freeaddrinfo(gai_res); } if(rc != 0){ #ifndef WIN32 if(rc == EAI_SYSTEM){ if(errno == ENOENT){ _mosquitto_log_printf(NULL, log, "%s: Unable to resolve %s %s.", msg, text, host); }else{ _mosquitto_log_printf(NULL, log, "%s: Error resolving %s: %s.", msg, text, strerror(errno)); } }else{ _mosquitto_log_printf(NULL, log, "%s: Error resolving %s: %s.", msg, text, gai_strerror(rc)); } #else if(rc == WSAHOST_NOT_FOUND){ _mosquitto_log_printf(NULL, log, "%s: Error resolving %s.", msg, text); } #endif return MOSQ_ERR_INVAL; } return MOSQ_ERR_SUCCESS; } static void _config_init_reload(struct mosquitto_db *db, struct mqtt3_config *config) { int i; /* Set defaults */ if(config->acl_file) _mosquitto_free(config->acl_file); config->acl_file = NULL; config->allow_anonymous = true; config->allow_duplicate_messages = false; config->allow_zero_length_clientid = true; config->auto_id_prefix = NULL; config->auto_id_prefix_len = 0; config->autosave_interval = 1800; config->autosave_on_changes = false; if(config->clientid_prefixes) _mosquitto_free(config->clientid_prefixes); config->connection_messages = true; config->clientid_prefixes = NULL; if(config->log_fptr){ fclose(config->log_fptr); config->log_fptr = NULL; } if(config->log_file){ _mosquitto_free(config->log_file); config->log_file = NULL; } #if defined(WIN32) || defined(__CYGWIN__) if(service_handle){ /* This is running as a Windows service. Default to no logging. Using * stdout/stderr is forbidden because the first clients to connect will * get log information sent to them for some reason. */ config->log_dest = MQTT3_LOG_NONE; }else{ config->log_dest = MQTT3_LOG_STDERR; } #else config->log_facility = LOG_DAEMON; config->log_dest = MQTT3_LOG_STDERR; if(db->verbose){ config->log_type = INT_MAX; }else{ config->log_type = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO; } #endif config->log_timestamp = true; if(config->password_file) _mosquitto_free(config->password_file); config->password_file = NULL; config->persistence = false; if(config->persistence_location) _mosquitto_free(config->persistence_location); config->persistence_location = NULL; if(config->persistence_file) _mosquitto_free(config->persistence_file); config->persistence_file = NULL; config->persistent_client_expiration = 0; if(config->psk_file) _mosquitto_free(config->psk_file); config->psk_file = NULL; config->queue_qos0_messages = false; config->retry_interval = 20; config->sys_interval = 10; config->upgrade_outgoing_qos = false; if(config->auth_options){ for(i=0; iauth_option_count; i++){ _mosquitto_free(config->auth_options[i].key); _mosquitto_free(config->auth_options[i].value); } _mosquitto_free(config->auth_options); config->auth_options = NULL; config->auth_option_count = 0; } } void mqtt3_config_init(struct mosquitto_db *db, struct mqtt3_config *config) { memset(config, 0, sizeof(struct mqtt3_config)); _config_init_reload(db, config); config->daemon = false; config->default_listener.host = NULL; config->default_listener.port = 0; config->default_listener.max_connections = -1; config->default_listener.mount_point = NULL; config->default_listener.socks = NULL; config->default_listener.sock_count = 0; config->default_listener.client_count = 0; config->default_listener.protocol = mp_mqtt; config->default_listener.use_username_as_clientid = false; #ifdef WITH_TLS config->default_listener.tls_version = NULL; config->default_listener.cafile = NULL; config->default_listener.capath = NULL; config->default_listener.certfile = NULL; config->default_listener.keyfile = NULL; config->default_listener.ciphers = NULL; config->default_listener.psk_hint = NULL; config->default_listener.require_certificate = false; config->default_listener.crlfile = NULL; config->default_listener.use_identity_as_username = false; #endif config->listeners = NULL; config->listener_count = 0; config->pid_file = NULL; config->user = NULL; #ifdef WITH_BRIDGE config->bridges = NULL; config->bridge_count = 0; #endif config->auth_plugin = NULL; config->auth_plugin_deny_special_chars = true; config->message_size_limit = 0; } void mqtt3_config_cleanup(struct mqtt3_config *config) { int i; #ifdef WITH_BRIDGE int j; #endif if(config->acl_file) _mosquitto_free(config->acl_file); if(config->auto_id_prefix) _mosquitto_free(config->auto_id_prefix); if(config->clientid_prefixes) _mosquitto_free(config->clientid_prefixes); if(config->password_file) _mosquitto_free(config->password_file); if(config->persistence_location) _mosquitto_free(config->persistence_location); if(config->persistence_file) _mosquitto_free(config->persistence_file); if(config->persistence_filepath) _mosquitto_free(config->persistence_filepath); if(config->psk_file) _mosquitto_free(config->psk_file); if(config->pid_file) _mosquitto_free(config->pid_file); if(config->listeners){ for(i=0; ilistener_count; i++){ if(config->listeners[i].host) _mosquitto_free(config->listeners[i].host); if(config->listeners[i].mount_point) _mosquitto_free(config->listeners[i].mount_point); if(config->listeners[i].socks) _mosquitto_free(config->listeners[i].socks); #ifdef WITH_TLS if(config->listeners[i].cafile) _mosquitto_free(config->listeners[i].cafile); if(config->listeners[i].capath) _mosquitto_free(config->listeners[i].capath); if(config->listeners[i].certfile) _mosquitto_free(config->listeners[i].certfile); if(config->listeners[i].keyfile) _mosquitto_free(config->listeners[i].keyfile); if(config->listeners[i].ciphers) _mosquitto_free(config->listeners[i].ciphers); if(config->listeners[i].psk_hint) _mosquitto_free(config->listeners[i].psk_hint); if(config->listeners[i].crlfile) _mosquitto_free(config->listeners[i].crlfile); if(config->listeners[i].tls_version) _mosquitto_free(config->listeners[i].tls_version); #ifdef WITH_WEBSOCKETS if(config->listeners[i].http_dir) _mosquitto_free(config->listeners[i].http_dir); if(!config->listeners[i].ws_context) /* libwebsockets frees its own SSL_CTX */ #endif { SSL_CTX_free(config->listeners[i].ssl_ctx); } #endif } _mosquitto_free(config->listeners); } #ifdef WITH_BRIDGE if(config->bridges){ for(i=0; ibridge_count; i++){ if(config->bridges[i].name) _mosquitto_free(config->bridges[i].name); if(config->bridges[i].addresses){ for(j=0; jbridges[i].address_count; j++){ _mosquitto_free(config->bridges[i].addresses[j].address); } _mosquitto_free(config->bridges[i].addresses); } if(config->bridges[i].remote_clientid) _mosquitto_free(config->bridges[i].remote_clientid); if(config->bridges[i].remote_username) _mosquitto_free(config->bridges[i].remote_username); if(config->bridges[i].remote_password) _mosquitto_free(config->bridges[i].remote_password); if(config->bridges[i].local_clientid) _mosquitto_free(config->bridges[i].local_clientid); if(config->bridges[i].local_username) _mosquitto_free(config->bridges[i].local_username); if(config->bridges[i].local_password) _mosquitto_free(config->bridges[i].local_password); if(config->bridges[i].topics){ for(j=0; jbridges[i].topic_count; j++){ if(config->bridges[i].topics[j].topic) _mosquitto_free(config->bridges[i].topics[j].topic); if(config->bridges[i].topics[j].local_prefix) _mosquitto_free(config->bridges[i].topics[j].local_prefix); if(config->bridges[i].topics[j].remote_prefix) _mosquitto_free(config->bridges[i].topics[j].remote_prefix); if(config->bridges[i].topics[j].local_topic) _mosquitto_free(config->bridges[i].topics[j].local_topic); if(config->bridges[i].topics[j].remote_topic) _mosquitto_free(config->bridges[i].topics[j].remote_topic); } _mosquitto_free(config->bridges[i].topics); } if(config->bridges[i].notification_topic) _mosquitto_free(config->bridges[i].notification_topic); #ifdef WITH_TLS if(config->bridges[i].tls_version) _mosquitto_free(config->bridges[i].tls_version); if(config->bridges[i].tls_cafile) _mosquitto_free(config->bridges[i].tls_cafile); #ifdef REAL_WITH_TLS_PSK if(config->bridges[i].tls_psk_identity) _mosquitto_free(config->bridges[i].tls_psk_identity); if(config->bridges[i].tls_psk) _mosquitto_free(config->bridges[i].tls_psk); #endif #endif } _mosquitto_free(config->bridges); } #endif if(config->auth_plugin) _mosquitto_free(config->auth_plugin); if(config->auth_options){ for(i=0; iauth_option_count; i++){ _mosquitto_free(config->auth_options[i].key); _mosquitto_free(config->auth_options[i].value); } _mosquitto_free(config->auth_options); config->auth_options = NULL; config->auth_option_count = 0; } if(config->log_fptr){ fclose(config->log_fptr); config->log_fptr = NULL; } if(config->log_file){ _mosquitto_free(config->log_file); config->log_file = NULL; } } static void print_usage(void) { printf("mosquitto version %s (build date %s)\n\n", VERSION, TIMESTAMP); printf("mosquitto is an MQTT v3.1.1/v3.1 broker.\n\n"); printf("Usage: mosquitto [-c config_file] [-d] [-h] [-p port]\n\n"); printf(" -c : specify the broker config file.\n"); printf(" -d : put the broker into the background after starting.\n"); printf(" -h : display this help.\n"); printf(" -p : start the broker listening on the specified port.\n"); printf(" Not recommended in conjunction with the -c option.\n"); printf(" -v : verbose mode - enable all logging types. This overrides\n"); printf(" any logging options given in the config file.\n"); printf("\nSee http://mosquitto.org/ for more information.\n\n"); } int mqtt3_config_parse_args(struct mosquitto_db *db, struct mqtt3_config *config, int argc, char *argv[]) { int i; int port_tmp; for(i=1; iconfig_file = argv[i+1]; if(mqtt3_config_read(db, config, false)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open configuration file."); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: -c argument given, but no config file specified."); return MOSQ_ERR_INVAL; } i++; }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--daemon")){ config->daemon = true; }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){ print_usage(); return MOSQ_ERR_INVAL; }else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){ if(i65535){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port specified (%d).", port_tmp); return MOSQ_ERR_INVAL; }else{ if(config->default_listener.port){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Default listener port specified multiple times. Only the latest will be used."); } config->default_listener.port = port_tmp; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: -p argument given, but no port specified."); return MOSQ_ERR_INVAL; } i++; }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){ db->verbose = true; }else{ fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); print_usage(); return MOSQ_ERR_INVAL; } } if(config->listener_count == 0 #ifdef WITH_TLS || config->default_listener.cafile || config->default_listener.capath || config->default_listener.certfile || config->default_listener.keyfile || config->default_listener.ciphers || config->default_listener.psk_hint || config->default_listener.require_certificate || config->default_listener.crlfile || config->default_listener.use_identity_as_username #endif || config->default_listener.use_username_as_clientid || config->default_listener.host || config->default_listener.port || config->default_listener.max_connections != -1 || config->default_listener.mount_point || config->default_listener.protocol != mp_mqtt){ config->listener_count++; config->listeners = _mosquitto_realloc(config->listeners, sizeof(struct _mqtt3_listener)*config->listener_count); if(!config->listeners){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } memset(&config->listeners[config->listener_count-1], 0, sizeof(struct _mqtt3_listener)); if(config->default_listener.port){ config->listeners[config->listener_count-1].port = config->default_listener.port; }else{ config->listeners[config->listener_count-1].port = 1883; } if(config->default_listener.host){ config->listeners[config->listener_count-1].host = config->default_listener.host; }else{ config->listeners[config->listener_count-1].host = NULL; } if(config->default_listener.mount_point){ config->listeners[config->listener_count-1].mount_point = config->default_listener.mount_point; }else{ config->listeners[config->listener_count-1].mount_point = NULL; } config->listeners[config->listener_count-1].max_connections = config->default_listener.max_connections; config->listeners[config->listener_count-1].protocol = config->default_listener.protocol; config->listeners[config->listener_count-1].client_count = 0; config->listeners[config->listener_count-1].socks = NULL; config->listeners[config->listener_count-1].sock_count = 0; config->listeners[config->listener_count-1].client_count = 0; config->listeners[config->listener_count-1].use_username_as_clientid = config->default_listener.use_username_as_clientid; #ifdef WITH_TLS config->listeners[config->listener_count-1].tls_version = config->default_listener.tls_version; config->listeners[config->listener_count-1].cafile = config->default_listener.cafile; config->listeners[config->listener_count-1].capath = config->default_listener.capath; config->listeners[config->listener_count-1].certfile = config->default_listener.certfile; config->listeners[config->listener_count-1].keyfile = config->default_listener.keyfile; config->listeners[config->listener_count-1].ciphers = config->default_listener.ciphers; config->listeners[config->listener_count-1].psk_hint = config->default_listener.psk_hint; config->listeners[config->listener_count-1].require_certificate = config->default_listener.require_certificate; config->listeners[config->listener_count-1].ssl_ctx = NULL; config->listeners[config->listener_count-1].crlfile = config->default_listener.crlfile; config->listeners[config->listener_count-1].use_identity_as_username = config->default_listener.use_identity_as_username; #endif } /* Default to drop to mosquitto user if we are privileged and no user specified. */ if(!config->user){ config->user = "mosquitto"; } if(db->verbose){ config->log_type = INT_MAX; } return MOSQ_ERR_SUCCESS; } /* Copy reloaded config into existing config struct */ void config__copy(struct mqtt3_config *src, struct mqtt3_config *dest) { _mosquitto_free(dest->acl_file); dest->acl_file = src->acl_file; dest->allow_anonymous = src->allow_anonymous; dest->allow_duplicate_messages = src->allow_duplicate_messages; dest->allow_zero_length_clientid = src->allow_zero_length_clientid; _mosquitto_free(dest->auto_id_prefix); dest->auto_id_prefix = src->auto_id_prefix; dest->auto_id_prefix_len = src->auto_id_prefix_len; dest->autosave_interval = src->autosave_interval; dest->autosave_on_changes = src->autosave_on_changes; _mosquitto_free(dest->clientid_prefixes); dest->clientid_prefixes = src->clientid_prefixes; dest->connection_messages = src->connection_messages; dest->log_dest = src->log_dest; dest->log_facility = src->log_facility; dest->log_type = src->log_type; dest->log_timestamp = src->log_timestamp; _mosquitto_free(dest->log_file); dest->log_file = src->log_file; dest->message_size_limit = src->message_size_limit; _mosquitto_free(dest->password_file); dest->password_file = src->password_file; dest->persistence = src->persistence; _mosquitto_free(dest->persistence_location); dest->persistence_location = src->persistence_location; _mosquitto_free(dest->persistence_file); dest->persistence_file = src->persistence_file; _mosquitto_free(dest->persistence_filepath); dest->persistence_filepath = src->persistence_filepath; dest->persistent_client_expiration = src->persistent_client_expiration; _mosquitto_free(dest->psk_file); dest->psk_file = src->psk_file; dest->queue_qos0_messages = src->queue_qos0_messages; dest->retry_interval = src->retry_interval; dest->sys_interval = src->sys_interval; dest->upgrade_outgoing_qos = src->upgrade_outgoing_qos; #ifdef WITH_WEBSOCKETS dest->websockets_log_level = src->websockets_log_level; #endif } int mqtt3_config_read(struct mosquitto_db *db, struct mqtt3_config *config, bool reload) { int rc = MOSQ_ERR_SUCCESS; struct config_recurse cr; int lineno; int len; struct mqtt3_config config_reload; #ifdef WITH_BRIDGE int i; #endif if(reload){ memset(&config_reload, 0, sizeof(struct mqtt3_config)); } cr.log_dest = MQTT3_LOG_NONE; cr.log_dest_set = 0; cr.log_type = MOSQ_LOG_NONE; cr.log_type_set = 0; cr.max_inflight_messages = 20; cr.max_queued_messages = 100; if(!db->config_file) return 0; if(reload){ /* Re-initialise appropriate config vars to default for reload. */ _config_init_reload(db, &config_reload); rc = _config_read_file(&config_reload, reload, db->config_file, &cr, 0, &lineno); }else{ rc = _config_read_file(config, reload, db->config_file, &cr, 0, &lineno); } if(rc){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", db->config_file, lineno); return rc; } if(reload){ config__copy(&config_reload, config); } #ifdef WITH_PERSISTENCE if(config->persistence){ if(!config->persistence_file){ config->persistence_file = _mosquitto_strdup("mosquitto.db"); if(!config->persistence_file) return MOSQ_ERR_NOMEM; } if(config->persistence_filepath){ _mosquitto_free(config->persistence_filepath); } if(config->persistence_location && strlen(config->persistence_location)){ len = strlen(config->persistence_location) + strlen(config->persistence_file) + 1; config->persistence_filepath = _mosquitto_malloc(len); if(!config->persistence_filepath) return MOSQ_ERR_NOMEM; snprintf(config->persistence_filepath, len, "%s%s", config->persistence_location, config->persistence_file); }else{ config->persistence_filepath = _mosquitto_strdup(config->persistence_file); if(!config->persistence_filepath) return MOSQ_ERR_NOMEM; } } #endif /* Default to drop to mosquitto user if no other user specified. This must * remain here even though it is covered in mqtt3_parse_args() because this * function may be called on its own. */ if(!config->user){ config->user = "mosquitto"; } mqtt3_db_limits_set(cr.max_inflight_messages, cr.max_queued_messages); #ifdef WITH_BRIDGE for(i=0; ibridge_count; i++){ if(!config->bridges[i].name || !config->bridges[i].addresses || !config->bridges[i].topic_count){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } #ifdef REAL_WITH_TLS_PSK if(config->bridges[i].tls_psk && !config->bridges[i].tls_psk_identity){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration: missing bridge_identity.\n"); return MOSQ_ERR_INVAL; } if(config->bridges[i].tls_psk_identity && !config->bridges[i].tls_psk){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration: missing bridge_psk.\n"); return MOSQ_ERR_INVAL; } #endif } #endif if(cr.log_dest_set){ config->log_dest = cr.log_dest; } if(db->verbose){ config->log_type = INT_MAX; }else if(cr.log_type_set){ config->log_type = cr.log_type; } return MOSQ_ERR_SUCCESS; } int _config_read_file_core(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *cr, int level, int *lineno, FILE *fptr, char **buf, int *buflen) { int rc; char *token; int tmp_int; char *saveptr = NULL; #ifdef WITH_BRIDGE struct _mqtt3_bridge *cur_bridge = NULL; struct _mqtt3_bridge_topic *cur_topic; #endif time_t expiration_mult; char *key; char *conf_file; #ifdef WIN32 HANDLE fh; char dirpath[MAX_PATH]; WIN32_FIND_DATA find_data; #else DIR *dh; struct dirent *de; #endif int len; struct _mqtt3_listener *cur_listener = &config->default_listener; #ifdef WITH_BRIDGE char *address; int i; #endif int lineno_ext; *lineno = 0; while(fgets_extending(buf, buflen, fptr)){ (*lineno)++; if((*buf)[0] != '#' && (*buf)[0] != 10 && (*buf)[0] != 13){ while((*buf)[strlen((*buf))-1] == 10 || (*buf)[strlen((*buf))-1] == 13){ (*buf)[strlen((*buf))-1] = 0; } token = strtok_r((*buf), " ", &saveptr); if(token){ if(!strcmp(token, "acl_file")){ if(reload){ if(config->acl_file){ _mosquitto_free(config->acl_file); config->acl_file = NULL; } } if(_conf_parse_string(&token, "acl_file", &config->acl_file, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "address") || !strcmp(token, "addresses")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge || cur_bridge->addresses){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } while((token = strtok_r(NULL, " ", &saveptr))){ cur_bridge->address_count++; cur_bridge->addresses = _mosquitto_realloc(cur_bridge->addresses, sizeof(struct bridge_address)*cur_bridge->address_count); if(!cur_bridge->addresses){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } cur_bridge->addresses[cur_bridge->address_count-1].address = token; } for(i=0; iaddress_count; i++){ address = strtok_r(cur_bridge->addresses[i].address, ":", &saveptr); if(address){ token = strtok_r(NULL, ":", &saveptr); if(token){ tmp_int = atoi(token); if(tmp_int < 1 || tmp_int > 65535){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port value (%d).", tmp_int); return MOSQ_ERR_INVAL; } cur_bridge->addresses[i].port = tmp_int; }else{ cur_bridge->addresses[i].port = 1883; } cur_bridge->addresses[i].address = _mosquitto_strdup(address); _conf_attempt_resolve(address, "bridge address", MOSQ_LOG_WARNING, "Warning"); } } if(cur_bridge->address_count == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty address value in configuration."); return MOSQ_ERR_INVAL; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "allow_anonymous")){ if(_conf_parse_bool(&token, "allow_anonymous", &config->allow_anonymous, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "allow_duplicate_messages")){ if(_conf_parse_bool(&token, "allow_duplicate_messages", &config->allow_duplicate_messages, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "allow_zero_length_clientid")){ if(_conf_parse_bool(&token, "allow_zero_length_clientid", &config->allow_zero_length_clientid, saveptr)) return MOSQ_ERR_INVAL; }else if(!strncmp(token, "auth_opt_", 9)){ if(strlen(token) < 12){ /* auth_opt_ == 9, + one digit key == 10, + one space == 11, + one value == 12 */ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid auth_opt_ config option."); return MOSQ_ERR_INVAL; } key = _mosquitto_strdup(&token[9]); if(!key){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; }else if(STREMPTY(key)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid auth_opt_ config option."); return MOSQ_ERR_INVAL; } token += 9+strlen(key)+1; while(token[0] == ' ' || token[0] == '\t'){ token++; } if(token[0]){ config->auth_option_count++; config->auth_options = _mosquitto_realloc(config->auth_options, config->auth_option_count*sizeof(struct mosquitto_auth_opt)); if(!config->auth_options){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } config->auth_options[config->auth_option_count-1].key = key; config->auth_options[config->auth_option_count-1].value = _mosquitto_strdup(token); if(!config->auth_options[config->auth_option_count-1].value){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", key); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "auth_plugin")){ if(reload) continue; // Auth plugin not currently valid for reloading. if(_conf_parse_string(&token, "auth_plugin", &config->auth_plugin, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "auth_plugin_deny_special_chars")){ if(reload) continue; // Auth plugin not currently valid for reloading. if(_conf_parse_bool(&token, "auth_plugin_deny_special_chars", &config->auth_plugin_deny_special_chars, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "auto_id_prefix")){ if(_conf_parse_string(&token, "auto_id_prefix", &config->auto_id_prefix, saveptr)) return MOSQ_ERR_INVAL; if(config->auto_id_prefix){ config->auto_id_prefix_len = strlen(config->auto_id_prefix); }else{ config->auto_id_prefix_len = 0; } }else if(!strcmp(token, "autosave_interval")){ if(_conf_parse_int(&token, "autosave_interval", &config->autosave_interval, saveptr)) return MOSQ_ERR_INVAL; if(config->autosave_interval < 0) config->autosave_interval = 0; }else if(!strcmp(token, "autosave_on_changes")){ if(_conf_parse_bool(&token, "autosave_on_changes", &config->autosave_on_changes, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "bind_address")){ if(reload) continue; // Listener not valid for reloading. if(_conf_parse_string(&token, "default listener bind_address", &config->default_listener.host, saveptr)) return MOSQ_ERR_INVAL; if(_conf_attempt_resolve(config->default_listener.host, "bind_address", MOSQ_LOG_ERR, "Error")){ return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "bridge_attempt_unsubscribe")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_bool(&token, "bridge_attempt_unsubscribe", &cur_bridge->attempt_unsubscribe, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "bridge_cafile")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } #ifdef REAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; } #endif if(_conf_parse_string(&token, "bridge_cafile", &cur_bridge->tls_cafile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "bridge_capath")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } #ifdef REAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; } #endif if(_conf_parse_string(&token, "bridge_capath", &cur_bridge->tls_capath, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "bridge_certfile")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } #ifdef REAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; } #endif if(_conf_parse_string(&token, "bridge_certfile", &cur_bridge->tls_certfile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "bridge_identity")){ #if defined(WITH_BRIDGE) && defined(REAL_WITH_TLS_PSK) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(cur_bridge->tls_cafile || cur_bridge->tls_capath || cur_bridge->tls_certfile || cur_bridge->tls_keyfile){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and identity encryption in a single bridge."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge_identity", &cur_bridge->tls_psk_identity, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS-PSK support not available."); #endif }else if(!strcmp(token, "bridge_insecure")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_bool(&token, "bridge_insecure", &cur_bridge->tls_insecure, saveptr)) return MOSQ_ERR_INVAL; if(cur_bridge->tls_insecure){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge %s using insecure mode.", cur_bridge->name); } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS-PSK support not available."); #endif }else if(!strcmp(token, "bridge_keyfile")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } #ifdef REAL_WITH_TLS_PSK if(cur_bridge->tls_psk_identity || cur_bridge->tls_psk){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; } #endif if(_conf_parse_string(&token, "bridge_keyfile", &cur_bridge->tls_keyfile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "bridge_protocol_version")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, "", &saveptr); if(token){ if(!strcmp(token, "mqttv31")){ cur_bridge->protocol_version = mosq_p_mqtt31; }else if(!strcmp(token, "mqttv311")){ cur_bridge->protocol_version = mosq_p_mqtt311; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge_protocol_version value (%s).", token); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty bridge_protocol_version value in configuration."); return MOSQ_ERR_INVAL; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "bridge_psk")){ #if defined(WITH_BRIDGE) && defined(REAL_WITH_TLS_PSK) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(cur_bridge->tls_cafile || cur_bridge->tls_capath || cur_bridge->tls_certfile || cur_bridge->tls_keyfile){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single bridge."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge_psk", &cur_bridge->tls_psk, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS-PSK support not available."); #endif }else if(!strcmp(token, "bridge_tls_version")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge_tls_version", &cur_bridge->tls_version, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "cafile")){ #if defined(WITH_TLS) if(reload) continue; // Listeners not valid for reloading. if(cur_listener->psk_hint){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single listener."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "cafile", &cur_listener->cafile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "capath")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "capath", &cur_listener->capath, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "certfile")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(cur_listener->psk_hint){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot use both certificate and psk encryption in a single listener."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "certfile", &cur_listener->certfile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "ciphers")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "ciphers", &cur_listener->ciphers, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "clientid") || !strcmp(token, "remote_clientid")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge remote clientid", &cur_bridge->remote_clientid, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "cleansession")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_bool(&token, "cleansession", &cur_bridge->clean_session, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "clientid_prefixes")){ if(reload){ if(config->clientid_prefixes){ _mosquitto_free(config->clientid_prefixes); config->clientid_prefixes = NULL; } } if(_conf_parse_string(&token, "clientid_prefixes", &config->clientid_prefixes, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "connection")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME token = strtok_r(NULL, " ", &saveptr); if(token){ /* Check for existing bridge name. */ for(i=0; ibridge_count; i++){ if(!strcmp(config->bridges[i].name, token)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate bridge name \"%s\".", token); return MOSQ_ERR_INVAL; } } config->bridge_count++; config->bridges = _mosquitto_realloc(config->bridges, config->bridge_count*sizeof(struct _mqtt3_bridge)); if(!config->bridges){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } cur_bridge = &(config->bridges[config->bridge_count-1]); memset(cur_bridge, 0, sizeof(struct _mqtt3_bridge)); cur_bridge->name = _mosquitto_strdup(token); if(!cur_bridge->name){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } cur_bridge->keepalive = 60; cur_bridge->notifications = true; cur_bridge->start_type = bst_automatic; cur_bridge->idle_timeout = 60; cur_bridge->restart_timeout = 30; cur_bridge->threshold = 10; cur_bridge->try_private = true; cur_bridge->attempt_unsubscribe = true; cur_bridge->protocol_version = mosq_p_mqtt31; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty connection value in configuration."); return MOSQ_ERR_INVAL; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "connection_messages")){ if(_conf_parse_bool(&token, token, &config->connection_messages, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "crlfile")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "crlfile", &cur_listener->crlfile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "http_dir")){ #ifdef WITH_WEBSOCKETS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "http_dir", &cur_listener->http_dir, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Websockets support not available."); #endif }else if(!strcmp(token, "idle_timeout")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_int(&token, "idle_timeout", &cur_bridge->idle_timeout, saveptr)) return MOSQ_ERR_INVAL; if(cur_bridge->idle_timeout < 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "idle_timeout interval too low, using 1 second."); cur_bridge->idle_timeout = 1; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "include_dir")){ if(level == 0){ /* Only process include_dir from the main config file. */ token = strtok_r(NULL, "", &saveptr); if(!token){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty include_dir value in configuration."); } #ifdef WIN32 snprintf(dirpath, MAX_PATH, "%s\\*.conf", token); fh = FindFirstFile(dirpath, &find_data); if(fh == INVALID_HANDLE_VALUE){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", token); return 1; } do{ len = strlen(token)+1+strlen(find_data.cFileName)+1; conf_file = _mosquitto_malloc(len+1); if(!conf_file){ FindClose(fh); return MOSQ_ERR_NOMEM; } snprintf(conf_file, len, "%s\\%s", token, find_data.cFileName); conf_file[len] = '\0'; rc = _config_read_file(config, reload, conf_file, cr, level+1, &lineno_ext); if(rc){ FindClose(fh); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext); _mosquitto_free(conf_file); return rc; } _mosquitto_free(conf_file); }while(FindNextFile(fh, &find_data)); FindClose(fh); #else dh = opendir(token); if(!dh){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open include_dir '%s'.", token); return 1; } while((de = readdir(dh)) != NULL){ if(strlen(de->d_name) > 5){ if(!strcmp(&de->d_name[strlen(de->d_name)-5], ".conf")){ len = strlen(token)+1+strlen(de->d_name)+1; conf_file = _mosquitto_malloc(len+1); if(!conf_file){ closedir(dh); return MOSQ_ERR_NOMEM; } snprintf(conf_file, len, "%s/%s", token, de->d_name); conf_file[len] = '\0'; rc = _config_read_file(config, reload, conf_file, cr, level+1, &lineno_ext); if(rc){ closedir(dh); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error found at %s:%d.", conf_file, lineno_ext); _mosquitto_free(conf_file); return rc; } _mosquitto_free(conf_file); } } } closedir(dh); #endif } }else if(!strcmp(token, "keepalive_interval")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_int(&token, "keepalive_interval", &cur_bridge->keepalive, saveptr)) return MOSQ_ERR_INVAL; if(cur_bridge->keepalive < 5){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "keepalive interval too low, using 5 seconds."); cur_bridge->keepalive = 5; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "keyfile")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "keyfile", &cur_listener->keyfile, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "listener")){ if(reload) continue; // Listeners not valid for reloading. token = strtok_r(NULL, " ", &saveptr); if(token){ config->listener_count++; config->listeners = _mosquitto_realloc(config->listeners, sizeof(struct _mqtt3_listener)*config->listener_count); if(!config->listeners){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } tmp_int = atoi(token); if(tmp_int < 1 || tmp_int > 65535){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port value (%d).", tmp_int); return MOSQ_ERR_INVAL; } cur_listener = &config->listeners[config->listener_count-1]; memset(cur_listener, 0, sizeof(struct _mqtt3_listener)); cur_listener->protocol = mp_mqtt; cur_listener->port = tmp_int; token = strtok_r(NULL, "", &saveptr); if(token){ cur_listener->host = _mosquitto_strdup(token); }else{ cur_listener->host = NULL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty listener value in configuration."); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "local_clientid")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge local clientd", &cur_bridge->local_clientid, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "local_password")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge local_password", &cur_bridge->local_password, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "local_username")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge local_username", &cur_bridge->local_username, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "log_dest")){ token = strtok_r(NULL, " ", &saveptr); if(token){ cr->log_dest_set = 1; if(!strcmp(token, "none")){ cr->log_dest = MQTT3_LOG_NONE; }else if(!strcmp(token, "syslog")){ cr->log_dest |= MQTT3_LOG_SYSLOG; }else if(!strcmp(token, "stdout")){ cr->log_dest |= MQTT3_LOG_STDOUT; }else if(!strcmp(token, "stderr")){ cr->log_dest |= MQTT3_LOG_STDERR; }else if(!strcmp(token, "topic")){ cr->log_dest |= MQTT3_LOG_TOPIC; }else if(!strcmp(token, "file")){ cr->log_dest |= MQTT3_LOG_FILE; if(config->log_fptr || config->log_file){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate \"log_dest file\" value."); return MOSQ_ERR_INVAL; } /* Get remaining string. */ token = &token[strlen(token)+1]; while(token[0] == ' ' || token[0] == '\t'){ token++; } if(token[0]){ config->log_file = _mosquitto_strdup(token); if(!config->log_file){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty \"log_dest file\" value in configuration."); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid log_dest value (%s).", token); return MOSQ_ERR_INVAL; } #if defined(WIN32) || defined(__CYGWIN__) if(service_handle){ if(cr->log_dest == MQTT3_LOG_STDOUT || cr->log_dest == MQTT3_LOG_STDERR){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Cannot log to stdout/stderr when running as a Windows service."); return MOSQ_ERR_INVAL; } } #endif }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty log_dest value in configuration."); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "log_facility")){ #if defined(WIN32) || defined(__CYGWIN__) _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: log_facility not supported on Windows."); #else if(_conf_parse_int(&token, "log_facility", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; switch(tmp_int){ case 0: config->log_facility = LOG_LOCAL0; break; case 1: config->log_facility = LOG_LOCAL1; break; case 2: config->log_facility = LOG_LOCAL2; break; case 3: config->log_facility = LOG_LOCAL3; break; case 4: config->log_facility = LOG_LOCAL4; break; case 5: config->log_facility = LOG_LOCAL5; break; case 6: config->log_facility = LOG_LOCAL6; break; case 7: config->log_facility = LOG_LOCAL7; break; default: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid log_facility value (%d).", tmp_int); return MOSQ_ERR_INVAL; } #endif }else if(!strcmp(token, "log_timestamp")){ if(_conf_parse_bool(&token, token, &config->log_timestamp, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "log_type")){ token = strtok_r(NULL, " ", &saveptr); if(token){ cr->log_type_set = 1; if(!strcmp(token, "none")){ cr->log_type = MOSQ_LOG_NONE; }else if(!strcmp(token, "information")){ cr->log_type |= MOSQ_LOG_INFO; }else if(!strcmp(token, "notice")){ cr->log_type |= MOSQ_LOG_NOTICE; }else if(!strcmp(token, "warning")){ cr->log_type |= MOSQ_LOG_WARNING; }else if(!strcmp(token, "error")){ cr->log_type |= MOSQ_LOG_ERR; }else if(!strcmp(token, "debug")){ cr->log_type |= MOSQ_LOG_DEBUG; }else if(!strcmp(token, "subscribe")){ cr->log_type |= MOSQ_LOG_SUBSCRIBE; }else if(!strcmp(token, "unsubscribe")){ cr->log_type |= MOSQ_LOG_UNSUBSCRIBE; #ifdef WITH_WEBSOCKETS }else if(!strcmp(token, "websockets")){ cr->log_type |= MOSQ_LOG_WEBSOCKETS; #endif }else if(!strcmp(token, "all")){ cr->log_type = INT_MAX; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid log_type value (%s).", token); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty log_type value in configuration."); } }else if(!strcmp(token, "max_connections")){ if(reload) continue; // Listeners not valid for reloading. token = strtok_r(NULL, " ", &saveptr); if(token){ cur_listener->max_connections = atoi(token); if(cur_listener->max_connections < 0) cur_listener->max_connections = -1; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_connections value in configuration."); } }else if(!strcmp(token, "max_inflight_messages")){ token = strtok_r(NULL, " ", &saveptr); if(token){ cr->max_inflight_messages = atoi(token); if(cr->max_inflight_messages < 0) cr->max_inflight_messages = 0; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_inflight_messages value in configuration."); } }else if(!strcmp(token, "max_queued_messages")){ token = strtok_r(NULL, " ", &saveptr); if(token){ cr->max_queued_messages = atoi(token); if(cr->max_queued_messages < 0) cr->max_queued_messages = 0; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty max_queued_messages value in configuration."); } }else if(!strcmp(token, "memory_limit")){ size_t lim; if(_conf_parse_int(&token, "memory_limit", (int *)&lim, saveptr)) return MOSQ_ERR_INVAL; if(lim < 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid memory_limit value (%lu).", lim); return MOSQ_ERR_INVAL; } memory__set_limit(lim); }else if(!strcmp(token, "message_size_limit")){ if(_conf_parse_int(&token, "message_size_limit", (int *)&config->message_size_limit, saveptr)) return MOSQ_ERR_INVAL; if(config->message_size_limit > MQTT_MAX_PAYLOAD){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid message_size_limit value (%d).", config->message_size_limit); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "mount_point")){ if(reload) continue; // Listeners not valid for reloading. if(config->listener_count == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: You must use create a listener before using the mount_point option in the configuration file."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "mount_point", &cur_listener->mount_point, saveptr)) return MOSQ_ERR_INVAL; if(mosquitto_pub_topic_check(cur_listener->mount_point) != MOSQ_ERR_SUCCESS){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid mount_point '%s'. Does it contain a wildcard character?", cur_listener->mount_point); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "notifications")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_bool(&token, "notifications", &cur_bridge->notifications, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "notification_topic")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "notification_topic", &cur_bridge->notification_topic, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "password") || !strcmp(token, "remote_password")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_string(&token, "bridge remote_password", &cur_bridge->remote_password, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "password_file")){ if(reload){ if(config->password_file){ _mosquitto_free(config->password_file); config->password_file = NULL; } } if(_conf_parse_string(&token, "password_file", &config->password_file, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "persistence") || !strcmp(token, "retained_persistence")){ if(_conf_parse_bool(&token, token, &config->persistence, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "persistence_file")){ if(_conf_parse_string(&token, "persistence_file", &config->persistence_file, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "persistence_location")){ if(_conf_parse_string(&token, "persistence_location", &config->persistence_location, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "persistent_client_expiration")){ token = strtok_r(NULL, " ", &saveptr); if(token){ switch(token[strlen(token)-1]){ case 'h': expiration_mult = 3600; break; case 'd': expiration_mult = 86400; break; case 'w': expiration_mult = 86400*7; break; case 'm': expiration_mult = 86400*30; break; case 'y': expiration_mult = 86400*365; break; default: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid persistent_client_expiration duration in configuration."); return MOSQ_ERR_INVAL; } token[strlen(token)-1] = '\0'; config->persistent_client_expiration = atoi(token)*expiration_mult; if(config->persistent_client_expiration <= 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid persistent_client_expiration duration in configuration."); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty persistent_client_expiration value in configuration."); } }else if(!strcmp(token, "pid_file")){ if(reload) continue; // pid file not valid for reloading. if(_conf_parse_string(&token, "pid_file", &config->pid_file, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "port")){ if(reload) continue; // Listener not valid for reloading. if(config->default_listener.port){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Default listener port specified multiple times. Only the latest will be used."); } if(_conf_parse_int(&token, "port", &tmp_int, saveptr)) return MOSQ_ERR_INVAL; if(tmp_int < 1 || tmp_int > 65535){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid port value (%d).", tmp_int); return MOSQ_ERR_INVAL; } config->default_listener.port = tmp_int; }else if(!strcmp(token, "protocol")){ token = strtok_r(NULL, " ", &saveptr); if(token){ if(!strcmp(token, "mqtt")){ cur_listener->protocol = mp_mqtt; /* }else if(!strcmp(token, "mqttsn")){ cur_listener->protocol = mp_mqttsn; */ }else if(!strcmp(token, "websockets")){ #ifdef WITH_WEBSOCKETS cur_listener->protocol = mp_websockets; config->have_websockets_listener = true; #else _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Websockets support not available."); return MOSQ_ERR_INVAL; #endif }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid protocol value (%s).", token); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty protocol value in configuration."); } }else if(!strcmp(token, "psk_file")){ #ifdef REAL_WITH_TLS_PSK if(reload){ if(config->psk_file){ _mosquitto_free(config->psk_file); config->psk_file = NULL; } } if(_conf_parse_string(&token, "psk_file", &config->psk_file, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS/TLS-PSK support not available."); #endif }else if(!strcmp(token, "psk_hint")){ #ifdef REAL_WITH_TLS_PSK if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "psk_hint", &cur_listener->psk_hint, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS/TLS-PSK support not available."); #endif }else if(!strcmp(token, "queue_qos0_messages")){ if(_conf_parse_bool(&token, token, &config->queue_qos0_messages, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "require_certificate")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_bool(&token, "require_certificate", &cur_listener->require_certificate, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "restart_timeout")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_int(&token, "restart_timeout", &cur_bridge->restart_timeout, saveptr)) return MOSQ_ERR_INVAL; if(cur_bridge->restart_timeout < 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "restart_timeout interval too low, using 1 second."); cur_bridge->restart_timeout = 1; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "retry_interval")){ if(_conf_parse_int(&token, "retry_interval", &config->retry_interval, saveptr)) return MOSQ_ERR_INVAL; if(config->retry_interval < 1 || config->retry_interval > 3600){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid retry_interval value (%d).", config->retry_interval); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "round_robin")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_bool(&token, "round_robin", &cur_bridge->round_robin, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "start_type")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ if(!strcmp(token, "automatic")){ cur_bridge->start_type = bst_automatic; }else if(!strcmp(token, "lazy")){ cur_bridge->start_type = bst_lazy; }else if(!strcmp(token, "manual")){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Manual start_type not supported."); return MOSQ_ERR_INVAL; }else if(!strcmp(token, "once")){ cur_bridge->start_type = bst_once; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid start_type value in configuration (%s).", token); return MOSQ_ERR_INVAL; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty start_type value in configuration."); return MOSQ_ERR_INVAL; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "store_clean_interval")){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: store_clean_interval is no longer needed."); }else if(!strcmp(token, "sys_interval")){ if(_conf_parse_int(&token, "sys_interval", &config->sys_interval, saveptr)) return MOSQ_ERR_INVAL; if(config->sys_interval < 0 || config->sys_interval > 65535){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid sys_interval value (%d).", config->sys_interval); return MOSQ_ERR_INVAL; } }else if(!strcmp(token, "threshold")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_int(&token, "threshold", &cur_bridge->threshold, saveptr)) return MOSQ_ERR_INVAL; if(cur_bridge->threshold < 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "threshold too low, using 1 message."); cur_bridge->threshold = 1; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "tls_version")){ #if defined(WITH_TLS) if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_string(&token, "tls_version", &cur_listener->tls_version, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "topic")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ cur_bridge->topic_count++; cur_bridge->topics = _mosquitto_realloc(cur_bridge->topics, sizeof(struct _mqtt3_bridge_topic)*cur_bridge->topic_count); if(!cur_bridge->topics){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } cur_topic = &cur_bridge->topics[cur_bridge->topic_count-1]; if(!strcmp(token, "\"\"")){ cur_topic->topic = NULL; }else{ cur_topic->topic = _mosquitto_strdup(token); if(!cur_topic->topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } cur_topic->direction = bd_out; cur_topic->qos = 0; cur_topic->local_prefix = NULL; cur_topic->remote_prefix = NULL; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty topic value in configuration."); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ if(!strcasecmp(token, "out")){ cur_topic->direction = bd_out; }else if(!strcasecmp(token, "in")){ cur_topic->direction = bd_in; }else if(!strcasecmp(token, "both")){ cur_topic->direction = bd_both; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic direction '%s'.", token); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ cur_topic->qos = atoi(token); if(cur_topic->qos < 0 || cur_topic->qos > 2){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge QoS level '%s'.", token); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ cur_bridge->topic_remapping = true; if(!strcmp(token, "\"\"")){ cur_topic->local_prefix = NULL; }else{ if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", token); return MOSQ_ERR_INVAL; } cur_topic->local_prefix = _mosquitto_strdup(token); if(!cur_topic->local_prefix){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } token = strtok_r(NULL, " ", &saveptr); if(token){ if(!strcmp(token, "\"\"")){ cur_topic->remote_prefix = NULL; }else{ if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic remote prefix '%s'.", token); return MOSQ_ERR_INVAL; } cur_topic->remote_prefix = _mosquitto_strdup(token); if(!cur_topic->remote_prefix){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } } } } } if(cur_topic->topic == NULL && (cur_topic->local_prefix == NULL || cur_topic->remote_prefix == NULL)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge remapping."); return MOSQ_ERR_INVAL; } if(cur_topic->local_prefix){ if(cur_topic->topic){ len = strlen(cur_topic->topic) + strlen(cur_topic->local_prefix)+1; cur_topic->local_topic = _mosquitto_malloc(len+1); if(!cur_topic->local_topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } snprintf(cur_topic->local_topic, len+1, "%s%s", cur_topic->local_prefix, cur_topic->topic); cur_topic->local_topic[len] = '\0'; }else{ cur_topic->local_topic = _mosquitto_strdup(cur_topic->local_prefix); if(!cur_topic->local_topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } }else{ cur_topic->local_topic = _mosquitto_strdup(cur_topic->topic); if(!cur_topic->local_topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } if(cur_topic->remote_prefix){ if(cur_topic->topic){ len = strlen(cur_topic->topic) + strlen(cur_topic->remote_prefix)+1; cur_topic->remote_topic = _mosquitto_malloc(len+1); if(!cur_topic->remote_topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } snprintf(cur_topic->remote_topic, len, "%s%s", cur_topic->remote_prefix, cur_topic->topic); cur_topic->remote_topic[len] = '\0'; }else{ cur_topic->remote_topic = _mosquitto_strdup(cur_topic->remote_prefix); if(!cur_topic->remote_topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } }else{ cur_topic->remote_topic = _mosquitto_strdup(cur_topic->topic); if(!cur_topic->remote_topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "try_private")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } if(_conf_parse_bool(&token, "try_private", &cur_bridge->try_private, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "upgrade_outgoing_qos")){ if(_conf_parse_bool(&token, token, &config->upgrade_outgoing_qos, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "use_identity_as_username")){ #ifdef WITH_TLS if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_bool(&token, "use_identity_as_username", &cur_listener->use_identity_as_username, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: TLS support not available."); #endif }else if(!strcmp(token, "user")){ if(reload) continue; // Drop privileges user not valid for reloading. if(_conf_parse_string(&token, "user", &config->user, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "use_username_as_clientid")){ if(reload) continue; // Listeners not valid for reloading. if(_conf_parse_bool(&token, "use_username_as_clientid", &cur_listener->use_username_as_clientid, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "username") || !strcmp(token, "remote_username")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME if(!cur_bridge){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ if(cur_bridge->remote_username){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate username value in bridge configuration."); return MOSQ_ERR_INVAL; } cur_bridge->remote_username = _mosquitto_strdup(token); if(!cur_bridge->remote_username){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty username value in configuration."); return MOSQ_ERR_INVAL; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif }else if(!strcmp(token, "websockets_log_level")){ #ifdef WITH_WEBSOCKETS if(_conf_parse_int(&token, "websockets_log_level", &config->websockets_log_level, saveptr)) return MOSQ_ERR_INVAL; #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Websockets support not available."); #endif }else if(!strcmp(token, "trace_level") || !strcmp(token, "ffdc_output") || !strcmp(token, "max_log_entries") || !strcmp(token, "trace_output")){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Unsupported rsmb configuration option \"%s\".", token); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unknown configuration variable \"%s\".", token); return MOSQ_ERR_INVAL; } } } } return MOSQ_ERR_SUCCESS; } int _config_read_file(struct mqtt3_config *config, bool reload, const char *file, struct config_recurse *cr, int level, int *lineno) { int rc; FILE *fptr = NULL; char *buf; int buflen; fptr = _mosquitto_fopen(file, "rt", false); if(!fptr){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open config file %s\n", file); return 1; } buflen = 1000; buf = _mosquitto_malloc(buflen); if(!buf){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } rc = _config_read_file_core(config, reload, file, cr, level, lineno, fptr, &buf, &buflen); _mosquitto_free(buf); fclose(fptr); return rc; } static int _conf_parse_bool(char **token, const char *name, bool *value, char *saveptr) { *token = strtok_r(NULL, " ", &saveptr); if(*token){ if(!strcmp(*token, "false") || !strcmp(*token, "0")){ *value = false; }else if(!strcmp(*token, "true") || !strcmp(*token, "1")){ *value = true; }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid %s value (%s).", name, *token); } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", name); return MOSQ_ERR_INVAL; } return MOSQ_ERR_SUCCESS; } static int _conf_parse_int(char **token, const char *name, int *value, char *saveptr) { *token = strtok_r(NULL, " ", &saveptr); if(*token){ *value = atoi(*token); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", name); return MOSQ_ERR_INVAL; } return MOSQ_ERR_SUCCESS; } static int _conf_parse_string(char **token, const char *name, char **value, char *saveptr) { *token = strtok_r(NULL, "", &saveptr); if(*token){ if(*value){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Duplicate %s value in configuration.", name); return MOSQ_ERR_INVAL; } /* Deal with multiple spaces at the beginning of the string. */ while((*token)[0] == ' ' || (*token)[0] == '\t'){ (*token)++; } *value = _mosquitto_strdup(*token); if(!*value){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Empty %s value in configuration.", name); return MOSQ_ERR_INVAL; } return MOSQ_ERR_SUCCESS; } mosquitto-1.4.15/src/lib_load.h0000664000175000017500000000201413245550210015365 0ustar rogerroger/* Copyright (c) 2012-2018 Roger Light 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 LIB_LOAD_H #define LIB_LOAD_H #ifdef WIN32 # include #else # include #endif #ifdef WIN32 # define LIB_LOAD(A) LoadLibrary(A) # define LIB_CLOSE(A) FreeLibrary(A) # define LIB_SYM(HANDLE, SYM) GetProcAddress(HANDLE, SYM) #else # define LIB_LOAD(A) dlopen(A, RTLD_NOW|RTLD_GLOBAL) # define LIB_CLOSE(A) dlclose(A) # define LIB_SYM(HANDLE, SYM) dlsym(HANDLE, SYM) #endif #define LIB_SYM_EASY(MEMBER, HANDLE, SYM) if(!(MEMBER = LIB_SYM(HANDLE, SYM)) return 1 #endif mosquitto-1.4.15/src/mosquitto_passwd.c0000664000175000017500000002704213245550210017250 0ustar rogerroger/* Copyright (c) 2012-2018 Roger Light 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 #include #include #include #include #include #include #include #ifdef WIN32 # include # include # ifndef __cplusplus # define bool char # define true 1 # define false 0 # endif # define snprintf sprintf_s # include #else # include # include # include #endif #define MAX_BUFFER_LEN 1024 #define SALT_LEN 12 int base64_encode(unsigned char *in, unsigned int in_len, char **encoded) { BIO *bmem, *b64; BUF_MEM *bptr; b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); BIO_write(b64, in, in_len); if(BIO_flush(b64) != 1){ BIO_free_all(b64); return 1; } BIO_get_mem_ptr(b64, &bptr); *encoded = malloc(bptr->length+1); if(!(*encoded)){ BIO_free_all(b64); return 1; } memcpy(*encoded, bptr->data, bptr->length); (*encoded)[bptr->length] = '\0'; BIO_free_all(b64); return 0; } void print_usage(void) { printf("mosquitto_passwd is a tool for managing password files for mosquitto.\n\n"); printf("Usage: mosquitto_passwd [-c | -D] passwordfile username\n"); printf(" mosquitto_passwd -b passwordfile username password\n"); printf(" mosquitto_passwd -U passwordfile\n"); printf(" -b : run in batch mode to allow passing passwords on the command line.\n"); printf(" -c : create a new password file. This will overwrite existing files.\n"); printf(" -D : delete the username rather than adding/updating its password.\n"); printf(" -U : update a plain text password file to use hashed passwords.\n"); printf("\nSee http://mosquitto.org/ for more information.\n\n"); } int output_new_password(FILE *fptr, const char *username, const char *password) { int rc; unsigned char salt[SALT_LEN]; char *salt64 = NULL, *hash64 = NULL; unsigned char hash[EVP_MAX_MD_SIZE]; unsigned int hash_len; const EVP_MD *digest; #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_MD_CTX context; #else EVP_MD_CTX *context; #endif rc = RAND_bytes(salt, SALT_LEN); if(!rc){ fprintf(stderr, "Error: Insufficient entropy available to perform password generation.\n"); return 1; } rc = base64_encode(salt, SALT_LEN, &salt64); if(rc){ if(salt64) free(salt64); fprintf(stderr, "Error: Unable to encode salt.\n"); return 1; } digest = EVP_get_digestbyname("sha512"); if(!digest){ if(salt64) free(salt64); fprintf(stderr, "Error: Unable to create openssl digest.\n"); return 1; } #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_MD_CTX_init(&context); EVP_DigestInit_ex(&context, digest, NULL); EVP_DigestUpdate(&context, password, strlen(password)); EVP_DigestUpdate(&context, salt, SALT_LEN); EVP_DigestFinal_ex(&context, hash, &hash_len); EVP_MD_CTX_cleanup(&context); #else context = EVP_MD_CTX_new(); EVP_DigestInit_ex(context, digest, NULL); EVP_DigestUpdate(context, password, strlen(password)); EVP_DigestUpdate(context, salt, SALT_LEN); EVP_DigestFinal_ex(context, hash, &hash_len); EVP_MD_CTX_free(context); #endif rc = base64_encode(hash, hash_len, &hash64); if(rc){ if(salt64) free(salt64); if(hash64) free(hash64); fprintf(stderr, "Error: Unable to encode hash.\n"); return 1; } fprintf(fptr, "%s:$6$%s$%s\n", username, salt64, hash64); free(salt64); free(hash64); return 0; } int delete_pwuser(FILE *fptr, FILE *ftmp, const char *username) { char buf[MAX_BUFFER_LEN]; char lbuf[MAX_BUFFER_LEN], *token; bool found = false; while(!feof(fptr) && fgets(buf, MAX_BUFFER_LEN, fptr)){ memcpy(lbuf, buf, MAX_BUFFER_LEN); token = strtok(lbuf, ":"); if(strcmp(username, token)){ fprintf(ftmp, "%s", buf); }else{ found = true; } } if(!found){ fprintf(stderr, "Warning: User %s not found in password file.\n", username); } return 0; } int update_file(FILE *fptr, FILE *ftmp) { char buf[MAX_BUFFER_LEN]; char lbuf[MAX_BUFFER_LEN]; char *username, *password; int rc; int len; while(!feof(fptr) && fgets(buf, MAX_BUFFER_LEN, fptr)){ memcpy(lbuf, buf, MAX_BUFFER_LEN); username = strtok(lbuf, ":"); password = strtok(NULL, ":"); if(password){ len = strlen(password); while(len && (password[len-1] == '\n' || password[len-1] == '\r')){ password[len-1] = '\0'; len = strlen(password); } rc = output_new_password(ftmp, username, password); if(rc) return rc; }else{ fprintf(ftmp, "%s", username); } } return 0; } int update_pwuser(FILE *fptr, FILE *ftmp, const char *username, const char *password) { char buf[MAX_BUFFER_LEN]; char lbuf[MAX_BUFFER_LEN], *token; bool found = false; int rc = 1; while(!feof(fptr) && fgets(buf, MAX_BUFFER_LEN, fptr)){ memcpy(lbuf, buf, MAX_BUFFER_LEN); token = strtok(lbuf, ":"); if(strcmp(username, token)){ fprintf(ftmp, "%s", buf); }else{ rc = output_new_password(ftmp, username, password); found = true; } } if(found){ return rc; }else{ return output_new_password(ftmp, username, password); } } int gets_quiet(char *s, int len) { #ifdef WIN32 HANDLE h; DWORD con_orig, con_quiet; DWORD read_len = 0; memset(s, 0, len); h = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(h, &con_orig); con_quiet = con_orig; con_quiet &= ~ENABLE_ECHO_INPUT; con_quiet |= ENABLE_LINE_INPUT; SetConsoleMode(h, con_quiet); if(!ReadConsole(h, s, len, &read_len, NULL)){ SetConsoleMode(h, con_orig); return 1; } while(s[strlen(s)-1] == 10 || s[strlen(s)-1] == 13){ s[strlen(s)-1] = 0; } if(strlen(s) == 0){ return 1; } SetConsoleMode(h, con_orig); return 0; #else struct termios ts_quiet, ts_orig; char *rs; memset(s, 0, len); tcgetattr(0, &ts_orig); ts_quiet = ts_orig; ts_quiet.c_lflag &= ~(ECHO | ICANON); tcsetattr(0, TCSANOW, &ts_quiet); rs = fgets(s, len, stdin); tcsetattr(0, TCSANOW, &ts_orig); if(!rs){ return 1; }else{ while(s[strlen(s)-1] == 10 || s[strlen(s)-1] == 13){ s[strlen(s)-1] = 0; } if(strlen(s) == 0){ return 1; } } return 0; #endif } int get_password(char *password, int len) { char pw1[MAX_BUFFER_LEN], pw2[MAX_BUFFER_LEN]; printf("Password: "); if(gets_quiet(pw1, MAX_BUFFER_LEN)){ fprintf(stderr, "Error: Empty password.\n"); return 1; } printf("\n"); printf("Reenter password: "); if(gets_quiet(pw2, MAX_BUFFER_LEN)){ fprintf(stderr, "Error: Empty password.\n"); return 1; } printf("\n"); if(strcmp(pw1, pw2)){ fprintf(stderr, "Error: Passwords do not match.\n"); return 1; } strncpy(password, pw1, len); return 0; } int copy_contents(FILE *src, FILE *dest) { char buf[MAX_BUFFER_LEN]; int len; rewind(src); rewind(dest); #ifdef WIN32 _chsize(fileno(dest), 0); #else if(ftruncate(fileno(dest), 0)) return 1; #endif while(!feof(src)){ len = fread(buf, 1, MAX_BUFFER_LEN, src); if(len > 0){ if(fwrite(buf, 1, len, dest) != len){ return 1; } }else{ return !feof(src); } } return 0; } int create_backup(const char *backup_file, FILE *fptr) { FILE *fbackup; fbackup = fopen(backup_file, "wt"); if(!fbackup){ fprintf(stderr, "Error creating backup password file \"%s\", not continuing.\n", backup_file); return 1; } if(copy_contents(fptr, fbackup)){ fprintf(stderr, "Error copying data to backup password file \"%s\", not continuing.\n", backup_file); fclose(fbackup); return 1; } fclose(fbackup); rewind(fptr); return 0; } void handle_sigint(int signal) { #ifndef WIN32 struct termios ts; tcgetattr(0, &ts); ts.c_lflag |= ECHO | ICANON; tcsetattr(0, TCSANOW, &ts); #endif exit(0); } int main(int argc, char *argv[]) { char *password_file_tmp = NULL; char password_file[1024]; char *username = NULL; char *password_cmd = NULL; bool batch_mode = false; bool create_new = false; bool delete_user = false; FILE *fptr, *ftmp; char password[MAX_BUFFER_LEN]; int rc; bool do_update_file = false; char *backup_file; signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); OpenSSL_add_all_digests(); if(argc == 1){ print_usage(); return 1; } if(!strcmp(argv[1], "-c")){ create_new = true; if(argc != 4){ fprintf(stderr, "Error: -c argument given but password file or username missing.\n"); return 1; }else{ password_file_tmp = argv[2]; username = argv[3]; } }else if(!strcmp(argv[1], "-D")){ delete_user = true; if(argc != 4){ fprintf(stderr, "Error: -D argument given but password file or username missing.\n"); return 1; }else{ password_file_tmp = argv[2]; username = argv[3]; } }else if(!strcmp(argv[1], "-b")){ batch_mode = true; if(argc != 5){ fprintf(stderr, "Error: -b argument given but password file, username or password missing.\n"); return 1; }else{ password_file_tmp = argv[2]; username = argv[3]; password_cmd = argv[4]; } }else if(!strcmp(argv[1], "-U")){ if(argc != 3){ fprintf(stderr, "Error: -U argument given but password file missing.\n"); return 1; }else{ do_update_file = true; password_file_tmp = argv[2]; } }else if(argc == 3){ password_file_tmp = argv[1]; username = argv[2]; }else{ print_usage(); return 1; } snprintf(password_file, 1024, "%s", password_file_tmp); if(create_new){ rc = get_password(password, 1024); if(rc) return rc; fptr = fopen(password_file, "wt"); if(!fptr){ fprintf(stderr, "Error: Unable to open file %s for writing. %s.\n", password_file, strerror(errno)); return 1; } rc = output_new_password(fptr, username, password); fclose(fptr); return rc; }else{ fptr = fopen(password_file, "r+t"); if(!fptr){ fprintf(stderr, "Error: Unable to open password file %s. %s.\n", password_file, strerror(errno)); return 1; } backup_file = malloc(strlen(password_file)+5); snprintf(backup_file, strlen(password_file)+5, "%s.tmp", password_file); if(create_backup(backup_file, fptr)){ fclose(fptr); free(backup_file); return 1; } ftmp = tmpfile(); if(!ftmp){ fprintf(stderr, "Error: Unable to open temporary file. %s.\n", strerror(errno)); fclose(fptr); free(backup_file); return 1; } if(delete_user){ rc = delete_pwuser(fptr, ftmp, username); }else if(do_update_file){ rc = update_file(fptr, ftmp); }else{ if(batch_mode){ /* Update password for individual user */ rc = update_pwuser(fptr, ftmp, username, password_cmd); }else{ rc = get_password(password, 1024); if(rc){ fclose(fptr); fclose(ftmp); unlink(backup_file); free(backup_file); return rc; } /* Update password for individual user */ rc = update_pwuser(fptr, ftmp, username, password); } } if(rc){ fclose(fptr); fclose(ftmp); unlink(backup_file); free(backup_file); return rc; } if(copy_contents(ftmp, fptr)){ fclose(fptr); fclose(ftmp); fprintf(stderr, "Error occurred updating password file.\n"); fprintf(stderr, "Password file may be corrupt, check the backup file: %s.\n", backup_file); free(backup_file); return 1; } fclose(fptr); fclose(ftmp); /* Everything was ok so backup no longer needed. May contain old * passwords so shouldn't be kept around. */ unlink(backup_file); free(backup_file); } return 0; } mosquitto-1.4.15/src/net.c0000664000175000017500000003602113245550210014406 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #ifndef WIN32 #include #include #include #include #else #include #include #endif #include #include #include #include #include #ifdef WITH_WRAP #include #endif #ifdef __FreeBSD__ # include # include #endif #ifdef __QNX__ #include #include #include #endif #include #include #include #include #include #ifdef WITH_TLS #include "tls_mosq.h" #include static int tls_ex_index_context = -1; static int tls_ex_index_listener = -1; #endif #ifdef WITH_SYS_TREE extern unsigned int g_socket_connections; #endif static void net__print_error(int log, const char *format_str) { #ifdef WIN32 char *buf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, WSAGetLastError(), LANG_NEUTRAL, &buf, 0, NULL); _mosquitto_log_printf(NULL, log, format_str, buf); LocalFree(buf); #else char buf[256]; strerror_r(errno, buf, 256); _mosquitto_log_printf(NULL, log, format_str, buf); #endif } int mqtt3_socket_accept(struct mosquitto_db *db, mosq_sock_t listensock) { int i; int j; mosq_sock_t new_sock = INVALID_SOCKET; struct mosquitto *new_context; #ifdef WITH_TLS BIO *bio; int rc; char ebuf[256]; unsigned long e; #endif #ifdef WITH_WRAP struct request_info wrap_req; char address[1024]; #endif new_sock = accept(listensock, NULL, 0); if(new_sock == INVALID_SOCKET) return -1; #ifdef WITH_SYS_TREE g_socket_connections++; #endif if(_mosquitto_socket_nonblock(new_sock)){ return INVALID_SOCKET; } #ifdef WITH_WRAP /* Use tcpd / libwrap to determine whether a connection is allowed. */ request_init(&wrap_req, RQ_FILE, new_sock, RQ_DAEMON, "mosquitto", 0); fromhost(&wrap_req); if(!hosts_access(&wrap_req)){ /* Access is denied */ if(!_mosquitto_socket_get_address(new_sock, address, 1024)){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address); } COMPAT_CLOSE(new_sock); return -1; } #endif new_context = mqtt3_context_init(db, new_sock); if(!new_context){ COMPAT_CLOSE(new_sock); return -1; } for(i=0; iconfig->listener_count; i++){ for(j=0; jconfig->listeners[i].sock_count; j++){ if(db->config->listeners[i].socks[j] == listensock){ new_context->listener = &db->config->listeners[i]; new_context->listener->client_count++; break; } } } if(!new_context->listener){ mqtt3_context_cleanup(db, new_context, true); return -1; } if(new_context->listener->max_connections > 0 && new_context->listener->client_count > new_context->listener->max_connections){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address); mqtt3_context_cleanup(db, new_context, true); return -1; } #ifdef WITH_TLS /* TLS init */ for(i=0; iconfig->listener_count; i++){ for(j=0; jconfig->listeners[i].sock_count; j++){ if(db->config->listeners[i].socks[j] == listensock){ if(db->config->listeners[i].ssl_ctx){ new_context->ssl = SSL_new(db->config->listeners[i].ssl_ctx); if(!new_context->ssl){ mqtt3_context_cleanup(db, new_context, true); return -1; } SSL_set_ex_data(new_context->ssl, tls_ex_index_context, new_context); SSL_set_ex_data(new_context->ssl, tls_ex_index_listener, &db->config->listeners[i]); new_context->want_write = true; bio = BIO_new_socket(new_sock, BIO_NOCLOSE); SSL_set_bio(new_context->ssl, bio, bio); ERR_clear_error(); rc = SSL_accept(new_context->ssl); if(rc != 1){ rc = SSL_get_error(new_context->ssl, rc); if(rc == SSL_ERROR_WANT_READ){ /* We always want to read. */ }else if(rc == SSL_ERROR_WANT_WRITE){ new_context->want_write = true; }else{ e = ERR_get_error(); while(e){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s failed: %s.", new_context->address, ERR_error_string(e, ebuf)); e = ERR_get_error(); } mqtt3_context_cleanup(db, new_context, true); return -1; } } } } } } #endif _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port); return new_sock; } #ifdef WITH_TLS static int client_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx) { /* Preverify should check expiry, revocation. */ return preverify_ok; } #endif #ifdef REAL_WITH_TLS_PSK static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { struct mosquitto_db *db; struct mosquitto *context; struct _mqtt3_listener *listener; char *psk_key = NULL; int len; const char *psk_hint; if(!identity) return 0; db = _mosquitto_get_db(); context = SSL_get_ex_data(ssl, tls_ex_index_context); if(!context) return 0; listener = SSL_get_ex_data(ssl, tls_ex_index_listener); if(!listener) return 0; psk_hint = listener->psk_hint; /* The hex to BN conversion results in the length halving, so we can pass * max_psk_len*2 as the max hex key here. */ psk_key = _mosquitto_calloc(1, max_psk_len*2 + 1); if(!psk_key) return 0; if(mosquitto_psk_key_get(db, psk_hint, identity, psk_key, max_psk_len*2) != MOSQ_ERR_SUCCESS){ _mosquitto_free(psk_key); return 0; } len = _mosquitto_hex2bin(psk_key, psk, max_psk_len); if (len < 0){ _mosquitto_free(psk_key); return 0; } if(listener->use_identity_as_username){ context->username = _mosquitto_strdup(identity); if(!context->username){ _mosquitto_free(psk_key); return 0; } } _mosquitto_free(psk_key); return len; } #endif #ifdef WITH_TLS static int _mosquitto_tls_server_ctx(struct _mqtt3_listener *listener) { int ssl_options = 0; char buf[256]; int rc; #ifdef WITH_EC #if OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L EC_KEY *ecdh = NULL; #endif #endif #if OPENSSL_VERSION_NUMBER >= 0x10001000L if(listener->tls_version == NULL){ listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); }else if(!strcmp(listener->tls_version, "tlsv1.2")){ listener->ssl_ctx = SSL_CTX_new(TLSv1_2_server_method()); }else if(!strcmp(listener->tls_version, "tlsv1.1")){ listener->ssl_ctx = SSL_CTX_new(TLSv1_1_server_method()); }else if(!strcmp(listener->tls_version, "tlsv1")){ listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); } #else listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); #endif if(!listener->ssl_ctx){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context."); return 1; } /* Don't accept SSLv2 or SSLv3 */ ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; #ifdef SSL_OP_NO_COMPRESSION /* Disable compression */ ssl_options |= SSL_OP_NO_COMPRESSION; #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE /* Server chooses cipher */ ssl_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; #endif SSL_CTX_set_options(listener->ssl_ctx, ssl_options); #ifdef SSL_MODE_RELEASE_BUFFERS /* Use even less memory per SSL connection. */ SSL_CTX_set_mode(listener->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef WITH_EC #if OPENSSL_VERSION_NUMBER >= 0x10002000L && OPENSSL_VERSION_NUMBER < 0x10100000L SSL_CTX_set_ecdh_auto(listener->ssl_ctx, 1); #elif OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if(!ecdh){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS ECDH curve."); return 1; } SSL_CTX_set_tmp_ecdh(listener->ssl_ctx, ecdh); EC_KEY_free(ecdh); #endif #endif snprintf(buf, 256, "mosquitto-%d", listener->port); SSL_CTX_set_session_id_context(listener->ssl_ctx, (unsigned char *)buf, strlen(buf)); if(listener->ciphers){ rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers); if(rc == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers); return 1; } }else{ rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, "DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH"); if(rc == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers); return 1; } } return MOSQ_ERR_SUCCESS; } #endif /* Creates a socket and listens on port 'port'. * Returns 1 on failure * Returns 0 on success. */ int mqtt3_socket_listen(struct _mqtt3_listener *listener) { mosq_sock_t sock = INVALID_SOCKET; struct addrinfo hints; struct addrinfo *ainfo, *rp; char service[10]; #ifndef WIN32 int ss_opt = 1; #else char ss_opt = 1; #endif #ifdef WITH_TLS int rc; X509_STORE *store; X509_LOOKUP *lookup; #endif if(!listener) return MOSQ_ERR_INVAL; snprintf(service, 10, "%d", listener->port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; if(getaddrinfo(listener->host, service, &hints, &ainfo)) return INVALID_SOCKET; listener->sock_count = 0; listener->socks = NULL; for(rp = ainfo; rp; rp = rp->ai_next){ if(rp->ai_family == AF_INET){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port)); }else if(rp->ai_family == AF_INET6){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port)); }else{ continue; } sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(sock == INVALID_SOCKET){ net__print_error(MOSQ_LOG_WARNING, "Warning: %s"); continue; } listener->sock_count++; listener->socks = _mosquitto_realloc(listener->socks, sizeof(mosq_sock_t)*listener->sock_count); if(!listener->socks){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } listener->socks[listener->sock_count-1] = sock; #ifndef WIN32 ss_opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ss_opt, sizeof(ss_opt)); #endif ss_opt = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt)); if(_mosquitto_socket_nonblock(sock)){ return 1; } if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){ net__print_error(MOSQ_LOG_ERR, "Error: %s"); COMPAT_CLOSE(sock); return 1; } if(listen(sock, 100) == -1){ net__print_error(MOSQ_LOG_ERR, "Error: %s"); COMPAT_CLOSE(sock); return 1; } } freeaddrinfo(ainfo); /* We need to have at least one working socket. */ if(listener->sock_count > 0){ #ifdef WITH_TLS if((listener->cafile || listener->capath) && listener->certfile && listener->keyfile){ if(_mosquitto_tls_server_ctx(listener)){ COMPAT_CLOSE(sock); return 1; } rc = SSL_CTX_load_verify_locations(listener->ssl_ctx, listener->cafile, listener->capath); if(rc == 0){ if(listener->cafile && listener->capath){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\" and capath \"%s\".", listener->cafile, listener->capath); }else if(listener->cafile){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\".", listener->cafile); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check capath \"%s\".", listener->capath); } COMPAT_CLOSE(sock); return 1; } /* FIXME user data? */ if(listener->require_certificate){ SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, client_certificate_verify); }else{ SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_NONE, client_certificate_verify); } rc = SSL_CTX_use_certificate_chain_file(listener->ssl_ctx, listener->certfile); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server certificate \"%s\". Check certfile.", listener->certfile); COMPAT_CLOSE(sock); return 1; } rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile); COMPAT_CLOSE(sock); return 1; } rc = SSL_CTX_check_private_key(listener->ssl_ctx); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Server certificate/key are inconsistent."); COMPAT_CLOSE(sock); return 1; } /* Load CRLs if they exist. */ if(listener->crlfile){ store = SSL_CTX_get_cert_store(listener->ssl_ctx); if(!store){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to obtain TLS store."); COMPAT_CLOSE(sock); return 1; } lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); rc = X509_load_crl_file(lookup, listener->crlfile, X509_FILETYPE_PEM); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile); COMPAT_CLOSE(sock); return 1; } X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); } # ifdef REAL_WITH_TLS_PSK }else if(listener->psk_hint){ if(tls_ex_index_context == -1){ tls_ex_index_context = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL); } if(tls_ex_index_listener == -1){ tls_ex_index_listener = SSL_get_ex_new_index(0, "listener", NULL, NULL, NULL); } if(_mosquitto_tls_server_ctx(listener)){ COMPAT_CLOSE(sock); return 1; } SSL_CTX_set_psk_server_callback(listener->ssl_ctx, psk_server_callback); if(listener->psk_hint){ rc = SSL_CTX_use_psk_identity_hint(listener->ssl_ctx, listener->psk_hint); if(rc == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint."); COMPAT_CLOSE(sock); return 1; } } # endif /* REAL_WITH_TLS_PSK */ } #endif /* WITH_TLS */ return 0; }else{ return 1; } } int _mosquitto_socket_get_address(mosq_sock_t sock, char *buf, int len) { struct sockaddr_storage addr; socklen_t addrlen; addrlen = sizeof(addr); if(!getpeername(sock, (struct sockaddr *)&addr, &addrlen)){ if(addr.ss_family == AF_INET){ if(inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr.s_addr, buf, len)){ return 0; } }else if(addr.ss_family == AF_INET6){ if(inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, buf, len)){ return 0; } } } return 1; } mosquitto-1.4.15/Makefile0000664000175000017500000000504113245550210014323 0ustar rogerrogerinclude config.mk DIRS=lib client src DOCDIRS=man DISTDIRS=man .PHONY : all mosquitto docs binary clean reallyclean test install uninstall dist sign copy all : $(MAKE_ALL) docs : set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d}; done binary : mosquitto mosquitto : ifeq ($(UNAME),Darwin) $(error Please compile using CMake on Mac OS X) endif set -e; for d in ${DIRS}; do $(MAKE) -C $${d}; done clean : set -e; for d in ${DIRS}; do $(MAKE) -C $${d} clean; done set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d} clean; done $(MAKE) -C test clean reallyclean : set -e; for d in ${DIRS}; do $(MAKE) -C $${d} reallyclean; done set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d} reallyclean; done $(MAKE) -C test reallyclean -rm -f *.orig test : mosquitto $(MAKE) -C test test install : mosquitto set -e; for d in ${DIRS}; do $(MAKE) -C $${d} install; done ifeq ($(WITH_DOCS),yes) set -e; for d in ${DOCDIRS}; do $(MAKE) -C $${d} install; done endif $(INSTALL) -d ${DESTDIR}/etc/mosquitto $(INSTALL) -m 644 mosquitto.conf ${DESTDIR}/etc/mosquitto/mosquitto.conf.example $(INSTALL) -m 644 aclfile.example ${DESTDIR}/etc/mosquitto/aclfile.example $(INSTALL) -m 644 pwfile.example ${DESTDIR}/etc/mosquitto/pwfile.example $(INSTALL) -m 644 pskfile.example ${DESTDIR}/etc/mosquitto/pskfile.example uninstall : set -e; for d in ${DIRS}; do $(MAKE) -C $${d} uninstall; done rm -f ${DESTDIR}/etc/mosquitto/mosquitto.conf rm -f ${DESTDIR}/etc/mosquitto/aclfile.example rm -f ${DESTDIR}/etc/mosquitto/pwfile.example rm -f ${DESTDIR}/etc/mosquitto/pskfile.example dist : reallyclean set -e; for d in ${DISTDIRS}; do $(MAKE) -C $${d} dist; done mkdir -p dist/mosquitto-${VERSION} cp -r client examples installer lib logo man misc security service src test about.html aclfile.example ChangeLog.txt CMakeLists.txt compiling.txt config.h config.mk CONTRIBUTING.md edl-v10 epl-v10 LICENSE.txt Makefile mosquitto.conf notice.html pskfile.example pwfile.example readme.md readme-windows.txt dist/mosquitto-${VERSION}/ cd dist; tar -zcf mosquitto-${VERSION}.tar.gz mosquitto-${VERSION}/ set -e; for m in man/*.xml; \ do \ hfile=$$(echo $${m} | sed -e 's#man/\(.*\)\.xml#\1#' | sed -e 's/\./-/g'); \ $(XSLTPROC) $(DB_HTML_XSL) $${m} > dist/$${hfile}.html; \ done sign : dist cd dist; gpg --detach-sign -a mosquitto-${VERSION}.tar.gz copy : sign cd dist; scp mosquitto-${VERSION}.tar.gz mosquitto-${VERSION}.tar.gz.asc mosquitto:site/mosquitto.org/files/source/ cd dist; scp *.html mosquitto:site/mosquitto.org/man/ scp ChangeLog.txt mosquitto:site/mosquitto.org/ mosquitto-1.4.15/edl-v100000664000175000017500000000304113245550210013754 0ustar rogerrogerEclipse Distribution License - v 1.0 Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mosquitto-1.4.15/ChangeLog.txt0000664000175000017500000020322413245550210015256 0ustar rogerroger1.4.15 - 20180228 ================= Security: - Fix CVE-2017-7652. If a SIGHUP is sent to the broker when there are no more file descriptors, then opening the configuration file will fail and security settings will be set back to their default values. - Fix CVE-2017-7651. Unauthenticated clients can cause excessive memory use by setting "remaining length" to be a large value. This is now mitigated by limiting the size of remaining length to valid values. A "memory_limit" configuration option has also been added to allow the overall memory used by the broker to be limited. Broker: - Use constant time memcmp for password comparisons. - Fix incorrect PSK key being used if it had leading zeroes. - Fix memory leak if a client provided a username/password for a listener with use_identity_as_username configured. - Fix use_identity_as_username not working on websockets clients. - Don't crash if an auth plugin returns MOSQ_ERR_AUTH for a username check on a websockets client. Closes #490. - Fix 08-ssl-bridge.py test when using async dns lookups. Closes #507. - Lines in the config file are no longer limited to 1024 characters long. Closes #652. - Fix $SYS counters of messages and bytes sent when message is sent over a Websockets. Closes #250. - Fix upgrade_outgoing_qos for retained message. Closes #534. - Fix CONNACK message not being sent for unauthorised connect on websockets. Closes #8. Client library: - Fix incorrect PSK key being used if it had leading zeroes. - Initialise "result" variable as soon as possible in mosquitto_topic_matches_sub. Closes #654. - No need to close socket again if setting non-blocking failed. Closes #649. - Fix mosquitto_topic_matches_sub() not correctly matching foo/bar against foo/+/#. Closes #670. Clients: - Correctly handle empty files with "mosquitto_pub -l". Closes #676. Build: - Don't run TLS-PSK tests if TLS-PSK disabled at compile time. Closes #636. 1.4.14 - 20170710 ================= Broker: - Fix regression from 1.4.13 where persistence data was not being saved. 1.4.13 - 20170627 ================= Security: - Fix CVE-2017-9868. The persistence file was readable by all local users, potentially allowing sensitive information to be leaked. This can also be fixed administratively, by restricting access to the directory in which the persistence file is stored. Broker: - Fix for poor websockets performance. - Fix lazy bridges not timing out for idle_timeout. Closes #417. - Fix problems with large retained messages over websockets. Closes #427. - Set persistence file to only be readable by owner, except on Windows. Closes #468. - Fix CONNECT check for reserved=0, as per MQTT v3.1.1 check MQTT-3.1.2-3. - When the broker stop, wills for any connected clients are now "sent". Closes #477. - Auth plugins can be configured to disable the check for +# in usernames/client ids with the auth_plugin_deny_special_chars option. Partially closes #462. - Restrictions for CVE-2017-7650 have been relaxed - '/' is allowed in usernames/client ids. Remainder of fix for #462. Clients: - Don't use / in auto-generated client ids. 1.4.12 - 20170528 ================= Security: - Fix CVE-2017-7650, which allows clients with username or client id set to '#' or '+' to bypass pattern based ACLs or third party plugins. The fix denies message sending or receiving of messages for clients with a '#' or '+' in their username or client id and if the message is subject to a pattern ACL check or plugin check. Patches for other versions are available at https://mosquitto.org/files/cve/2017-7650/ Broker: - Fix mosquitto.db from becoming corrupted due to client messages being persisted with no stored message. Closes #424. - Fix bridge not restarting properly. Closes #428. - Fix unitialized memory in gets_quiet on Windows. Closes #426. - Fix building with WITH_ADNS=no for systems that don't use glibc. Closes #415. - Fixes to readme.md. - Fix deprecation warning for OpenSSL 1.1. PR #416. - Don't segfault on duplicate bridge names. Closes #446. - Fix CVE-2017-7650. 1.4.11 - 20170220 ================= Broker: - Fix crash when "lazy" type bridge attempts to reconnect. Closes #259. - maximum_connections now applies to websockets listeners. Closes #271. - Allow bridges to use TLS with IPv6. - Don't error on zero length persistence files. Closes #316. - For http only websockets clients, close files served over http in all cases when the client disconnects. Closes #354. - Fix error message when websockets http_dir directory does not exist. - Improve password utility error message. Closes #379. Clients: - Use of --ciphers no longer requires you to also pass --tls-version. Closes #380. Client library: - Clients can now use TLS with IPv6. - Fix potential socket leakage when reconnecting. Closes #304. - Fix potential negative timeout being passed to pselect. Closes #329. 1.4.10 - 20160816 ================= Broker: - Fix TLS operation with websockets listeners and libwebsockts 2.x. Closes #186. - Don't disconnect client on HUP before reading the pending data. Closes #7. - Fix some $SYS messages being incorrectly persisted. Closes #191. - Support OpenSSL 1.1.0. - Call fsync after persisting data to ensure it is correctly written. Closes #189. - Fix persistence saving of subscription QoS on big-endian machines. - Fix will retained flag handling on Windows. Closes #222. - Broker now displays an error if it is unable to open the log file. Closes #234. Client library: - Support OpenSSL 1.1.0. - Fixed the C++ library not allowing SOCKS support to be used. Closes #198. - Fix memory leak when verifying a server certificate with a subjectAltName section. Closes #237. Build: - Don't attempt to install docs when WITH_DOCS=no. Closes #184. 1.4.9 - 20160603 ================ Broker: - Ensure websockets clients that previously connected with clean session set to false have their queued messages delivered immediately on reconnecting. Closes #476314. - Reconnecting client with clean session set to false doesn't start with mid=1 again. - Will topic isn't truncated by one byte when using a mount_point any more. - Network errors are printed correctly on Windows. - Fix incorrect $SYS heap memory reporting when using ACLs. - Bridge config parameters couldn't contain a space, this has been fixed. Closes #150. - Fix saving of persistence messages that start with a '/'. Closes #151. - Fix reconnecting for bridges that use TLS on Windows. Closes #154. - Broker and bridges can now cope with unknown incoming PUBACK, PUBREC, PUBREL, PUBCOMP without disconnecting. Closes #57. - Fix websockets listeners not being able to bind to an IP address. Closes #170. - mosquitto_passwd utility now correctly deals with unknown command line arguments in all cases. Closes #169. - Fix publishing of $SYS/broker/clients/maximum - Fix order of #includes in lib/send_mosq.c to ensure struct mosquitto doesn't differ between source files when websockets is being used. Closes #180. - Fix possible rare crash when writing out persistence file and a client has incomplete messages inflight that it has been denied the right to publish. Client library: - Fix the case where a message received just before the keepalive timer expired would cause the client to miss the keepalive timer. - Return value of pthread_create is now checked. - _mosquitto_destroy should not cancel threads that weren't created by libmosquitto. Closes #166. - Clients can now cope with unknown incoming PUBACK, PUBREC, PUBREL, PUBCOMP without disconnecting. Closes #57. - Fix mosquitto_topic_matches_sub() reporting matches on some invalid subscriptions. Clients: - Handle some unchecked malloc() calls. Closes #1. Build: - Fix string quoting in CMakeLists.txt. Closes #4. - Fix building on Visual Studio 2015. Closes #136. 1.4.8 - 20160214 ================ Broker: - Wills published by clients connected to a listener with mount_point defined now correctly obey the mount point. This was a potential security risk because it allowed clients to publish messages outside of their restricted mount point. This is only affects brokers where the mount_point option is in use. Closes #487178. - Fix detection of broken connections on Windows. Closes #485143. - Close stdin etc. when daemonised. Closes #485589. - Fix incorrect detection of FreeBSD and OpenBSD. Closes #485131. Client library: - mosq->want_write should be cleared immediately before a call to SSL_write, to allow clients using mosquitto_want_write() to get accurate results. 1.4.7 - 20151221 ================ Broker: - Fix support for libwebsockets 1.22. 1.4.6 - 20151220 ================ Broker: - Add support for libwebsockets 1.6. Client library: - Fix _mosquitto_socketpair() on Windows, reducing the chance of delays when publishing. Closes #483979. Clients: - Fix "mosquitto_pub -l" stripping the final character on a line. Closes #483981. 1.4.5 - 20151108 ================ Broker: - Fix possible memory leak if bridge using SSL attempts to connect to a host that is not up. - Free unused topic tree elements (fix in 1.4.3 was incomplete). Closes #468987. Clients: - "mosquitto_pub -l" now no longer limited to 1024 byte lines. Closes #478917. 1.4.4 - 20150916 ================ Broker: - Don't leak sockets when outgoing bridge with multiple addresses cannot connect. Closes #477571. - Fix cross compiling of websockets. Closes #475807. - Fix memory free related crashes on openwrt. Closes #475707. - Fix excessive calls to message retry check. 1.4.3 - 20150818 ================ Broker: - Fix incorrect bridge notification on initial connection. Closes #467096. - Build fixes for OpenBSD. - Fix incorrect behaviour for autosave_interval, most noticable for autosave_interval=1. Closes #465438. - Fix handling of outgoing QoS>0 messages for bridges that could not be sent because the bridge connection was down. - Free unused topic tree elements. Closes #468987. - Fix some potential memory leaks. Closes #470253. - Fix potential crash on libwebsockets error. Client library: - Add missing error strings to mosquitto_strerror. - Handle fragmented TLS packets without a delay. Closes #470660. - Fix incorrect loop timeout being chosen when using threaded interface and keepalive = 0. Closes #471334. - Increment inflight messages count correctly. Closes #474935. Clients: - Report error string on connection failure rather than error code. 1.4.2 - 20150507 ================ Broker: - Fix bridge prefixes only working for the first outgoing message. Closes #464437. - Fix incorrect bridge connection notifications on local broker. - Fix persistent db writing on Windows. Closes #464779. - ACLs are now checked before sending a will message. - Fix possible crash when using bridges on Windows. Closes #465384. - Fix parsing of auth_opt_ arguments with extra spaces/tabs. - Broker will return CONNACK rc=5 when a username/password is not authorised. This was being incorrectly set as rc=4. - Fix handling of payload lengths>4096 with websockets. Client library: - Inflight message count wasn't being decreased for outgoing messages using QoS 2, meaning that only up to 20 QoS 2 messages could be sent. This has been fixed. Closes #464436. - Fix CMake dependencies for C++ wrapper building. Closes #463884. - Fix possibility of select() being called with a socket that is >FD_SETSIZE. This is a fix for #464632 that will be followed up by removing the select() call in a future version. - Fix calls to mosquitto_connect*_async() not completing. 1.4.1 - 20150403 ================ Broker: - Fix possible crash under heavy network load. Closes #463241. - Fix possible crash when using pattern ACLs. - Fix problems parsing config strings with multiple leading spaces. Closes #462154. - Websockets clients are now periodically disconnected if they have not maintained their keepalive timer. Closes #461619. - Fix possible minor memory leak on acl parsing. Client library: - Inflight limits should only apply to outgoing messages. Closes #461620. - Fix reconnect bug on Windows. Closes #463000. - Return -1 on error from mosquitto_socket(). Closes #461705. - Fix crash on multiple calls to mosquitto_lib_init/mosquitto_lib_cleanup. Closes #462780. - Allow longer paths on Windows. Closes #462781. - Make _mosquitto_mid_generate() thread safe. Closes #463479. 1.4 - 20150218 ============== Important changes: - Websockets support in the broker. - Bridge behaviour on the local broker has changed due to the introduction of the local_* options. This may affect you if you are using authentication and/or ACLs with bridges. - The default TLS behaviour has changed to accept all of TLS v1.2, v1.1 and v1.0, rather than only only one version of the protocol. It is still possible to restrict a listener to a single version of TLS. - The Python client has been removed now that the Eclipse Paho Python client has had a release. - When a durable client reconnects, its queued messages are now checked against ACLs in case of a change in username/ACL state since it last connected. - New use_username_as_clientid option on the broker, for preventing hijacking of a client id. - The client library and clients now have experimental SOCKS5 support. - Wildcard TLS certificates are now supported for bridges and clients. - The clients have support for config files with default options. - Client and client libraries have support for MQTT v3.1.1. - Bridge support for MQTT v3.1.1. Broker: - Websockets support in the broker. - Add local_clientid, local_username, local_password for bridge connections to authenticate to the local broker. - Default TLS mode now accepts TLS v1.2, v1.1 and v1.0. - Support for ECDHE-ECDSA family ciphers. - Fix bug #1324411, which could have had unexpected consequences for delayed messages in rare circumstances. - Add support for "session present" in CONNACK messages for MQTT v3.1.1. - Remove strict protocol #ifdefs. - Change $SYS/broker/clients/active -> $SYS/broker/clients/connected - Change $SYS/broker/clients/inactive -> $SYS/broker/clients/disconnected - When a durable client reconnects, its queued messages are now checked against ACLs in case of a change in username/ACL state since it last connected. - libuuid is used to generate client ids, where it is available, when an MQTT v3.1.1 client connects with a zero length client id. - Anonymous clients are no longer accidently disconnected from the broker after a SIGHUP. - mosquitto_passwd now supports -b (batch mode) to allow the password to be provided at the command line. - Removed $SYS/broker/changeset. This was intended for use with debugging, but in practice is of no use. - Add support for use_username_as_clientid which can be used with authentication to restrict ownership of client ids and hence prevent one client disconnecting another by using the same client id. - When "require_certificate" was false, the broker was incorrectly asking for a certificate (but not checking it). This caused problems with some clients and has been fixed so the broker no longer asks. - When using syslog logging on non-Windows OSs, it is now possible to specify the logging facility to one of local0-7 instead of the default "daemon". - The bridge_attempt_unsubscribe option has been added, to allow the sending of UNSUBSCRIBE requests to be disabled for topics with "out" direction. Closes bug #456899. - Wildcard TLS certificates are now supported for bridges. - Support for "hour" client expiration lengths for the persistent_client_expiration option. Closes bug #425835. - Bridge support for MQTT v3.1.1. - Root privileges are now dropped after starting listeners and loading certificates/private keys, to allow private keys to have their permissions restricted to the root user only. Closes bug #452914. - Usernames and topics given in ACL files can now include a space. Closes bug #431780. - Fix hang if pattern acl contains a %u but an anonymous client connect. Closes bug #455402. - Fix man page installation with cmake. Closes bug #458843. - When using "log_dest file" the output file is now flushed periodically. Clients: - Both clients can now load default configuration options from a file. - Add -C option to mosquitto_sub to allow the client to quit after receiving a certain count of messages. Closes bug #453850. - Add --proxy SOCKS5 support for both clients. - Pub client supports setting its keepalive. Closes bug #454852. - Add support for config files with default options. - Add support for MQTT v3.1.1. Client library: - Add experimental SOCKS5 support. - mosquitto_loop_forever now quits after a fatal error, rather than blindly retrying. - SRV support is now not compiled in by default. - Wildcard TLS certificates are now supported. - mosquittopp now has a virtual destructor. Closes bug #452915. - Add support for MQTT v3.1.1. - Don't quit mosquitto_loop_forever() if broker not available on first connect. Closes bug #453293, but requires more work. 1.3.5 - 20141008 ================ Broker: - Fix possible memory leak when using a topic that has a leading slash. Fixes bug #1360985. - Fix saving persistent database on Windows. - Temporarily disable ACL checks on subscriptions when using MQTT v3.1.1. This is due to the complexity of checking wildcard ACLs against wildcard subscriptions. This does not have a negative impact on security because checks are still made before a message is sent to a client. Fixes bug #1374291. - When using -v and the broker receives a SIGHUP, verbose logging was being disabled. This has been fixed. Client library: - Fix mutex being incorrectly passed by value. Fixes bug #1373785. 1.3.4 - 20140806 ================ Broker: - Don't ask client for certificate when require_certificate is false. - Backout incomplete functionality that was incorrectly included in 1.3.2. 1.3.3 - 20140801 ================ Broker: - Fix incorrect handling of anonymous bridges on the local broker. 1.3.2 - 20140713 ================ Broker: - Don't allow access to clients when authenticating if a security plugin returns an application error. Fixes bug #1340782. - Ensure that bridges verify certificates by default when using TLS. - Fix possible crash when using pattern ACLs that do not include a %u and clients that connect without a username. - Fix subscriptions being deleted when clients subscribed to a topic beginning with a $ but that is not $SYS. - When a durable client reconnects, its queued messages are now checked against ACLs in case of a change in username/ACL state since it last connected. - Fix bug #1324411, which could have had unexpected consequences for delayed messages in rare circumstances. - Anonymous clients are no longer accidently disconnected from the broker after a SIGHUP. Client library: - Fix topic matching edge case. - Fix callback deadlocks after calling mosquitto_disconnect(), when using the threaded interfaces. Closes bug #1313725. - Fix SRV support when building with CMake. - Remove strict protocol #ifdefs. General: - Use $(STRIP) for stripping binaries when installing, to allow easier cross compilation. 1.3.1 - 20140324 ================ Broker: - Prevent possible crash on client reconnect. Closes bug #1294108. - Don't accept zero length unsubscription strings (MQTT v3.1.1 fix) - Don't accept QoS 3 (MQTT v3.1.1 fix) - Don't disconnect clients immediately on HUP to give chance for all data to be read. - Reject invalid un/subscriptions e.g. foo/+bar #/bar. - Take more care not to disconnect clients that are sending large messages. Client library: - Fix socketpair code on the Mac. - Fix compilation for WITH_THREADING=no. - Break out of select() when calling mosquitto_loop_stop(). - Reject invalid un/subscriptions e.g. foo/+bar #/bar. - Add mosquitto_threaded_set(). Clients: - Fix keepalive value on mosquitto_pub. - Fix possibility of mosquitto_pub not exiting after sending messages when using -l. 1.3 - 20140316 ============== Broker: - The broker no longer ignores the auth_plugin_init() return value. - Accept SSLv2/SSLv3 HELLOs when using TLSv1, whilst keeping SSLv2 and SSLv3 disabled. This increases client compatibility without sacrificing security. - The $SYS tree can now be disabled at runtime as well as at compile time. - When remapping bridged topics, only check for matches when the message direction is correct. This allows two identical topics to be remapped differently for both in and out. - Change "$SYS/broker/heap/current size" to "$SYS/broker/heap/current" for easier parsing. - Change "$SYS/broker/heap/maximum size" to "$SYS/broker/heap/maximum" for easier parsing. - Topics are no longer normalised from e.g a///topic to a/topic. This matches the behaviour as clarified by the Oasis MQTT spec. This will lead to unexpected behaviour if you were using topics of this form. - Log when outgoing messages for a client begin to drop off the end of the queue. - Bridge clients are recognised as bridges even after reloading from persistence. - Basic support for MQTT v3.1.1. This does not include being able to bridge to an MQTT v3.1.1 broker. - Username is displayed in log if present when a client connects. - Support for 0 length client ids (v3.1.1 only) that result in automatically generated client ids on the broker (see option allow_zero_length_clientid). - Ability to set the prefix of automatically generated client ids (see option auto_id_prefix). - Add support for TLS session resumption. - When using TLS, the server now chooses the cipher to use when negotiating with the client. - Weak TLS ciphers are now disabled by default. Client library: - Fix support for Python 2.6, 3.0, 3.1. - Add support for un/subscribing to multiple topics at once in un/subscribe(). - Clients now close their socket after sending DISCONNECT. - Python client now contains its version number. - C library mosquitto_want_write() now supports TLS clients. - Fix possible memory leak in C/C++ library when communicating with a broker that doesn't follow the spec. - Return strerror() through mosquitto_strerror() to make error printing easier. - Topics are no longer normalised from e.g a///topic to a/topic. This matches the behaviour as clarified by the Oasis MQTT spec. This will lead to unexpected behaviour if you were using topics of this form. - Add support for SRV lookups. - Break out of select() on publish(), subscribe() etc. when using the threaded interface. Fixes bug #1270062. - Handle incoming and outgoing messages separately. Fixes bug #1263172. - Don't terminate threads on mosquitto_destroy() when a client is not using the threaded interface but does use their own thread. Fixes bug #1291473. Clients: - Add --ciphers to allow specifying which TLS ciphers to support. - Add support for SRV lookups. - Add -N to sub client to suppress printing of EOL after the payload. - Add -T to sub client to suppress printing of a topic hierarchy. 1.2.3 - 20131202 ================ Broker: - Don't always attempt to call read() for SSL clients, irrespective of whether they were ready to read or not. Reduces syscalls significantly. - Possible memory leak fixes. - Further fix for bug #1226040: multiple retained messages being delivered for subscriptions ending in #. - Fix bridge reconnections when using multiple bridge addresses. Client library: - Fix possible memory leak in C/C++ library when communicating with a broker that doesn't follow the spec. - Block in Python loop_stop() until all messages are sent, as the documentation states should happen. - Fix for asynchronous connections on Windows. Closes bug #1249202. - Module version is now available in mosquitto.py. Clients: - mosquitto_sub now uses fwrite() instead of printf() to output messages, so messages with NULL characters aren't truncated. 1.2.2 - 20131021 ================ Broker: - Fix compliance with max_inflight_messages when a non-clean session client reconnects. Closes one of the issues on bug #1237389. Client library: - Fix incorrect inflight message accounting, which caused messages to go unsent. Partial fix for bug #1237351. - Fix potential memory corruption when sending QoS>0 messages at a high rate using the threaded interface. Further fix for #1237351. - Fix incorrect delay scaling when exponential_backoff=true in mosquitto_reconnect_delay_set(). - Some pep8 fixes for Python. 1.2.1 - 20130918 ================ Broker: - The broker no longer ignores the auth_plugin_init() return value. Closes bug #1215084. - Use RTLD_GLOBAL when opening authentication plugins on posix systems. Fixes resolving of symbols in libraries used by authentication plugins. - Add/fix some config documentation. - Fix ACLs for topics with $SYS. - Clients loaded from the persistence file on startup were not being added to the client hash, causing subtle problems when the client reconnected, including ACLs failing. This has been fixed. - Add note to mosquitto-tls man page stating that certificates need to be unique. Closes bug #1221285. - Fix incorrect retained message delivery when using wildcard subs in some circumstances. Fixes bug #1226040. Client library: - Fix support for Python 2.6, 3.0, 3.1. - Fix TLS subjectAltName verification and segfaults. - Handle EAGAIN in Python on Windows. Closes bug #1220004. - Fix compilation when using WITH_TLS=no. - Don't fail reconnecting in Python when broker is temporarily unavailable. 1.2 - 20130708 ============== Broker: - Replace O(n) username lookup on CONNECT with a roughly O(1) hashtable version. - It is now possible to disable $SYS at compile time. - Add dropped publish messages to load tree in $SYS. Closes bug #1183318. - Add support for logging SUBSCRIBE/UNSUBSCRIBE events. - Add "log_dest file" logging support. - Auth plugin ACL check function now passes the client id as well as username and password. - The queue_qos0_messages option wasn't working correctly, this has now been fixed. Closes bug #1125200. - Don't drop all messages for disconnected durable clients when max_queued_messages=0. - Add support for "log_type all". - Add support for "-v" option on the command line to provide the equivalent of "log_type all" without needing a config file. - Add the "upgrade_outgoing_qos" option, a non-standard feature. - Persistence data is now written to a temporary file which is atomically renamed on completion, so a crash during writing will not produce a corrupt file. - mosquitto.conf is now installed as mosquitto.conf.example - Configuration file errors are now reported with filename and line number. - The broker now uses a monotonic clock if available, to avoid changes in time causing client disconnections or message retries. - Clean session and keepalive status are now display the log when a client connects. - Add support for TLSv1.2 and TLSv1.1. - Clients that connect with zero length will topics are now rejected. - Add the ability to set a maximum allowed PUBLISH payload size. - Fix an ACL with topic "#" incorrectly granting access to $SYS. - Fix retained messages incorrectly being set on wildcard topics, leading to duplicate retained messages being sent on subscription. Closes bug #1116233. - Don't discard listener values when no "port" option given. Closes bug #1131406. - Client password check was always failing when security was being reapplied after a config reload. This meant that all clients were being disconnected. This has been fixed. - Fix build when WITH_TLS=no. Closes bug #1174971. - Fix single outgoing packets not being sent in a timely fashion if they were not sent in one call to write(). Closes bug #1176796. - Fix remapping of messages for clients connected to a listener with mount_point set. Closes bug #1180765. - Fix duplicate retained messages being sent for some wildcard patterns. - If a client connects with a will topic to which they do not have write access, they are now disconnected with CONNACK "not authorised". - Fix retained messages on topic foo being incorrectly delivered to subscriptions of /# - Fix handling of SSL errors on SSL_accept(). - Fix handling of QoS 2 messages on client reconnect. - Drop privileges now sets supplementary groups correctly. - Fix load reporting interval (is now 60s). - Be strict with malformed PUBLISH packets - clients are now disconnected rather than the packet discarded. This goes inline with future OASIS spec changes and makes other changes more straightforward. - Process incoming messages denied by ACL properly so that clients don't keep resending them. - Add support for round_robin bridge option. - Add bridge support for verifying remote server certificate subject against the remote hostname. - Fix problem with out of order calls to free() when restarting a lazy bridge. - The broker now attempts to resolve bind_address and bridge addresses immediately when parsing the config file in order to detect invalid hosts. - Bridges now set their notification state before attempting to connect, so if they fail to connect the state can still be seen. - Fix bridge notification payload length - no need to send a null byte. - mosquitto_passwd utility now reports errors more clearly. - Fix "mosquitto_passwd -U". Client library: - Add support for TLSv1.2 and TLSv1.1, except for on the Python module. - Add support for verifying remote server certificate subject against the remote hostname. - Add mosquitto_reconnect_async() support and make asynchronous connections truely asynchronous rather than simply deferred. DNS lookups are still blocking, so asynchronous connections require an IP address instead of hostname. - Allow control of reconnection timeouts in mosquitto_loop_forever() and after mosquitto_loop_start() by using mosquitto_reconnect_delay_set(). - Fix building on Android NDK. - Re-raise unhandled errors in Python so as not to provide confusing error messages later on. - Python module supports IPv6 connections. - mosquitto_sub_topic_tokenise() was behaving incorrectly if the last topic hierarchy had only a single character. This has been fixed. Closes bug #1163348. - Fix possible crash after disconnects when using the threaded interface with TLS. - Allow build/install without Python. Closes bug #1174972. - Add support for binding connection to a local interface. - Implement maximum inflight messages handling. - Fix Python client not handling will_payload==None. - Fix potential memory leak when setting username/password. - Fix handling of QoS 2 messages on reconnect. - Improve handling of mosquitto_disconnect() with threaded mode. Clients: - Add support for TLSv1.2 and TLSv1.1. - Sub client can now suppress printing of messages with the retain bit set. - Add support for binding connection to a local interface. - Implement maximum inflight messages handling for the pub client. 1.1.3 - 20130211 ================ Broker: - mosquitto_passwd utility now uses tmpfile() to generate its temporary data storage file. It also creates a backup file that can be used to recover data if an errors occur. Other: - Build script fixes to help packaging on Debian. 1.1.2 - 20130130 ================ Client library: - Fix tls_cert_reqs not being set to SSL_VERIFY_PEER by default. This meant that clients were not verifying the server certificate when connecting over TLS. This affects the C, C++ and Python libraries. 1.1.1 - 20130116 ================ Broker: - Fix crash on reload if using acl patterns. Client library: - Fix static C++ functions not being exported on Windows. Fixes bug #1098256. 1.1 - 20121219 ============== Broker: - Add $SYS/broker/messages/dropped - Add $SYS/broker/clients/expired - Replace $SYS/broker/+/per second/+ with moving average versions published at $SYS/broker/load/# - Add $SYS/broker/load/sockets/+ and $SYS/broker/load/connections/+ - Documentation on password file format has been fixed. - Disable SSL compression. This reduces memory usage significantly and removes the possibility of CRIME type attacks. - Enable SSL_MODE_RELEASE_BUFFERS mode to reduce SSL memory usage further. - Add allow_duplicate_messages option. - ACL files can now have comment lines with # as the first character. - Display message on startup about which config is being loaded. - Fix max_inflight_messages and max_queued_messages not being applied. - Fix documentation error in mosquitto.conf. - Ensure that QoS 2 queued messages are sent out in a timely manner. - Local bridges now act on clean_session correctly. - Local bridges with clean_session==false now remove unused subscriptions on broker restart. - The $SYS/broker/heap/# messages now no longer include "bytes" as part of the string for ease of use. Client library: - Free memory used by OpenSSL in mosquitto_lib_cleanup() where possible. - Change WebSocket subprotocol name to mqttv3.1 to make future changes easier and for compatibility with other implementations. - mosquitto_loop_read() and mosquitto_loop_write() now handle errors themselves rather than having mosquitto_loop() handle their errors. This makes using them in a separate event loop more straightforward. - Add mosquitto_loop_forever() / loop_forever() function call to make simple clients easier. - Disable SSL compression. This reduces memory usage significantly and removes the possibility of CRIME type attacks. - Enable SSL_MODE_RELEASE_BUFFERS mode to reduce SSL memory usage further. - mosquitto_tls_set() will now return an error or raise an exception immediately if the CA certificate or client certificate/key cannot be accessed. - Fix potential memory leaks on connection failures. - Don't produce return error from mosquitto_loop() if a system call is interrupted. This prevents disconnects/reconnects in threaded mode and simplifies non-threaded client handling. - Ignore SIGPIPE to prevent unnecessary client quits in threaded mode. - Fix document error for mosquitto_message_retry_set(). - Fix mosquitto_topic_matches_sub() for subscriptions with + as the final character. Fixes bug #1085797. - Rename all "obj" parameters to "userdata" for consistency with other libraries. - Reset errno before network read/write to ensure EAGAIN isn't mistakenly returned. - The message queue length is now tracked and used to determine the maximum number of packets to process at once. This removes the need for the max_packets parameter which is now unused. - Fix incorrect error value in Python error_string() function. Fixes bug #1086777. - Reset last message in/out timer in Python module when we send a PINGREQ. Fixes too-early disconnects. Clients: - Clients now display their own version number and library version number in their help messages. - Fix "mosquitto_pub -l -q 2" disconnecting before all messages were transmitted. - Fix potential out-of-bounds array access with client ids. Fixes bug #1083182. Other: - mosquitto_passwd can now convert password files with plain text files to hashed versions. 1.0.5 - 20121103 ================ Broker: - Fix crash when the broker has use_identity_as_username set to true but a client connects without a certificate. - mosquitto_passwd should only be installed if WITH_TLS=yes. Library: - Use symbolic errno values rather than numbers in Python module to avoid cross platform issues (incorrect errno on Mac OS). Other: - Build script fixes for FreeBSD. 1.0.4 - 20121017 ================ Broker: - Deal with poll() POLLIN/POLLOUT before POLL[RD]HUP to correctly handle the case where a client sends data and immediately closes its socket. Library: - Fix memory leak with messages of QoS=2. Fixes bug #1064981. - Fix potential thread synchronisation problem with outgoing packets in the Python module. Fixes bug #1064977. Clients: - Fix "mosquitto_sub -l" incorrectly only sending one message per second. 1.0.3 - 20120927 ================ Broker: - Fix loading of psk files. - Don't return an error when reloading config if an ACL file isn't defined. This was preventing psk files being reloaded. - Clarify meaning of $SYS/broker/clients/total in mosquitto(8) man page. - Clarify meaning of $SYS/broker/messages/stored in mosquitto(8) man page. - Fix non-retained message delivery when subscribing to #. - Fix retained message delivery for subs to foo/# with retained messages at foo. - Include the filename in password/acl file loading errors. Library: - Fix possible AttributeError when self._sock == None in Python module. - Fix reconnecting after a timeout in Python module. - Fix reconnecting when there were outgoing packets in the queue in the Python module. - Fix problem with mutex initialisation causing crashes on some Windows installations. 1.0.2 - 20120919 ================ Broker: - If the broker was configured for persistence, a durable client had a subscription to topics in $SYS/# and had messages in its queue when the broker restarted, then the persistent database would have messages missing and so the broker would not restart properly. This has been fixed. Library: - Fix threading problem on some systems. Tests: - Close socket after 08-ssl-connect-no-auth-wrong-ca.py test to prevent subsequent tests having problems. Build scripts: - Install pskfile.example in CMake. Fixes bug #1037504. Other: - Fix db_dump parameter printing message store and sub chunks. 1.0.1 - 20120815 ================ Broker: - Fix default log_dest when running as a Windows service. Client library: - Fix incorrect parameters in Python on_log() callback call. Fixes bug #1036818. Clients: - Clients now don't display TLS/TLS-PSK usage help if they don't support it. Build scripts: - Fix TLS-PSK support in the CMake build files. - Fix man page installation in the CMake build files. - Fix SYSCONFDIR in cmake on *nix when installing to /usr. Fixes bug #1036908. Documentation: - Fix mqtt/MQTT capitalisation in man pages. - Update compiling.txt. - Fix incorrect callback docs in mosquitto.py. Fixes bug #1036607. - Fix various doc typos and remove obsolete script. Fixes bug #1037088. 1.0 - 20120814 ============== Broker: - Add SSL/TLS support. - Add TLS-PSK support, providing a simpler encryption method for constrained devices. - Passwords are now salted+hashed if compiled with WITH_TLS (recommended). - Add mosquitto_passwd for handling password files. - Add $SYS/broker/publish/messages/{sent|received} to show the number of PUBLISH messages sent/received. - Add $SYS/broker/publish/bytes/{sent|received} to show the number of PUBLISH bytes sent/received. - Add reload parameter for security init/cleanup functions. - Add option for expiring disconnected persistent clients. - Add option for queueing of QoS 0 messages when persistent clients are disconnected. - Enforce client id limits in the broker (only when WITH_STRICT_PROTOCOL is defined). - Fix reloading of log configuration. - Add support for try_private config option for bridge connections. - Add support for autosave_on_changes config option. - Add support for include_dir config option. - Add support for topic remapping. - Usernames were being lost when a non clean-session client reconnected, potentially causing problems with ACLs. This has been fixed. - Significant improvement to memory handling on Windows. - Bridges with outgoing topics will now set the retain flag correctly so that messages will be retained on the remote broker. - Incoming bridge connections are now detected by checking if bit 8 of the protocol version number is set. This requires support from the remote broker. - Add support for notification_topic option. - Add $SYS/broker/subscriptions/count and $SYS/broker/retained messages/count. - Add restart_timeout to control the amount of time an automatic bridge will wait before reconnecting. - Overlapping subscriptions are now handled properly. Fixes bug #928538. - Fix reloading of persistence_file and persistence_location. - Fix broker crash on incorrect protocol number. - Fix missing COMPAT_ECONNRESET define on Windows. - Clients that had disconnected were not always being detected immediately on Linux. This has been fixed. - Don't save $SYS messages to the on-disk persistent db. All $SYS messages should be reconstructed on a restart. This means bridge connection notifications will now be correct on a restart. - Fix reloading of bridge clients from the persistent db. This means that outgoing bridged topics should always work. - Local bridges are now no longer restricted by local ACLs. - Discard publish messages with zero length topics. - Drop to "mosquitto" user even if no config file specified. - Don't incorrectly allow topic access if ACL patterns but no normal ACL rules are defined. Client library: - Add SSL/TLS support. - Add TLS-PSK support, providing a simpler encryption method for constrained devices. - Add javascript/websockets client library. - Add "struct mosquitto *mosq" parameter for all callbacks in the client library. This is a binary incompatible change so the soversion of the libraries has been incremented. The new parameter should make it easier to use callbacks in practice. - Add mosquitto_want_write() for use when using own select() loop with mosquitto_socket(). - Add mosquitto_connect_async() to provide a non-blocking connect client call. - Add mosquitto_user_data_set() to allow user data pointer to be updated. - Add "int rc" parameter to disconnect callback to indicate whether disconnect was unexpected or the result of calling mosquitto_disconnect(). - Add mosquitto_strerror() for obtaining a string description of error numbers. - Add mosquitto_connack_string() for obtaining a string description of MQTT connection results. - Add mosquitto_will_clear() and change mosquitto_will_set() to only set the will. - Add mosquitto_sub_topic_tokenise() and mosquitto_sub_topic_tokens_free() utility functions to tokenise a subscription/topic string into a string array. - Add mosquitto_topic_matches_sub() to check whether a topic matches a subscription. - Replaced mosquitto_log_init() with mosquitto_log_callback_set() to allow clients to decide what to do with log messages. - Client will now disconnect itself from the broker if it doesn't receive a PINGRESP in the keepalive period after sending a PINGREQ. - Client will now send a PINGREQ if it has not received a message from the broker in keepalive seconds. - mosquitto_new() will now generate a random client id if the id parameter is NULL. - Added max_packets to mosquitto_loop(), mosquitto_loop_read() and mosquitto_loop_write() to control the maximum number of packets that are handled per call. - Payload parameters are now void * instead of uint8_t *. - The clean_session parameter has been moved from mosquitto_connect() to mosquitto_new() because it is a client parameter rather than a connection parameter. - Functions now use int instead of uint*_t where possible. - mosquitto_new() now sets errno to indicate failure type. - Return MOSQ_ERR_INVAL on zero length topic. - Fix automatic client id generation on Windows. - mosquitto_loop_misq() can now return MOSQ_ERR_NO_CONN. - Compile static library as well as dynamic library with default makefiles. - Rename C++ namespace from mosquittopp to mosqpp to remove ambiguity. - C++ lib_init(), lib_version() and lib_cleanup() are now in the mosqpp namespace directly, not mosquittopp class members. - The Python library is now written in pure Python and so no longer depends on libmosquitto. - The Python library includes SSL/TLS support. - The Python library should now be compatible with Python 3. Other: - Fix db_dump reading of retained messages. - Add example of logging all messages to mysql. - Add C++ client example. - Fix potential buffer overflow in pub/sub clients. - Add "make binary" target that doesn't make documents. - Add "--help" arguments to pub/sub clients. - Fix building on Solaris. 0.15 - 20120205 =============== - Add support for $SYS/broker/clients/maximum and $SYS/broker/clients/active topics. - Add support for $SYS messages/byte per second received/sent topics. - Updated mosquitto man page - $SYS hierarchy and signal support were out of date. - Auto generated pub/sub client ids now include the hostname. - Tool for dumping persistent DB contents is available in src/db_dump. It isn't installed by default. - Enforce topic length checks in client library. - Implement "once" and "lazy" bridge start types. - Add new return type MOSQ_ERR_ERRNO to indicate that the errno variable should be checked for the real error code. - Add support for connection_messages config option. - mosquitto_sub will now refuse to run if the -c option (disable clean session) is given and no client id is provided. - mosquitto_pub now gives more useful error messages on invalid input or other error conditions. - Fix Python will_set() true/True typo. - Fix messages to topic "a/b" incorrectly matching on a subscription "a" if another subscription "a/#" exists. 0.14.4 - 20120106 ================= - Fix local bridge notification messages. - Fix return values for more internal library calls. - Fix incorrect out of memory checks in library and broker. - Never time out local bridge connections. 0.14.3 - 20111210 ================= - Fix potential crash when client connects with an invalid CONNECT packet. - Fix incorrect invalid socket comparison on Windows. - Server shouldn't crash when a message is published to foo/ when a subscription to foo/# exists (bug #901697). - SO_REUSEADDR doesn't work the same on Windows, so don't use it. - Cygwin builds now support Windows service features. - Fix $SYS/broker/bytes/sent reporting. 0.14.2 - 20111123 ================= - Add uninstall target for libs. - Don't try to write packet whilst in a callback. 0.14.1 - 20111117 ================= - Fix Python sytax errors (bug #891673). 0.14 - 20111116 =============== - Add support for matching ACLs based on client id and username. - Add a Windows installer file (NSIS based). - Add native support for running the broker as a Windows service. This is the default when installed using the new installer. - Fix client count for listeners. When clients disconnect, decrement the count. Allow max_connections to work again. - Attempt to send all packets immediately upon being queued. This will result in more immediate network communication in many cases. - Log IP address when reporting CONNACK packets if the client id isn't yet known. - Fix payload length calculation in python will_set function. - Fix Python publish and will_set functions for payload=None. - Fix keepalive value being lost when reconnecting a client (bug #880863). - Persistence file writing now uses portable file functions, so the Cygwin broker build should no longer be necessary. - Duplicate code between the client and broker side has been reduced. - Queued messages for clients reconnecting with clean_session=false set were not being sent until the next message for that client was received. This has been fixed (bug #890724). - Fix subscriptions to # incorrectly matching against topics beginning with / 0.13 - 20110920 =============== - Implement bridge state notification messages. - Save client last used mid in persistent database (DB version number bumped). - Expose message id in Python MosquittoMessage. - It is now possible to set the topic QoS level for bridges. - Python MosquittoMessage payload parameter is now a Python string, not a ctypes object which makes it much easier to use. - Fix queueing of messages for disconnected clients. The max_queued_messages option is now obeyed. - C++ library is now in its own namespace, mosquittopp. - Add support for adding log message timestamps in the broker. - Fix missing mosquitto_username_pw_set() python binding. - Fix keepalive timeout for reconnecting non clean-session clients. Prevents immediate disconnection on reconnection. - Fix subscription wildcard matching - a subscription of +/+ will now match against /foo - Fix subscription wildcard matching - a subscription of foo/# will now match against foo - When restoring persistent database, clients should be set to non clean-session or their subscriptions will be immediately removed. - Fix SUBACK payload for multiple topic subscriptions. - Don't send retained messages when a client subscribes to a topic it is already subscribed to. 0.12 - 20110725 =============== - Reload (most) configuration on SIGHUP. - Memory tracking is no longer compiled in the client library. - Add --help option to mosquitto to display usage. - Add --id-prefix option to clients to allow easier use with brokers that are using the clientid_prefix option. - Fix compilation on QNX. - Add -P as a synonym argument for --pw in the clients. - Fix python MosquittoMessage payload parameter. This is now returned as a pointer to an array of c_uint8 values so binary data is handled correctly. If a string is needed, use msg.payload_str - Fix memory leaks on client authentication. - If password_file is not defined then clients can now connect even if they use a username/password. - Add mosquitto_reconnect() to the client library. - Add option for compiling with liberal protocol compliance support (enabled by default). - Fix problems with clients reconnecting and old messages remaining in the message store. - Display both ip and client id in the log message when a client connects. Change the socket connection message to make it more obvious that it is just a socket connection being made (bug #801135). - Fix retained message delivery where a subscription contains a +. - Be more lenient when reloading persistent database to reduce errors with empty retained messages. 0.11.3 - 20110707 ================= - Don't complain and quit if persistence_file option is given (bug #802423). - Initialise listeners correctly when clients with duplicate client ids connect. Bug #801678. - Memory tracking is now disabled for Symbian builds due to lack of malloc.h. - Fix memory tracking compilation for kFreeBSD. - Python callbacks can now be used with class member functions. - Fix persistent database writing of client message chunks which caused errors when restoring (bug #798164). 0.11.2 - 20110626 ================= - Don't free contexts in mqtt3_context_disconnect() (bug #799688 / #801678). - Only free will if present when freeing a client context. 0.11.1 - 20110620 ================= - Fix buffer overrun when checking for + and # in topics (bug #799688). - Pub client now quits if publish fails. 0.11 - 20110619 =============== - Removed all old sqlite code. - Remove client id limit in clients. - Implemented $SYS/broker/heap/maximum size - Implemented $SYS/broker/clients/inactive to show the number of disconnected non-clean session clients. - $SYS/broker/heap/current size and maximum size messages now include "bytes" to match rsmb message format. - Implemented the retained_persistence config file option - a synonym of the "persistence" option. - Added security_external.c to broker source to make it easier for third parties to add support for their existing username/password and ACL database for security checks. See external_security_checks.txt. - $SYS messages are now only republished when their value changes. - Windows native broker now responds to command line arguments. - Simplify client disconnecting so wills gets sent in all cases (bug #792468). - Clients now have a --quiet option. - The on_disconnect() callback will always be called now, even if the client has disconnected unexpectedly. - Always close persistent DB file after restoring. - Return error code when exiting the clients. - mosquitto_publish() now returns MOSQ_ERR_INVAL if the topic contains + or # - mosquitto now silently rejects published messages with + or # in the topic. - max_connections is now a per-listener setting instead of global. - Connection count is now reduced when clients disconnect (bug #797983). 0.10.2 - 20110106 ================= - Don't abort when connecting if the first connection fails. This is important on e.g. Windows 7, where IPV6 is offered as the first choice but may not be available. - Deal with long logging messages properly (bug #785882). - Fix library compilation on Symbian - no pselect() available. - Don't stop processing subscriptions on received messages after a subscription with # matches. (bug #791206). 0.10.1 - 20110512 ================= - Fix Windows compilation. - Fix mosquitto.py on Windows - call lib init/cleanup. - Don't abort when connecting if given an unknown address type (assuming an IPv4 or IPv6 address is given). 0.10 - 20110429 =============== - Implement support for the password_file option and accompanying authentication requirements in the broker. - Implement topic Access Control Lists. - mosquitto_will_set() and mosquitto_publish() now return MOSQ_ERR_PAYLOAD_SIZE if the payload is too large (>268,435,455 bytes). - Bridge support can now be disabled at compile time. - Group together network writes for outgoing packets - don't send single byte writes! - Add support for clientid_prefixes variable. - Add support for the clientid config variable for controlling bridge client ids. - Remove 32-bit database ID support because htobe64() no longer used. - Multiple client subscriptions to the same topic result in only a single subscription. Bug #744077. 0.9.3 - 20110310 ================ - Set retained message status for QoS 2 messages (bug #726535). - Only abort with an error when opening listening sockets if no address family is available, rather than aborting when any address family is not available. - Don't clean queued messages when a non clean session client reconnects. - Make mosquitto.py compatible with Python <2.6. - Fix mosquitto.h header includes for Windows. 0.9.2 - 20110208 ================ - Only send a single DISCONNECT command when using -l in the pub client. - Set QoS=1 on PUBREL commands to meet protocol spec. - Don't leak sockets on connection failure in the library. - Install man pages when building under cmake. - Fix crash bug on malformed CONNECT message. - Clients are now rejected if their socket peer name cannot be obtained on connection. - Fix a number of potential problems caused when a client with a duplicate id connects. - Install mosquitto.conf under cmake. 0.9.1 - 20101203 ================ - Add missing code for parsing the "bind_address" configuration option. - Fix missing include when compiling with tcp-wrappers support. - Add linker version script for C library to control exported functions. 0.9 - 20101114 ============== - Client and message data is now stored in memory with custom routines rather than a sqlite database. This removes the dependencies on sqlite, pcre and sqlite3-pcre. It also means that the persistent database format has had to be reimplemented in a custom format. Optional support for importing old sqlite databases is provided. - Added IPv6 support for mosquitto and the clients. - Provide username and password support for the clients and client libraries. This is part of the new MQTT v3.1 spec. - The broker supports the username and password connection flags, but will not do anything with the username and password. - Python callback functions now optionally take an extra argument which will return the user object passed to the Mosquitto() constructor, or the calling python object itself if nothing was given to Mosquitto(). - Remove the mosquitto command line option "-i interface". - Remove the mosquitto.conf "interface" variable. - Add support for the listener config variable (replaces the interface variable) - Add support for the bind_address config variable. - Change the port config variable behaviour to match that of rsmb (applies to the default listener only, can be given just once). - Fix QoS 2 protocol compliance - stop sending duplicate messages and handle timeouts correctly. Fixes bug #598290. - Set retain flag correctly for outgoing messages. It should only be set for messages sent in response to a subscribe command (ie. stale data). - Fix bug in returning correct CONNACK result to on_connect client callback. - Don't send client will if it is disconnected for exceeding its keepalive timer. - Fix client library unsubscribe function incorrectly sending a SUBSCRIBE command when it should be UNSUBSCRIBE. - Fix max_inflight_messages and max_queued_messages operation. These parameters now apply only to QoS 1 and 2 messages and are used regardless of the client connection state. - mosquitto.conf now installed to /etc/mosquitto/mosquitto.conf instead of /etc/mosquitto.conf. The /etc/mosquitto/ directory will be used for password and access control files in the future. - Give the compile time option of using 32-bit integers for the database IDs instead of 64-bit integers. This is useful where htobe64()/be64toh() are not available or for embedded systems for example. - The DUP bit is now set correctly when resending PUBREL messages. - A port to Windows native has been partially completed. This currently drops a number of features, including the ability to change configuration parameters and persistent storage. 0.8.3 - 20101004 ================ - Fix QoS 2 protocol compliance - stop sending duplicate messages and handle timeouts correctly. Fixes bug #598290. (backported from future 0.9 code) 0.8.2 - 20100815 ================ - Fix default loop() timeout value in mosquitto.py. Previous value was 0, causing high cpu load. - Fix message handling problem in client library when more than one message was in the client queue. - Fix the logic used to determine whether a QoS>0 message needs to be retried. - Fix the Python sub.py example so that it quits on error. 0.8.1 - 20100812 ================ - Improve python interface - Fix incorrect return value from message delete function - Use logging function to print error messages in clients. - Fix python installation script DESTDIR. - Fix library destination path for 64-bit machines. 0.8 - 20100807 ============== - Topics starting with a / are treated as distinct to those not starting with a /. For example, /topic/path is different to topic/path. This matches the behaviour of rsmb. - Correctly calculate the will QoS on a new client connection (bug #597451). - Add "addresses" configuration file variable as an alias of "address", for better rsmb compatibility. - Bridge clean_session setting is now false, to give more sensible behaviour and be more compatible with rsmb. - Add cleansession variable for configuring bridges. - Add keepalive_interval variable for bridges. - Remove default topic subscription for mosquitto_sub because the old behaviour was too confusing. - Added a C client library, which the pub and sub clients now use. - Added a C++ client library (bound to the C library). - Added a Python client library (bound to the C library). - Added CMake build scripts to allow the library and clients (not the broker) to be compiled natively on Windows. 0.7 - 20100615 ============== - mosquitto_pub can now send null (zero length) messages. - Don't store QoS=0 messages for disconnected clients with subscriptions of QoS>0. - accept() all available sockets when new clients are connecting, rather than just one. - Add option to print debug messages in pub and sub clients. - hg revision is now exported via $SYS/broker/changeset - Send Will when client exceeds keepalive timer and is disconnected. - Check to see if a client has a will before sending it. - Correctly deal with clients connecting with the same id multiple times. - Add compile time option to disable heap memory tracking. - Use poll() instead of select() to allow >1024 clients. - Implement max_connections. - Run VACUUM on in-memory database on receiving SIGUSR2. - Fix bridge keepalive timeouts and reconnects. - Don't attempt to drop root privileges when running on Windows as this isn't well supported (bug #586231). 0.6.1 - 20100506 ================ - Fix DB auto upgrade for messages table. 0.6 - 20100505 ============== - Basic support for connecting multiple MQTT brokers together (bridging). - mosquitto_sub can now subscribe to multiple topics (limited to a global QoS). - mosquitto_pub can now send a file as a message. - mosquitto_pub can now read all of stdin and send it as a message. - mosquitto_pub can now read stdin and send each line as a message. - mosquitto will now correctly run VACUUM on the persistent database on exit. - Implement a more efficient database design, so that only one copy of each message is held in the database, rather than one per subscribed client. - Add the store_cleanup_interval config option for dealing with the internal message store. - Add support for disabling "clean session" for the sub client. - Add support for automatic upgrading of the mosquitto DB from v1 to v2. - Add persistence_file config option to allow changing the filename of the persistence database. This allows multiple mosquitto DBs to be stored in the same location whilst keeping persistence_location compatible with rsmb. - Don't store QoS=0 messages for disconnected clients. Fixes bug #572608. This wasn't correctly fixed in version 0.5. - Don't disconnect clients if they send a PUBLISH with zero length payload (bug #573610). - If a retained message is received with a zero length payload, the retained message for that topic is deleted. - Send through zero length messages. - Produce a warning on unsupported rsmb options instead of quitting. - Describe clean session flag in the mqtt man page. - Implement the max_inflight_messages and max_queued_messages features in the broker. 0.5.4 - 20100311 ================ - Fix memory allocation in mqtt3_fix_sub_topic() (bug #531861). - Remove accidental limit of 100 client connections. - Fix mosquitto_pub handling of messages with QoS>0 (bug #537061). 0.5.3 - 20100303 ================ - Will messages are now only sent when a client disconnects unexpectedly. - Fix all incoming topics/subscriptions that start with a / or contain multiple / in a row (//). - Do actually disconnect client when it sends an empty subscription/topic string. - Add missing $SYS/broker/clients/total to man page. 0.5.2 - 20100302 ================ - Always update last backup time, so that the backup doesn't run every time through the main loop once autosave_interval has been reached. - Report $SYS/broker/uptime in the same format as rsmb. - Make mandatory options obvious in usage output and man page of mosquitto_pub. Fixes bug #529990. - Treat subscriptions with a trailing slash correctly. This should fix bugs #530369 and #530099. 0.5.1 - 20100227 ================ - Must daemonise before pid file is written. 0.5 - 20100227 ============== - No longer store QoS=0 messages for disconnected clients that do not have clean start set. - Rename msg_timeout option to retry_interval for better rsmb compatibility. - Change persistence behaviour. The database is now stored in memory even if persistence is enabled. It is written to disk when mosquitto exits and also at periodic intervals as defined by the new autosave_interval option. - The writing of the persistence database may be forced by sending mosquitto the SIGUSR1 signal. - Clients that do not send CONNECT as their first command are now disconnected. - Boolean configuration values may now be specified with true/false as well as 1/0. - Log message on CONNECT with invalid protocol or protocol version. - Default sqlite3-pcre path on Linux is now /usr/lib/sqlite3/pcre.so to match future sqlite3-pcre packages. - Add mosquitto_sub and mosquitto_pub, simple clients for subscribe/publish. - Add man pages for clients. - Add general man page on mqtt. - Root privileges are now dropped only after attempting to write a pid file (if configured). This means that the pid file can be written to /var/run/ directly and should fix bug #523183. 0.4.2 - 20100203 ================ - Fix segfault on client connect with invalid protocol name/version. 0.4.1 - 20100112 =============== - Fix regex used for finding retained messages to send on new subscription. 0.4 - 20100105 ============== - Added support for wildcard subscriptions using + and #. - All network operations are now non-blocking and can cope with partial packets, meaning that networking should be a lot more reliable. - Total messsages/bytes sent/received are now available in $SYS. - Improved logging information - use client ip address and id instead of socket number. - Broker build timestamp is available in $SYS. - Keepalive==0 is now correctly treated as "never disconnect". - Fixed manpage installation. - Fixed incorrect $SYS hierarchy locations in documentation and code. - Debug type log messages are no longer sent to "topics". - Default logging destination no longer includes "topics" to prevent possible error logging to the db before it is initialised. - Periodic $SYS messages can now be disabled. - stdout and stderr are flushed when logging to them to give more timely updates. - dup is now set correctly when resending messages. - Database format bumped due to topic column naming fix. 0.3 - 20091217 ============== - The port option in the configuration file and --port command line argument may now be given any number of times to make mosquitto listen on multiple sockets. - Add new config file and command line option "interface" to specify an interface to listen on, rather than all interfaces. - Added host access control through tcp-wrappers support. - Set SO_REUSEADDR on the listening socket so restart is much quicker. - Added support for tracking current heap memory usage - this is published on the topic "$SYS/broker/heap/current size" - Added code for logging to stderr, stdout, syslog and topics. - Added logging to numerous places - still plenty of scope for more. 0.2 - 20091204 ============== - Replaced the command line option --foreground with --daemon, swapping the default behaviour. - Added the command line option --config-file, to specify a config file to load. If this is not given, no config file is load and the default options are used. - Added the command line option --port for specifying the port to listen on. This overrides values in the config file. - Don't use persistence by default. - Default behaviour is now more sane when run by a normal user with no command line options (combination of above changes). - Added option user to config file, defaulting to a value of mosquitto. If this value isn't blank and mosquitto is started by root, then it will drop privileges by changing to the user and its primary group. This replaces the current behaviour of refusing to start if run by root. - Fix non-persistent mode, which would never work in the previous release. - Added information on default values of msg_timeout and sys_interval to the mosquitto.conf man page. (closes bug #492045). mosquitto-1.4.15/config.h0000664000175000017500000000141613245550210014303 0ustar rogerroger/* ============================================================ * Control compile time options. * ============================================================ * * Compile time options have moved to config.mk. */ /* ============================================================ * Compatibility defines * * Generally for Windows native support. * ============================================================ */ #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) mosquitto-1.4.15/misc/0000775000175000017500000000000013245550210013616 5ustar rogerrogermosquitto-1.4.15/misc/currentcost/0000775000175000017500000000000013245550210016171 5ustar rogerrogermosquitto-1.4.15/misc/currentcost/cc128_read.pl0000775000175000017500000000071713245550210020351 0ustar rogerroger#!/usr/bin/perl -w # Reads data from a Current Cost device via serial port. # Spawns use strict; use Device::SerialPort qw( :PARAM :STAT 0.07 ); my $pubclient = "mosquitto_pub -t sensors/cc128/raw -q 2 -l"; my $PORT = "/dev/ttyUSB0"; local $| = 1; my $ob = Device::SerialPort->new($PORT); $ob->baudrate(57600); $ob->write_settings; open(SERIAL, "+<$PORT"); open(MQTT, "|$pubclient"); while (my $line = ) { print(MQTT "$line"); } close(MQTT); mosquitto-1.4.15/misc/currentcost/cc128_parse.pl0000775000175000017500000000250013245550210020540 0ustar rogerroger#!/usr/bin/perl -w # Read raw cc128 data and republish without xml. # Probably only works if you have a single channel. use strict; use HTTP::Date "str2time"; use FileHandle; local $| = 1; my $subclient = "/usr/bin/mosquitto_sub -t sensors/cc128/raw -q 2"; my $pubclient = "/usr/bin/mosquitto_pub -t sensors/cc128 -q 2 -l"; my $pubclient_ch1 = "/usr/bin/mosquitto_pub -t sensors/cc128/ch1 -q 2 -l"; open(SUB, "$subclient|"); open(PUB, "|$pubclient"); open(PUB_CH1, "|$pubclient_ch1"); SUB->autoflush(1); PUB->autoflush(1); PUB_CH1->autoflush(1); while (my $line = ) { #CC128-v0.120000215.7003112100108 if ($line =~ m# *([\-\d.]+)0[0-9]*10*(\d+) $now){ $r_stamp -= 86400; } print PUB "$r_stamp,$temp,$watts\n"; print PUB_CH1 "$r_stamp $watts\n"; } } mosquitto-1.4.15/misc/currentcost/cc128_read.py0000775000175000017500000000057713245550210020372 0ustar rogerroger#!/usr/bin/python -u import mosquitto import serial usb = serial.Serial(port='/dev/ttyUSB0', baudrate=57600) mosq = mosquitto.Mosquitto() mosq.connect("localhost") mosq.loop_start() running = True try: while running: line = usb.readline() mosq.publish("cc128/raw", line) except usb.SerialException, e: running = False mosq.disconnect() mosq.loop_stop() mosquitto-1.4.15/misc/currentcost/cc128_log_mysql.pl0000775000175000017500000000267013245550210021444 0ustar rogerroger#!/usr/bin/perl # Log CurrentCost power meter data to a mysql database. # Assumes data is coming in on MQTT topic sensors/cc128 # and in format timestamp,temperature,ch1_data # e.g. 1276605752,12.7,86 # To create database, table and user: # # CREATE DATABASE powermeter; # USE 'powermeter'; # CREATE TABLE powermeter ( # `id` INT NOT NULL auto_increment, # `timestamp` INT NOT NULL, # `temperature` FLOAT NOT NULL DEFAULT 0.0, # `ch1` INT NOT NULL DEFAULT 0, # PRIMARY KEY (`id`), # UNIQUE KEY `timestamp` (`timestamp`) # ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # # CREATE USER 'powermeter'@'localhost' IDENTIFIED BY ''; # GRANT ALL ON powermeter.* to 'powermeter'@'localhost'; use strict; use DBI(); use FileHandle; local $| = 1; my $dbname = "powermeter"; my $dbhost = "localhost"; my $dbusername = "powermeter"; my $dbpassword = "password"; my $dbtable = "powermeter"; my $subclient = "/usr/bin/mosquitto_sub -t sensors/cc128"; open(SUB, "$subclient|"); SUB->autoflush(1); my $dbh = DBI->connect("DBI:mysql:database=$dbname;host=$dbhost", "$dbusername", "$dbpassword", {'RaiseError' => 1}); my $query = "INSERT INTO powermeter (timestamp, temperature, ch1) VALUES (?,?,?)"; my @vals; my ($timestamp, $temperature, $ch1); while (my $line = ) { @vals = split(/,/, $line); $timestamp = @vals[0]; $temperature = @vals[1]; $ch1 = @vals[2]; $dbh->do($query, undef, $timestamp, $temperature, $ch1); } $dbh->disconnect(); mosquitto-1.4.15/misc/currentcost/gnome-panel/0000775000175000017500000000000013245550210020373 5ustar rogerrogermosquitto-1.4.15/misc/currentcost/gnome-panel/CurrentCostMQTT.server0000664000175000017500000000217613245550210024612 0ustar rogerroger mosquitto-1.4.15/misc/currentcost/gnome-panel/CurrentCostMQTT.py0000775000175000017500000000421113245550210023727 0ustar rogerroger#!/usr/bin/env python import gnomeapplet import gtk import mosquitto import sys class CurrentCostMQTT(gnomeapplet.Applet): def on_message(self, mosq, obj, msg): # Message format is "power" self.label.set_text(msg.payload+"W") def set_label(self, val): self.label.set_text(val) def on_change_background(self, applet, type, color, pixmap): applet.set_style(None) applet.modify_style(gtk.RcStyle()) if type == gnomeapplet.COLOR_BACKGROUND: applet.modify_bg(gtk.STATE_NORMAL, color) elif type == gnomeapplet.PIXMAP_BACKGROUND: style = applet.get_style().copy() style.bg_pixmap[gtk.STATE_NORMAL] = pixmap applet.set_style(style) def show_menu(self, widget, event): print "menu" def __init__(self, applet, iid): self.applet = applet self.label = gtk.Label("0W") self.event_box = gtk.EventBox() self.event_box.add(self.label) self.event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK) self.event_box.connect("button_press_event", self.show_menu) self.applet.add(self.event_box) self.applet.set_background_widget(applet) self.applet.show_all() self.mosq = mosquitto.Mosquitto() self.mosq.on_message = self.on_message self.mosq.connect("localhost") self.mosq.loop_start() self.mosq.subscribe("sensors/cc128/ch1", 0) self.applet.connect('change-background', self.on_change_background) def CurrentCostMQTT_factory(applet, iid): CurrentCostMQTT(applet, iid) return gtk.TRUE if len(sys.argv) == 2: if sys.argv[1] == "-d": #Debug mode main_window = gtk.Window(gtk.WINDOW_TOPLEVEL) main_window.set_title("Python Applet") main_window.connect("destroy", gtk.main_quit) app = gnomeapplet.Applet() CurrentCostMQTT_factory(app,None) app.reparent(main_window) main_window.show_all() gtk.main() sys.exit() if __name__ == '__main__': gnomeapplet.bonobo_factory("OAFIID:CurrentCostMQTT_Factory", gnomeapplet.Applet.__gtype__, "MQTT", "0", CurrentCostMQTT_factory) mosquitto-1.4.15/misc/currentcost/gnome-panel/currentcost.png0000664000175000017500000001230413245550210023454 0ustar rogerrogerPNG  IHDR00WsRGBbKGD pHYs ftIME m,tEXtCommentCreated with GIMPWIDAThޭk$uz{z;;"wK.IEG l  LcH,0A r DKb `ǰ2 7AEe>fv=ﮪ{ɇ]1< (TssFxiVNcrv-SՕA.z^ !<霻+@bEv(VFdDx^7Z^nF%֣kOMx̙v% B#,^'d2PAdxE hP1VRj^,};I?Y<ųÉYiT{:p:ܘLǽ_L&{8F# +J{g2`D *jQk?M;]t0F6ky0I^= j8ջPζAy$1F$!c+@%Mi[+nk:RVY/7G3wl`w?}t|\GQX9D֖<B@‰s,ϘfyNARUI8mnm_?o|<j=ywN'r]UQ3oux웍I*;OGƫbUCpbU1:1LVj8ZÓO>/:G'@INpZxڱUm}Ν;cm4&Iypzh93<<~؇+ޣjqLףsZM=GV*daLͿ\[VUED 'Da-[{.~h[RȳdV]Z͖ 'h6A 4=-T*"xʊ;9!6aooϤi\A"'o IRL8K)z7ݴF)FC`gy&+7]4$Ϧ"B`n*G3 aJ<N#L&M&VmUzeFb3'ZƙvTJِ2ɊReՔZu !3 !W(PUEAfIb8d6Som8<@=P3e`^t$">E^}j`ueRݏVU1 tc v(O&5.GGGNck5QܯE^V%ix<&21ưBZ)qxL1Ȼ93~(Q @ 6"ɳ\888޳n5$˦X1+&ςh4Tk ,XɊ`I!3^ $! Zk++gi[2qn5 ;T*)׮>ƕK1w ZƗ@imm8d!Ld;'J,^0޹c(p͓b… TR3M9>d: kkkji>t@Ze9VVɳ cM |ys~ܡޮc,]`6899;7R}cȋe($8d фh\r$jG* BP<ˉίR#\rJ\1rwNseϳzRyW\\B) ce3E#X 9.l[ۻg9KV8>:PUiƀDxXW9z?6έr~c7߾CT~1]k^bX_Y%#;s$Ke̼!:viѐmjCEt5@Ygփ#DZfcE:-ȲIN_{|Ρl3NԈ-z)ZP,G1Qs҅~dݭTVOOy.,gOdc1 ޳O\RZsrpp@$[_΍ڵLjr=X[.Pc 4x,(t>k$T]{Oei7h5f޾6A X1~~lc-8&ZʹՎ^v#1%xp}{}B1B~V;F,JjMⓓSvvwKb-W"OCvVhpZԳ`xL$8x{qw7x\(kA T\i(K(^TU1jİO|QD_wMg +p~V>rۈEޕVJ*q=a0`ELm0J|G<ua:ɸ,^Z"" xSGk DB]B\๛?="`<^"jA5Kj1N؅ x2xѯ3a8b#KN?G3D,'8+\)j.:>̫"e/\SO i0o>uO?''=ob z&fKhe;歧{[ Fc$lO*Ad.vPpyfW;ܳ^oR"B%1j`Z\⹕O{&Grm1zeZv)CDNx&b>,c7Ixң"5x2a%Ix,+m{߽OdeIVJ\^x+~Mݮ^p lVv\R# w^?V*xPΈHyQ@8Q~<rɳO?+/_訫X޽G̥֛_[bl_ zL&u2*\N%w3fJ-+r5& b} 1"jQ ̲}gϾܫ [^m}ORL\>v[}uwgr8bmm-lllH2 :f(5jZs4(zfŸ*˝֋|,lΓO=E=[җoX_wwÃse{f3<JY,T4#DQk ,ԫKϷj|Sq^zyp0O+?ճ޼K?9=]ZQIH̚2o8J} ERINKzsy.+wyxpt*:_7?:>?=̈ (zG,)d^QrIY_~鿊ޛo37{+z/u։Wf/*ս^ _WIgDg`9GvjO*ieV1Oo~wG}U[?xn*SOK:4/_/RowkvtyN^sO\/wg?Ddq}?Pb} }aQӾZhIENDB`mosquitto-1.4.15/examples/0000775000175000017500000000000013245550210014501 5ustar rogerrogermosquitto-1.4.15/examples/temperature_conversion/0000775000175000017500000000000013245550210021303 5ustar rogerrogermosquitto-1.4.15/examples/temperature_conversion/temperature_conversion.cpp0000664000175000017500000000227713245550210026621 0ustar rogerroger#include #include #include "temperature_conversion.h" #include mqtt_tempconv::mqtt_tempconv(const char *id, const char *host, int port) : mosquittopp(id) { int keepalive = 60; /* Connect immediately. This could also be done by calling * mqtt_tempconv->connect(). */ connect(host, port, keepalive); }; mqtt_tempconv::~mqtt_tempconv() { } void mqtt_tempconv::on_connect(int rc) { printf("Connected with code %d.\n", rc); if(rc == 0){ /* Only attempt to subscribe on a successful connect. */ subscribe(NULL, "temperature/celsius"); } } void mqtt_tempconv::on_message(const struct mosquitto_message *message) { double temp_celsius, temp_farenheit; char buf[51]; if(!strcmp(message->topic, "temperature/celsius")){ memset(buf, 0, 51*sizeof(char)); /* Copy N-1 bytes to ensure always 0 terminated. */ memcpy(buf, message->payload, 50*sizeof(char)); temp_celsius = atof(buf); temp_farenheit = temp_celsius*9.0/5.0 + 32.0; snprintf(buf, 50, "%f", temp_farenheit); publish(NULL, "temperature/farenheit", strlen(buf), buf); } } void mqtt_tempconv::on_subscribe(int mid, int qos_count, const int *granted_qos) { printf("Subscription succeeded.\n"); } mosquitto-1.4.15/examples/temperature_conversion/temperature_conversion.h0000664000175000017500000000062213245550210026256 0ustar rogerroger#ifndef TEMPERATURE_CONVERSION_H #define TEMPERATURE_CONVERSION_H #include class mqtt_tempconv : public mosqpp::mosquittopp { public: mqtt_tempconv(const char *id, const char *host, int port); ~mqtt_tempconv(); void on_connect(int rc); void on_message(const struct mosquitto_message *message); void on_subscribe(int mid, int qos_count, const int *granted_qos); }; #endif mosquitto-1.4.15/examples/temperature_conversion/Makefile0000664000175000017500000000071213245550210022743 0ustar rogerrogerCFLAGS=-Wall -ggdb -I../../lib -I../../lib/cpp LDFLAGS=-L../../lib ../../lib/cpp/libmosquittopp.so.1 ../../lib/libmosquitto.so.1 .PHONY: all clean all : mqtt_temperature_conversion mqtt_temperature_conversion : main.o temperature_conversion.o ${CXX} $^ -o $@ ${LDFLAGS} main.o : main.cpp ${CXX} -c $^ -o $@ ${CFLAGS} temperature_conversion.o : temperature_conversion.cpp ${CXX} -c $^ -o $@ ${CFLAGS} clean : -rm -f *.o mqtt_temperature_conversion mosquitto-1.4.15/examples/temperature_conversion/main.cpp0000664000175000017500000000047713245550210022743 0ustar rogerroger#include "temperature_conversion.h" int main(int argc, char *argv[]) { class mqtt_tempconv *tempconv; int rc; mosqpp::lib_init(); tempconv = new mqtt_tempconv("tempconv", "localhost", 1883); while(1){ rc = tempconv->loop(); if(rc){ tempconv->reconnect(); } } mosqpp::lib_cleanup(); return 0; } mosquitto-1.4.15/examples/temperature_conversion/readme.txt0000664000175000017500000000045613245550210023306 0ustar rogerrogerThis is a simple example of the C++ library mosquittopp. It is a client that subscribes to the topic temperature/celsius which should have temperature data in text form being published to it. It reads this data as a Celsius temperature, converts to Farenheit and republishes on temperature/farenheit. mosquitto-1.4.15/examples/mysql_log/0000775000175000017500000000000013245550210016507 5ustar rogerrogermosquitto-1.4.15/examples/mysql_log/Makefile0000664000175000017500000000043713245550210020153 0ustar rogerrogerCFLAGS=-Wall -ggdb LDFLAGS=../../lib/libmosquitto.so.1 -lmysqlclient .PHONY: all clean all : mosquitto_mysql_log mosquitto_mysql_log : mysql_log.o ${CC} $^ -o $@ ${LDFLAGS} mysql_log.o : mysql_log.c ${CC} -c $^ -o $@ ${CFLAGS} -I../../lib clean : -rm -f *.o mosquitto_mysql_log mosquitto-1.4.15/examples/mysql_log/mysql_log.c0000664000175000017500000000527713245550210020674 0ustar rogerroger#include #include #include #ifndef WIN32 # include #else # include # define snprintf sprintf_s #endif #include #include #define db_host "localhost" #define db_username "mqtt_log" #define db_password "password" #define db_database "mqtt_log" #define db_port 3306 #define db_query "INSERT INTO mqtt_log (topic, payload) VALUES (?,?)" #define mqtt_host "localhost" #define mqtt_port 1883 static int run = 1; static MYSQL_STMT *stmt = NULL; void handle_signal(int s) { run = 0; } void connect_callback(struct mosquitto *mosq, void *obj, int result) { } void message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) { MYSQL_BIND bind[2]; memset(bind, 0, sizeof(bind)); bind[0].buffer_type = MYSQL_TYPE_STRING; bind[0].buffer = message->topic; bind[0].buffer_length = strlen(message->topic); // Note: payload is normally a binary blob and could contains // NULL byte. This sample does not handle it and assume payload is a // string. bind[1].buffer_type = MYSQL_TYPE_STRING; bind[1].buffer = message->payload; bind[1].buffer_length = message->payloadlen; mysql_stmt_bind_param(stmt, bind); mysql_stmt_execute(stmt); } int main(int argc, char *argv[]) { MYSQL *connection; my_bool reconnect = true; char clientid[24]; struct mosquitto *mosq; int rc = 0; signal(SIGINT, handle_signal); signal(SIGTERM, handle_signal); mysql_library_init(0, NULL, NULL); mosquitto_lib_init(); connection = mysql_init(NULL); if(connection){ mysql_options(connection, MYSQL_OPT_RECONNECT, &reconnect); connection = mysql_real_connect(connection, db_host, db_username, db_password, db_database, db_port, NULL, 0); if(connection){ stmt = mysql_stmt_init(connection); mysql_stmt_prepare(stmt, db_query, strlen(db_query)); memset(clientid, 0, 24); snprintf(clientid, 23, "mysql_log_%d", getpid()); mosq = mosquitto_new(clientid, true, connection); if(mosq){ mosquitto_connect_callback_set(mosq, connect_callback); mosquitto_message_callback_set(mosq, message_callback); rc = mosquitto_connect(mosq, mqtt_host, mqtt_port, 60); mosquitto_subscribe(mosq, NULL, "#", 0); while(run){ rc = mosquitto_loop(mosq, -1, 1); if(run && rc){ sleep(20); mosquitto_reconnect(mosq); } } mosquitto_destroy(mosq); } mysql_stmt_close(stmt); mysql_close(connection); }else{ fprintf(stderr, "Error: Unable to connect to database.\n"); printf("%s\n", mysql_error(connection)); rc = 1; } }else{ fprintf(stderr, "Error: Unable to start mysql.\n"); rc = 1; } mysql_library_end(); mosquitto_lib_cleanup(); return rc; } mosquitto-1.4.15/man/0000775000175000017500000000000013245550210013436 5ustar rogerrogermosquitto-1.4.15/man/mosquitto.conf.5.xml0000664000175000017500000017535313245550210017331 0ustar rogerroger mosquitto.conf 5 Mosquitto Project File formats and conventions mosquitto.conf the configuration file for mosquitto mosquitto.conf Description mosquitto.conf is the configuration file for mosquitto. This file can reside anywhere as long as mosquitto can read it. By default, mosquitto does not need a configuration file and will use the default values listed below. See mosquitto8 for information on how to load a configuration file. File Format All lines with a # as the very first character are treated as a comment. Configuration lines start with a variable name. The variable value is separated from the name by a single space. Authentication The authentication options described below allow a wide range of possibilities in conjunction with the listener options. This section aims to clarify the possibilities. The simplest option is to have no authentication at all. This is the default if no other options are given. Unauthenticated encrypted support is provided by using the certificate based SSL/TLS based options cafile/capath, certfile and keyfile. MQTT provides username/password authentication as part of the protocol. Use the password_file option to define the valid usernames and passwords. Be sure to use network encryption if you are using this option otherwise the username and password will be vulnerable to interception. When using certificate based encryption there are two options that affect authentication. The first is require_certificate, which may be set to true or false. If false, the SSL/TLS component of the client will verify the server but there is no requirement for the client to provide anything for the server: authentication is limited to the MQTT built in username/password. If require_certificate is true, the client must provide a valid certificate in order to connect successfully. In this case, the second option, use_identity_as_username, becomes relevant. If set to true, the Common Name (CN) from the client certificate is used instead of the MQTT username for access control purposes. The password is not replaced because it is assumed that only authenticated clients have valid certificates. If use_identity_as_username is false, the client must authenticate as normal (if required by password_file) through the MQTT options. When using pre-shared-key based encryption through the psk_hint and psk_file options, the client must provide a valid identity and key in order to connect to the broker before any MQTT communication takes place. If use_identity_as_username is true, the PSK identity is used instead of the MQTT username for access control purposes. If use_identity_as_username is false, the client may still authenticate using the MQTT username/password if using the password_file option. Both certificate and PSK based encryption are configured on a per-listener basis. Authentication plugins can be created to replace the password_file and psk_file options (as well as the ACL options) with e.g. SQL based lookups. It is possible to support multiple authentication schemes at once. A config could be created that had a listener for all of the different encryption options described above and hence a large number of ways of authenticating. General Options file path Set the path to an access control list file. If defined, the contents of the file are used to control client access to topics on the broker. If this parameter is defined then only the topics listed will have access. Topic access is added with lines of the format: topic [read|write|readwrite] <topic> The access type is controlled using "read", "write" or "readwrite". This parameter is optional (unless <topic> includes a space character) - if not given then the access is read/write. <topic> can contain the + or # wildcards as in subscriptions. The first set of topics are applied to anonymous clients, assuming is true. User specific topic ACLs are added after a user line as follows: user <username> The username referred to here is the same as in . It is not the clientid. It is also possible to define ACLs based on pattern substitution within the topic. The form is the same as for the topic keyword, but using pattern as the keyword. pattern [read|write|readwrite] <topic> The patterns available for substition are: %c to match the client id of the client %u to match the username of the client The substitution pattern must be the only text for that level of hierarchy. Pattern ACLs apply to all users even if the "user" keyword has previously been given. Example: pattern write sensor/%u/data Allow access for bridge connection messages: pattern write $SYS/broker/connection/%c/state If the first character of a line of the ACL file is a # it is treated as a comment. Reloaded on reload signal. The currently loaded ACLs will be freed and reloaded. Existing subscriptions will be affected after the reload. [ true | false ] Boolean value that determines whether clients that connect without providing a username are allowed to connect. If set to false then another means of connection should be created to control authenticated client access. Defaults to true. Reloaded on reload signal. [ true | false ] If a client is subscribed to multiple subscriptions that overlap, e.g. foo/# and foo/+/baz , then MQTT expects that when the broker receives a message on a topic that matches both subscriptions, such as foo/bar/baz, then the client should only receive the message once. Mosquitto keeps track of which clients a message has been sent to in order to meet this requirement. This option allows this behaviour to be disabled, which may be useful if you have a large number of clients subscribed to the same set of topics and want to minimise memory usage. It can be safely set to true if you know in advance that your clients will never have overlapping subscriptions, otherwise your clients must be able to correctly deal with duplicate messages even when then have QoS=2. Defaults to true. Reloaded on reload signal. value Options to be passed to the auth plugin. See the specific plugin instructions. file path Specify an external module to use for authentication and access control. This allows custom username/password and access control functions to be created. Not currently reloaded on reload signal. [ true | false ] If true then before an ACL check is made, the username/client id of the client needing the check is searched for the presence of either a '+' or '#' character. If either of these characters is found in either the username or client id, then the ACL check is denied before it is sent to the plugin. This check prevents the case where a malicious user could circumvent an ACL check by using one of these characters as their username or client id. This is the same issue as was reported with mosquitto itself as CVE-2017-7650. If you are entirely sure that the plugin you are using is not vulnerable to this attack (i.e. if you never use usernames or client ids in topics) then you can disable this extra check and hence have all ACL checks delivered to your plugin by setting this option to false. Defaults to true. Not currently reloaded on reload signal. seconds The number of seconds that mosquitto will wait between each time it saves the in-memory database to disk. If set to 0, the in-memory database will only be saved when mosquitto exits or when receiving the SIGUSR1 signal. Note that this setting only has an effect if persistence is enabled. Defaults to 1800 seconds (30 minutes). Reloaded on reload signal. [ true | false ] If true, mosquitto will count the number of subscription changes, retained messages received and queued messages and if the total exceeds then the in-memory database will be saved to disk. If false, mosquitto will save the in-memory database to disk by treating as a time in seconds. Reloaded on reload signal. prefix If defined, only clients that have a clientid with a prefix that matches clientid_prefixes will be allowed to connect to the broker. For example, setting "secure-" here would mean a client "secure-client" could connect but another with clientid "mqtt" couldn't. By default, all client ids are valid. Reloaded on reload signal. Note that currently connected clients will be unaffected by any changes. [ true | false ] If set to true, the log will include entries when clients connect and disconnect. If set to false, these entries will not appear. Reloaded on reload signal. dir External configuration files may be included by using the include_dir option. This defines a directory that will be searched for config files. All files that end in '.conf' will be loaded as a configuration file. It is best to have this as the last option in the main file. This option will only be processed from the main configuration file. The directory specified must not contain the main configuration file. destinations Send log messages to a particular destination. Possible destinations are: . and log to the console on the named output. uses the userspace syslog facility which usually ends up in /var/log/messages or similar and topic logs to the broker topic '$SYS/broker/log/<severity>', where severity is one of D, E, W, N, I, M which are debug, error, warning, notice, information and message. Message type severity is used by the subscribe and unsubscribe log_type options and publishes log messages at $SYS/broker/log/M/subscribe and $SYS/broker/log/M/unsubscribe. The destination requires an additional parameter which is the file to be logged to, e.g. "log_dest file /var/log/mosquitto.log". The file will be closed and reopened when the broker receives a HUP signal. Only a single file destination may be configured. Use "log_dest none" if you wish to disable logging. Defaults to stderr. This option may be specified multiple times. Note that if the broker is running as a Windows service it will default to "log_dest none" and neither stdout nor stderr logging is available. Reloaded on reload signal. local facility If using syslog logging (not on Windows), messages will be logged to the "daemon" facility by default. Use the option to choose which of local0 to local7 to log to instead. The option value should be an integer value, e.g. "log_facility 5" to use local5. [ true | false ] Boolean value, if set to true a timestamp value will be added to each log entry. The default is true. Reloaded on reload signal. types Choose types of messages to log. Possible types are: debug, error, warning, notice, information, subscribe, unsubscribe, websockets, none, all. Defaults to error, warning, notice and information. This option may be specified multiple times. Note that the debug type (used for decoding incoming/outgoing network packets) is never logged in topics. Reloaded on reload signal. count The maximum number of QoS 1 or 2 messages that can be in the process of being transmitted simultaneously. This includes messages currently going through handshakes and messages that are being retried. Defaults to 20. Set to 0 for no maximum. If set to 1, this will guarantee in-order delivery of messages. Reloaded on reload signal. count The maximum number of QoS 1 or 2 messages to hold in the queue above those messages that are currently in flight. Defaults to 100. Set to 0 for no maximum (not recommended). See also the option. Reloaded on reload signal. limit This option sets the maximum publish payload size that the broker will allow. Received messages that exceed this size will not be accepted by the broker. The default value is 0, which means that all valid MQTT messages are accepted. MQTT imposes a maximum payload size of 268435455 bytes. file path Set the path to a password file. If defined, the contents of the file are used to control client access to the broker. The file can be created using the mosquitto_passwd1 utility. If mosquitto is compiled without TLS support (it is recommended that TLS support is included), then the password file should be a text file with each line in the format "username:password", where the colon and password are optional but recommended. If is set to false, only users defined in this file will be able to connect. Setting to true when password_fileis defined is valid and could be used with acl_file to have e.g. read only guest/anonymous accounts and defined users that can publish. Reloaded on reload signal. The currently loaded username and password data will be freed and reloaded. Clients that are already connected will not be affected. See also mosquitto_passwd1. [ true | false ] If true, connection, subscription and message data will be written to the disk in mosquitto.db at the location dictated by persistence_location. When mosquitto is restarted, it will reload the information stored in mosquitto.db. The data will be written to disk when mosquitto closes and also at periodic intervals as defined by autosave_interval. Writing of the persistence database may also be forced by sending mosquitto the SIGUSR1 signal. If false, the data will be stored in memory only. Defaults to false. Reloaded on reload signal. file name The filename to use for the persistent database. Defaults to mosquitto.db. Reloaded on reload signal. path The path where the persistence database should be stored. Must end in a trailing slash. If not given, then the current directory is used. Reloaded on reload signal. duration This option allows persistent clients (those with clean session set to false) to be removed if they do not reconnect within a certain time frame. This is a non-standard option. As far as the MQTT spec is concerned, persistent clients persist forever. Badly designed clients may set clean session to false whilst using a randomly generated client id. This leads to persistent clients that will never reconnect. This option allows these clients to be removed. The expiration period should be an integer followed by one of h d w m y for hour, day, week, month and year respectively. For example: persistent_client_expiration 2m persistent_client_expiration 14d persistent_client_expiration 1y As this is a non-standard option, the default if not set is to never expire persistent clients. Reloaded on reload signal. file path Write a pid file to the file specified. If not given (the default), no pid file will be written. If the pid file cannot be written, mosquitto will exit. This option only has an effect is mosquitto is run in daemon mode. If mosquitto is being automatically started by an init script it will usually be required to write a pid file. This should then be configured as e.g. /var/run/mosquitto.pid Not reloaded on reload signal. file path Set the path to a pre-shared-key file. This option requires a listener to be have PSK support enabled. If defined, the contents of the file are used to control client access to the broker. Each line should be in the format "identity:key", where the key is a hexadecimal string with no leading "0x". A client connecting to a listener that has PSK support enabled must provide a matching identity and PSK to allow the encrypted connection to proceed. Reloaded on reload signal. The currently loaded identity and key data will be freed and reloaded. Clients that are already connected will not be affected. [ true | false ] Set to true to queue messages with QoS 0 when a persistent client is disconnected. These messages are included in the limit imposed by max_queued_messages. Defaults to false. Note that the MQTT v3.1 spec states that only QoS 1 and 2 messages should be saved in this situation so this is a non-standard option. Reloaded on reload signal. [ true | false ] This is a synonym of the option. Reloaded on reload signal. seconds The integer number of seconds after a QoS=1 or QoS=2 message has been sent that mosquitto will wait before retrying when no response is received. If unset, defaults to 20 seconds. Reloaded on reload signal. seconds The integer number of seconds between the internal message store being cleaned of messages that are no longer referenced. Lower values will result in lower memory usage but more processor time, higher values will have the opposite effect. Setting a value of 0 means the unreferenced messages will be disposed of as quickly as possible. Defaults to 10 seconds. Reloaded on reload signal. seconds The integer number of seconds between updates of the $SYS subscription hierarchy, which provides status information about the broker. If unset, defaults to 10 seconds. Set to 0 to disable publishing the $SYS hierarchy completely. Reloaded on reload signal. [ true | false ] The MQTT specification requires that the QoS of a message delivered to a subscriber is never upgraded to match the QoS of the subscription. Enabling this option changes this behaviour. If is set true, messages sent to a subscriber will always match the QoS of its subscription. This is a non-standard option not provided for by the spec. Defaults to false. Reloaded on reload signal. username When run as root, change to this user and its primary group on startup. If mosquitto is unable to change to this user and group, it will exit with an error. The user specified must have read/write access to the persistence database if it is to be written. If run as a non-root user, this setting has no effect. Defaults to mosquitto. This setting has no effect on Windows and so you should run mosquitto as the user you wish it to run as. Not reloaded on reload signal. Listeners The network ports that mosquitto listens on can be controlled using listeners. The default listener options can be overridden and further listeners can be created. General Options address Listen for incoming network connections on the specified IP address/hostname only. This is useful to restrict access to certain network interfaces. To restrict access to mosquitto to the local host only, use "bind_address localhost". This only applies to the default listener. Use the listener variable to control other listeners. Not reloaded on reload signal. directory When a listener is using the websockets protocol, it is possible to serve http data as well. Set to a directory which contains the files you wish to serve. If this option is not specified, then no normal http connections will be possible. Not reloaded on reload signal. port bind address/host Listen for incoming network connection on the specified port. A second optional argument allows the listener to be bound to a specific ip address/hostname. If this variable is used and neither the global nor options are used then the default listener will not be started. The option allows this listener to be bound to a specific IP address by passing an IP address or hostname. For websockets listeners, it is only possible to pass an IP address here. This option may be specified multiple times. See also the option. Not reloaded on reload signal. count Limit the total number of clients connected for the current listener. Set to -1 to have "unlimited" connections. Note that other limits may be imposed that are outside the control of mosquitto. See e.g. limits.conf5. Not reloaded on reload signal. topic prefix This option is used with the listener option to isolate groups of clients. When a client connects to a listener which uses this option, the string argument is attached to the start of all topics for this client. This prefix is removed when any messages are sent to the client. This means a client connected to a listener with mount point example can only see messages that are published in the topic hierarchy example and above. Not reloaded on reload signal. port number Set the network port for the default listener to listen on. Defaults to 1883. Not reloaded on reload signal. value Set the protocol to accept for this listener. Can be , the default, or if available. Websockets support is currently disabled by default at compile time. Certificate based TLS may be used with websockets, except that only the , , and options are supported. Not reloaded on reload signal. [ true | false ] Set to true to replace the clientid that a client connected with with its username. This allows authentication to be tied to the clientid, which means that it is possible to prevent one client disconnecting another by using the same clientid. Defaults to false. If a client connects with no username it will be disconnected as not authorised when this option is set to true. Do not use in conjunction with . See also . Not reloaded on reload signal. level Change the websockets logging level. This is a global option, it is not possible to set per listener. This is an integer that is interpreted by libwebsockets as a bit mask for its lws_log_levels enum. See the libwebsockets documentation for more details. To use this option, must also be enabled. Defaults to 0. Certificate based SSL/TLS Support The following options are available for all listeners to configure certificate based SSL support. See also "Pre-shared-key based SSL/TLS support". file path At least one of or must be provided to allow SSL support. is used to define the path to a file containing the PEM encoded CA certificates that are trusted. directory path At least one of or must be provided to allow SSL support. is used to define a directory that contains PEM encoded CA certificates that are trusted. For to work correctly, the certificates files must have ".pem" as the file ending and you must run "c_rehash <path to capath>" each time you add/remove a certificate. file path Path to the PEM encoded server certificate. cipher:list The list of allowed ciphers, each separated with a colon. Available ciphers can be obtained using the "openssl ciphers" command. file path If you have set to true, you can create a certificate revocation list file to revoke access to particular client certificates. If you have done this, use crlfile to point to the PEM encoded revocation file. file path Path to the PEM encoded keyfile. [ true | false ] By default an SSL/TLS enabled listener will operate in a similar fashion to a https enabled web server, in that the server has a certificate signed by a CA and the client will verify that it is a trusted certificate. The overall aim is encryption of the network traffic. By setting to true, the client must provide a valid certificate in order for the network connection to proceed. This allows access to the broker to be controlled outside of the mechanisms provided by MQTT. version Configure the version of the TLS protocol to be used for this listener. Possible values are tlsv1.2, tlsv1.1 and tlsv1. If left unset, the default of allowing all of TLS v1.2, v1.1 and v1.0 is used. [ true | false ] If is true, you may set to true to use the CN value from the client certificate as a username. If this is true, the option will not be used for this listener. Pre-shared-key based SSL/TLS Support The following options are available for all listeners to configure pre-shared-key based SSL support. See also "Certificate based SSL/TLS support". cipher:list When using PSK, the encryption ciphers used will be chosen from the list of available PSK ciphers. If you want to control which ciphers are available, use this option. The list of available ciphers can be optained using the "openssl ciphers" command and should be provided in the same format as the output of that command. hint The option enables pre-shared-key support for this listener and also acts as an identifier for this listener. The hint is sent to clients and may be used locally to aid authentication. The hint is a free form string that doesn't have much meaning in itself, so feel free to be creative. If this option is provided, see to define the pre-shared keys to be used or create a security plugin to handle them. version Configure the version of the TLS protocol to be used for this listener. Possible values are tlsv1.2, tlsv1.1 and tlsv1. If left unset, the default of allowing all of TLS v1.2, v1.1 and v1.0 is used. [ true | false ] Set to have the psk identity sent by the client used as its username. The username will be checked as normal, so or another means of authentication checking must be used. No password will be used. Configuring Bridges Multiple bridges (connections to other brokers) can be configured using the following variables. Bridges cannot currently be reloaded on reload signal. address[:port] [address[:port]] address[:port] [address[:port]] Specify the address and optionally the port of the bridge to connect to. This must be given for each bridge connection. If the port is not specified, the default of 1883 is used. Multiple host addresses can be specified on the address config. See the option for more details on the behaviour of bridges with multiple addresses. [ true | false ] If a bridge has topics that have "out" direction, the default behaviour is to send an unsubscribe request to the remote broker on that topic. This means that changing a topic direction from "in" to "out" will not keep receiving incoming messages. Sending these unsubscribe requests is not always desirable, setting to false will disable sending the unsubscribe request. Defaults to true. version Set the version of the MQTT protocol to use with for this bridge. Can be one of mqttv31 or mqttv311. Defaults to mqttv31. [ true | false ] Set the clean session option for this bridge. Setting to false (the default), means that all subscriptions on the remote broker are kept in case of the network connection dropping. If set to true, all subscriptions and messages on the remote broker will be cleaned up if the connection drops. Note that setting to true may cause a large amount of retained messages to be sent each time the bridge reconnects. If you are using bridges with set to false (the default), then you may get unexpected behaviour from incoming topics if you change what topics you are subscribing to. This is because the remote broker keeps the subscription for the old topic. If you have this problem, connect your bridge with set to true, then reconnect with cleansession set to false as normal. name This variable marks the start of a new bridge connection. It is also used to give the bridge a name which is used as the client id on the remote broker. seconds Set the number of seconds after which the bridge should send a ping if no other traffic has occurred. Defaults to 60. A minimum value of 5 seconds is allowed. seconds Set the amount of time a bridge using the lazy start type must be idle before it will be stopped. Defaults to 60 seconds. id Set the clientid to use on the local broker. If not defined, this defaults to . If you are bridging a broker to itself, it is important that local_clientid and remote_clientid do not match. password Configure the password to be used when connecting this bridge to the local broker. This may be important when authentication and ACLs are being used. username Configure the username to be used when connecting this bridge to the local broker. This may be important when authentication and ACLs are being used. [ true | false ] If set to true, publish notification messages to the local and remote brokers giving information about the state of the bridge connection. Retained messages are published to the topic $SYS/broker/connection/<remote_clientid>/state unless otherwise set with s. If the message is 1 then the connection is active, or 0 if the connection has failed. Defaults to true. topic Choose the topic on which notifications will be published for this bridge. If not set the messages will be sent on the topic $SYS/broker/connection/<remote_clientid>/state. id Set the client id for this bridge connection. If not defined, this defaults to 'name.hostname', where name is the connection name and hostname is the hostname of this computer. This replaces the old "clientid" option to avoid confusion with local/remote sides of the bridge. "clientid" remains valid for the time being. value Configure a password for the bridge. This is used for authentication purposes when connecting to a broker that supports MQTT v3.1 and up and requires a username and/or password to connect. This option is only valid if a remote_username is also supplied. This replaces the old "password" option to avoid confusion with local/remote sides of the bridge. "password" remains valid for the time being. name Configure a username for the bridge. This is used for authentication purposes when connecting to a broker that supports MQTT v3.1 and up and requires a username and/or password to connect. See also the option. This replaces the old "username" option to avoid confusion with local/remote sides of the bridge. "username" remains valid for the time being. value Set the amount of time a bridge using the automatic start type will wait until attempting to reconnect. Defaults to 30 seconds. [ true | false ] If the bridge has more than one address given in the address/addresses configuration, the round_robin option defines the behaviour of the bridge on a failure of the bridge connection. If round_robin is false, the default value, then the first address is treated as the main bridge connection. If the connection fails, the other secondary addresses will be attempted in turn. Whilst connected to a secondary bridge, the bridge will periodically attempt to reconnect to the main bridge until successful. If round_robin is true, then all addresses are treated as equals. If a connection fails, the next address will be tried and if successful will remain connected until it fails. [ automatic | lazy | once ] Set the start type of the bridge. This controls how the bridge starts and can be one of three types: automatic, lazy and once. Note that RSMB provides a fourth start type "manual" which isn't currently supported by mosquitto. automatic is the default start type and means that the bridge connection will be started automatically when the broker starts and also restarted after a short delay (30 seconds) if the connection fails. Bridges using the lazy start type will be started automatically when the number of queued messages exceeds the number set with the option. It will be stopped automatically after the time set by the parameter. Use this start type if you wish the connection to only be active when it is needed. A bridge using the once start type will be started automatically when the broker starts but will not be restarted if the connection fails. count Set the number of messages that need to be queued for a bridge with lazy start type to be restarted. Defaults to 10 messages. pattern [[[ out | in | both ] qos-level] local-prefix remote-prefix] Define a topic pattern to be shared between the two brokers. Any topics matching the pattern (which may include wildcards) are shared. The second parameter defines the direction that the messages will be shared in, so it is possible to import messages from a remote broker using in, export messages to a remote broker using out or share messages in both directions. If this parameter is not defined, the default of out is used. The QoS level defines the publish/subscribe QoS level used for this topic and defaults to 0. The local-prefix and remote-prefix options allow topics to be remapped when publishing to and receiving from remote brokers. This allows a topic tree from the local broker to be inserted into the topic tree of the remote broker at an appropriate place. For incoming topics, the bridge will prepend the pattern with the remote prefix and subscribe to the resulting topic on the remote broker. When a matching incoming message is received, the remote prefix will be removed from the topic and then the local prefix added. For outgoing topics, the bridge will prepend the pattern with the local prefix and subscribe to the resulting topic on the local broker. When an outgoing message is processed, the local prefix will be removed from the topic then the remote prefix added. When using topic mapping, an empty prefix can be defined using the place marker "". Using the empty marker for the topic itself is also valid. The table below defines what combination of empty or value is valid. Topic Local Prefix Remote Prefix Validity 1valuevaluevaluevalid 2valuevalue""valid 3value""valuevalid 4value""""valid (no remapping) 5""valuevaluevalid (remap single local topic to remote) 6""value""invalid 7""""valueinvalid 8""""""invalid To remap an entire topic tree, use e.g.: topic # both 2 local/topic/ remote/topic/ This option can be specified multiple times per bridge. Care must be taken to ensure that loops are not created with this option. If you are experiencing high CPU load from a broker, it is possible that you have a loop where each broker is forever forwarding each other the same messages. See also the option if you have messages arriving on unexpected topics when using incoming topics. The configuration below connects a bridge to the broker at . It subscribes to the remote topic and republishes the messages received to the local topic connection test-mosquitto-org address test.mosquitto.org cleansession true topic clients/total in 0 test/mosquitto/org $SYS/broker/ [ true | false ] If try_private is set to true, the bridge will attempt to indicate to the remote broker that it is a bridge not an ordinary client. If successful, this means that loop detection will be more effective and that retained messages will be propagated correctly. Not all brokers support this feature so it may be necessary to set to false if your bridge does not connect properly. Defaults to true. SSL/TLS Support The following options are available for all bridges to configure SSL/TLS support. file path One of or must be provided to allow SSL/TLS support. bridge_cafile is used to define the path to a file containing the PEM encoded CA certificates that have signed the certificate for the remote broker. file path One of or must be provided to allow SSL/TLS support. bridge_capath is used to define the path to a directory containing the PEM encoded CA certificates that have signed the certificate for the remote broker. For bridge_capath to work correctly, the certificate files must have ".crt" as the file ending and you must run "c_rehash <path to bridge_capath>" each time you add/remove a certificate. file path Path to the PEM encoded client certificate for this bridge, if required by the remote broker. identity Pre-shared-key encryption provides an alternative to certificate based encryption. A bridge can be configured to use PSK with the and options. This is the client identity used with PSK encryption. Only one of certificate and PSK based encryption can be used on one bridge at once. [ true | false ] When using certificate based TLS, the bridge will attempt to verify the hostname provided in the remote certificate matches the host/address being connected to. This may cause problems in testing scenarios, so may be set to false to disable the hostname verification. Setting this option to true means that a malicious third party could potentially inpersonate your server, so it should always be set to false in production environments. file path Path to the PEM encoded private key for this bridge, if required by the remote broker. key Pre-shared-key encryption provides an alternative to certificate based encryption. A bridge can be configured to use PSK with the and options. This is the pre-shared-key in hexadecimal format with no "0x". Only one of certificate and PSK based encryption can be used on one bridge at once. version Configure the version of the TLS protocol to be used for this bridge. Possible values are tlsv1.2, tlsv1.1 and tlsv1. Defaults to tlsv1.2. The remote broker must support the same version of TLS for the connection to succeed. Files mosquitto.conf Bugs mosquitto bug information can be found at See Also mosquitto 8 mosquitto_passwd 1 mosquitto-tls 7 mqtt 7 limits.conf 5 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/mosquitto_passwd.1.xml0000664000175000017500000001171713245550210017753 0ustar rogerroger mosquitto_passwd 1 Mosquitto Project Commands mosquitto_passwd manage password files for mosquitto mosquitto_passwd passwordfile username mosquitto_passwd passwordfile username password mosquitto_passwd passwordfile Description mosquitto_passwd is a tool for managing password files for the mosquitto MQTT broker. Usernames must not contain ":". Passwords are stored in a similar format to crypt3. Options Run in batch mode. This allows the password to be provided at the command line which can be convenient but should be used with care because the password will be visible on the command line and in command history. Create a new password file. If the file already exists, it will be overwritten. Delete the specified user from the password file. This option can be used to upgrade/convert a password file with plain text passwords into one using hashed passwords. It will modify the specified file. It does not detect whether passwords are already hashed, so using it on a password file that already contains hashed passwords will generate new hashes based on the old hashes and render the password file unusable. The password file to modify. The username to add/update/delete. The password to use when in batch mode. Examples Add a user to a new password file: mosquitto_passwd -c /etc/mosquitto/passwd ral Delete a user from a password file mosquitto_passwd -D /etc/mosquitto/passwd ral Bugs mosquitto bug information can be found at See Also mosquitto 8 mosquitto.conf 5 mqtt 7 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/mosquitto_pub.1.xml0000664000175000017500000004777013245550210017250 0ustar rogerroger mosquitto_pub 1 Mosquitto Project Commands mosquitto_pub an MQTT version 3.1/3.1.1 client for publishing simple messages mosquitto_pub bind_address hostname client_id client id prefix keepalive time port number message QoS file message username password topic payload qos file dir file file ciphers version hex-key identity ciphers version socks-url protocol-version message-topic mosquitto_pub Description mosquitto_pub is a simple MQTT version 3.1 client that will publish a single message on a topic and exit. Options The options below may be given on the command line, but may also be placed in a config file located at or with one pair of per line. The values in the config file will be used as defaults and can be overridden by using the command line. The exceptions to this are the message type options, of which only one can be specified. Note also that currently some options cannot be negated, e.g. . Config file lines that have a as the first character are treated as comments and not processed any further. Bind the outgoing connection to a local ip address/hostname. Use this argument if you need to restrict network communication to a particular interface. Define the path to a file containing PEM encoded CA certificates that are trusted. Used to enable SSL communication. See also Define the path to a directory containing PEM encoded CA certificates that are trusted. Used to enable SSL communication. For to work correctly, the certificate files must have ".crt" as the file ending and you must run "c_rehash <path to capath>" each time you add/remove a certificate. See also Define the path to a file containing a PEM encoded certificate for this client, if required by the server. See also . An openssl compatible list of TLS ciphers to support in the client. See ciphers1 for more information. Enable debug messages. Send the contents of a file as the message. Display usage information. Specify the host to connect to. Defaults to localhost. The id to use for this client. If not given, defaults to mosquitto_pub_ appended with the process id of the client. Cannot be used at the same time as the argument. Provide a prefix that the client id will be built from by appending the process id of the client. This is useful where the broker is using the clientid_prefixes option. Cannot be used at the same time as the argument. When using certificate based encryption, this option disables verification of the server hostname in the server certificate. This can be useful when testing initial server configurations but makes it possible for a malicious third party to impersonate your server through DNS spoofing, for example. Use this option in testing only. If you need to resort to using this option in a production environment, your setup is at fault and there is no point using encryption. The number of seconds between sending PING commands to the broker for the purposes of informing it we are still connected and functioning. Defaults to 60 seconds. Define the path to a file containing a PEM encoded private key for this client, if required by the server. See also . Send messages read from stdin, splitting separate lines into separate messages. Note that blank lines won't be sent. Send a single message from the command line. Send a null (zero length) message. Connect to the port specified instead of the default 1883. Provide a password to be used for authenticating with the broker. Using this argument without also specifying a username is invalid. This requires a broker that supports MQTT v3.1. See also the option. Specify a SOCKS5 proxy to connect through. "None" and "username" authentication types are supported. The must be of the form . The protocol prefix means that hostnames are resolved by the proxy. The symbols %25, %3A and %40 are URL decoded into %, : and @ respectively, if present in the username or password. If username is not given, then no authentication is attempted. If the port is not given, then the default of 1080 is used. More SOCKS versions may be available in the future, depending on demand, and will use different protocol prefixes as described in curl 1 . Provide the hexadecimal (no leading 0x) pre-shared-key matching the one used on the broker to use TLS-PSK encryption support. must also be provided to enable TLS-PSK. The client identity to use with TLS-PSK support. This may be used instead of a username if the broker is configured to do so. Specify the quality of service to use for the message, from 0, 1 and 2. Defaults to 0. If this argument is given, no runtime errors will be printed. This excludes any error messages given in case of invalid user input (e.g. using without a port). If retain is given, the message will be retained as a "last known good" value on the broker. See mqtt7 for more information. Send a message read from stdin, sending the entire content as a single message. Use SRV lookups to determine which host to connect to. Performs lookups to when used in conjunction with , otherwise uses . The MQTT topic on which to publish the message. See mqtt7 for more information on MQTT topics. Choose which TLS protocol version to use when communicating with the broker. Valid options are , and . The default value is . If the installed version of openssl is too old, only will be available. Must match the protocol version used by the broker. Provide a username to be used for authenticating with the broker. This requires a broker that supports MQTT v3.1. See also the argument. Specify which version of the MQTT protocol should be used when connecting to the rmeote broker. Can be or . Defaults to . Specify a message that will be stored by the broker and sent out if this client disconnects unexpectedly. This must be used in conjunction with . The QoS to use for the Will. Defaults to 0. This must be used in conjunction with . If given, if the client disconnects unexpectedly the message sent out will be treated as a retained message. This must be used in conjunction with . The topic on which to send a Will, in the event that the client disconnects unexpectedly. Wills mosquitto_sub can register a message with the broker that will be sent out if it disconnects unexpectedly. See mqtt7 for more information. The minimum requirement for this is to use to specify which topic the will should be sent out on. This will result in a non-retained, zero length message with QoS 0. Use the , and arguments to modify the other will parameters. Examples Publish temperature information to localhost with QoS 1: mosquitto_pub -t sensors/temperature -m 32 -q 1 Publish timestamp and temperature information to a remote host on a non-standard port and QoS 0: mosquitto_pub -h 192.168.1.1 -p 1885 -t sensors/temperature -m "1266193804 32" Publish light switch status. Message is set to retained because there may be a long period of time between light switch events: mosquitto_pub -r -t switches/kitchen_lights/status -m "on" Send the contents of a file in two ways: mosquitto_pub -t my/topic -f ./data mosquitto_pub -t my/topic -s < ./data Send parsed electricity usage data from a Current Cost meter, reading from stdin with one line/reading as one message: read_cc128.pl | mosquitto_pub -t sensors/cc128 -l Files $XDG_CONFIG_HOME/mosquitto_pub $HOME/.config/mosquitto_pub Configuration file for default options. Bugs mosquitto bug information can be found at See Also mqtt 7 mosquitto_sub 1 mosquitto 8 libmosquitto 3 mosquitto-tls 7 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/manpage.xsl0000664000175000017500000000144313245550210015600 0ustar rogerroger 0 0 http://mosquitto.org/man/ ansi mosquitto-1.4.15/man/html.xsl0000664000175000017500000000130713245550210015133 0ustar rogerroger man.css ansi ansi mosquitto-1.4.15/man/mqtt.7.xml0000664000175000017500000002031013245550210015306 0ustar rogerroger mqtt 7 Mosquitto Project Conventions and miscellaneous mqtt MQ Telemetry Transport MQTT Description MQTT is a lightweight publish/subscribe messaging protocol. It is useful for use with low power sensors, but is applicable to many scenarios. This manual describes some of the features of MQTT version 3.1, to assist end users in getting the most out of the protocol. For more complete information on MQTT, see http://mqtt.org/. Publish/Subscribe The MQTT protocol is based on the principle of publishing messages and subscribing to topics, or "pub/sub". Multiple clients connect to a broker and subscribe to topics that they are interested in. Clients also connect to the broker and publish messages to topics. Many clients may subscribe to the same topics and do with the information as they please. The broker and MQTT act as a simple, common interface for everything to connect to. This means that you if you have clients that dump subscribed messages to a database, to Twitter, Cosm or even a simple text file, then it becomes very simple to add new sensors or other data input to a database, Twitter or so on. Topics/Subscriptions Messages in MQTT are published on topics. There is no need to configure a topic, publishing on it is enough. Topics are treated as a hierarchy, using a slash (/) as a separator. This allows sensible arrangement of common themes to be created, much in the same way as a filesystem. For example, multiple computers may all publish their hard drive temperature information on the following topic, with their own computer and hard drive name being replaced as appropriate: sensors/COMPUTER_NAME/temperature/HARDDRIVE_NAME Clients can receive messages by creating subscriptions. A subscription may be to an explicit topic, in which case only messages to that topic will be received, or it may include wildcards. Two wildcards are available, or . can be used as a wildcard for a single level of hierarchy. It could be used with the topic above to get information on all computers and hard drives as follows: sensors/+/temperature/+ As another example, for a topic of "a/b/c/d", the following example subscriptions will match: a/b/c/d +/b/c/d a/+/c/d a/+/+/d +/+/+/+ The following subscriptions will not match: a/b/c b/+/c/d +/+/+ can be used as a wildcard for all remaining levels of hierarchy. This means that it must be the final character in a subscription. With a topic of "a/b/c/d", the following example subscriptions will match: a/b/c/d # a/# a/b/# a/b/c/# +/b/c/# Zero length topic levels are valid, which can lead to some slightly non-obvious behaviour. For example, a topic of "a//topic" would correctly match against a subscription of "a/+/topic". Likewise, zero length topic levels can exist at both the beginning and the end of a topic string, so "/a/topic" would match against a subscription of "+/a/topic", "#" or "/#", and a topic "a/topic/" would match against a subscription of "a/topic/+" or "a/topic/#". Quality of Service MQTT defines three levels of Quality of Service (QoS). The QoS defines how hard the broker/client will try to ensure that a message is received. Messages may be sent at any QoS level, and clients may attempt to subscribe to topics at any QoS level. This means that the client chooses the maximum QoS it will receive. For example, if a message is published at QoS 2 and a client is subscribed with QoS 0, the message will be delivered to that client with QoS 0. If a second client is also subscribed to the same topic, but with QoS 2, then it will receive the same message but with QoS 2. For a second example, if a client is subscribed with QoS 2 and a message is published on QoS 0, the client will receive it on QoS 0. Higher levels of QoS are more reliable, but involve higher latency and have higher bandwidth requirements. 0: The broker/client will deliver the message once, with no confirmation. 1: The broker/client will deliver the message at least once, with confirmation required. 2: The broker/client will deliver the message exactly once by using a four step handshake. Retained Messages All messages may be set to be retained. This means that the broker will keep the message even after sending it to all current subscribers. If a new subscription is made that matches the topic of the retained message, then the message will be sent to the client. This is useful as a "last known good" mechanism. If a topic is only updated infrequently, then without a retained message, a newly subscribed client may have to wait a long time to receive an update. With a retained message, the client will receive an instant update. Clean session / Durable connections On connection, a client sets the "clean session" flag, which is sometimes also known as the "clean start" flag. If clean session is set to false, then the connection is treated as durable. This means that when the client disconnects, any subscriptions it has will remain and any subsequent QoS 1 or 2 messages will be stored until it connects again in the future. If clean session is true, then all subscriptions will be removed for the client when it disconnects. Wills When a client connects to a broker, it may inform the broker that it has a will. This is a message that it wishes the broker to send when the client disconnects unexpectedly. The will message has a topic, QoS and retain status just the same as any other message. See Also mosquitto 8 mosquitto_pub 1 mosquitto_sub 1 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/mosquitto-tls.7.xml0000664000175000017500000000717413245550210017202 0ustar rogerroger mosquitto-tls 7 Mosquitto Project Conventions and miscellaneous mosquitto-tls Configure SSL/TLS support for Mosquitto Description mosquitto provides SSL support for encrypted network connections and authentication. This manual describes how to create the files needed. It is important to use different certificate subject parameters for your CA, server and clients. If the certificates appear identical, even though generated separately, the broker/client will not be able to distinguish between them and you will experience difficult to diagnose errors. Certificate Authority Generate a certificate authority certificate and key. openssl req -new -x509 -days <duration> -extensions v3_ca -keyout ca.key -out ca.crt Server Generate a server key. openssl genrsa -des3 -out server.key 2048 Generate a server key without encryption. openssl genrsa -out server.key 2048 Generate a certificate signing request to send to the CA. openssl req -out server.csr -key server.key -new When prompted for the CN (Common Name), please enter either your server (or broker) hostname or domain name. Send the CSR to the CA, or sign it with your CA key: openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days <duration> Client Generate a client key. openssl genrsa -des3 -out client.key 2048 Generate a certificate signing request to send to the CA. openssl req -out client.csr -key client.key -new Send the CSR to the CA, or sign it with your CA key: openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days <duration> See Also mosquitto 8 mosquitto-conf 5 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/mosquitto.conf.50000664000175000017500000012773313245550210016531 0ustar rogerroger'\" t .\" Title: mosquitto.conf .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: File formats and conventions .\" Source: Mosquitto Project .\" Language: English .\" .TH "MOSQUITTO\&.CONF" "5" "02/28/2018" "Mosquitto Project" "File formats and conventions" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mosquitto.conf \- the configuration file for mosquitto .SH "SYNOPSIS" .HP \w'\fBmosquitto\&.conf\fR\ 'u \fBmosquitto\&.conf\fR .SH "DESCRIPTION" .PP \fBmosquitto\&.conf\fR is the configuration file for mosquitto\&. This file can reside anywhere as long as mosquitto can read it\&. By default, mosquitto does not need a configuration file and will use the default values listed below\&. See \fBmosquitto\fR(8) for information on how to load a configuration file\&. .SH "FILE FORMAT" .PP All lines with a # as the very first character are treated as a comment\&. .PP Configuration lines start with a variable name\&. The variable value is separated from the name by a single space\&. .SH "AUTHENTICATION" .PP The authentication options described below allow a wide range of possibilities in conjunction with the listener options\&. This section aims to clarify the possibilities\&. .PP The simplest option is to have no authentication at all\&. This is the default if no other options are given\&. Unauthenticated encrypted support is provided by using the certificate based SSL/TLS based options cafile/capath, certfile and keyfile\&. .PP MQTT provides username/password authentication as part of the protocol\&. Use the password_file option to define the valid usernames and passwords\&. Be sure to use network encryption if you are using this option otherwise the username and password will be vulnerable to interception\&. .PP When using certificate based encryption there are two options that affect authentication\&. The first is require_certificate, which may be set to true or false\&. If false, the SSL/TLS component of the client will verify the server but there is no requirement for the client to provide anything for the server: authentication is limited to the MQTT built in username/password\&. If require_certificate is true, the client must provide a valid certificate in order to connect successfully\&. In this case, the second option, use_identity_as_username, becomes relevant\&. If set to true, the Common Name (CN) from the client certificate is used instead of the MQTT username for access control purposes\&. The password is not replaced because it is assumed that only authenticated clients have valid certificates\&. If use_identity_as_username is false, the client must authenticate as normal (if required by password_file) through the MQTT options\&. .PP When using pre\-shared\-key based encryption through the psk_hint and psk_file options, the client must provide a valid identity and key in order to connect to the broker before any MQTT communication takes place\&. If use_identity_as_username is true, the PSK identity is used instead of the MQTT username for access control purposes\&. If use_identity_as_username is false, the client may still authenticate using the MQTT username/password if using the password_file option\&. .PP Both certificate and PSK based encryption are configured on a per\-listener basis\&. .PP Authentication plugins can be created to replace the password_file and psk_file options (as well as the ACL options) with e\&.g\&. SQL based lookups\&. .PP It is possible to support multiple authentication schemes at once\&. A config could be created that had a listener for all of the different encryption options described above and hence a large number of ways of authenticating\&. .SH "GENERAL OPTIONS" .PP \fBacl_file\fR \fIfile path\fR .RS 4 Set the path to an access control list file\&. If defined, the contents of the file are used to control client access to topics on the broker\&. .sp If this parameter is defined then only the topics listed will have access\&. Topic access is added with lines of the format: .sp topic [read|write|readwrite] .sp The access type is controlled using "read", "write" or "readwrite"\&. This parameter is optional (unless includes a space character) \- if not given then the access is read/write\&. can contain the + or # wildcards as in subscriptions\&. .sp The first set of topics are applied to anonymous clients, assuming \fBallow_anonymous\fR is true\&. User specific topic ACLs are added after a user line as follows: .sp user .sp The username referred to here is the same as in \fBpassword_file\fR\&. It is not the clientid\&. .sp It is also possible to define ACLs based on pattern substitution within the topic\&. The form is the same as for the topic keyword, but using pattern as the keyword\&. .sp pattern [read|write|readwrite] .sp The patterns available for substition are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %c to match the client id of the client .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} %u to match the username of the client .RE .sp The substitution pattern must be the only text for that level of hierarchy\&. Pattern ACLs apply to all users even if the "user" keyword has previously been given\&. .sp Example: .sp pattern write sensor/%u/data .sp Allow access for bridge connection messages: .sp pattern write $SYS/broker/connection/%c/state .sp If the first character of a line of the ACL file is a # it is treated as a comment\&. .sp Reloaded on reload signal\&. The currently loaded ACLs will be freed and reloaded\&. Existing subscriptions will be affected after the reload\&. .RE .PP \fBallow_anonymous\fR [ true | false ] .RS 4 Boolean value that determines whether clients that connect without providing a username are allowed to connect\&. If set to \fIfalse\fR then another means of connection should be created to control authenticated client access\&. Defaults to \fItrue\fR\&. .sp Reloaded on reload signal\&. .RE .PP \fBallow_duplicate_messages\fR [ true | false ] .RS 4 If a client is subscribed to multiple subscriptions that overlap, e\&.g\&. foo/# and foo/+/baz , then MQTT expects that when the broker receives a message on a topic that matches both subscriptions, such as foo/bar/baz, then the client should only receive the message once\&. .sp Mosquitto keeps track of which clients a message has been sent to in order to meet this requirement\&. This option allows this behaviour to be disabled, which may be useful if you have a large number of clients subscribed to the same set of topics and want to minimise memory usage\&. .sp It can be safely set to \fItrue\fR if you know in advance that your clients will never have overlapping subscriptions, otherwise your clients must be able to correctly deal with duplicate messages even when then have QoS=2\&. .sp Defaults to \fItrue\fR\&. .sp Reloaded on reload signal\&. .RE .PP \fBauth_opt_*\fR \fIvalue\fR .RS 4 Options to be passed to the auth plugin\&. See the specific plugin instructions\&. .RE .PP \fBauth_plugin\fR \fIfile path\fR .RS 4 Specify an external module to use for authentication and access control\&. This allows custom username/password and access control functions to be created\&. .sp Not currently reloaded on reload signal\&. .RE .PP \fBauth_plugin_deny_special_chars\fR [ true | false ] .RS 4 If \fItrue\fR then before an ACL check is made, the username/client id of the client needing the check is searched for the presence of either a \*(Aq+\*(Aq or \*(Aq#\*(Aq character\&. If either of these characters is found in either the username or client id, then the ACL check is denied before it is sent to the plugin\&. .sp This check prevents the case where a malicious user could circumvent an ACL check by using one of these characters as their username or client id\&. This is the same issue as was reported with mosquitto itself as CVE\-2017\-7650\&. .sp If you are entirely sure that the plugin you are using is not vulnerable to this attack (i\&.e\&. if you never use usernames or client ids in topics) then you can disable this extra check and hence have all ACL checks delivered to your plugin by setting this option to \fIfalse\fR\&. .sp Defaults to \fItrue\fR\&. .sp Not currently reloaded on reload signal\&. .RE .PP \fBautosave_interval\fR \fIseconds\fR .RS 4 The number of seconds that mosquitto will wait between each time it saves the in\-memory database to disk\&. If set to 0, the in\-memory database will only be saved when mosquitto exits or when receiving the SIGUSR1 signal\&. Note that this setting only has an effect if persistence is enabled\&. Defaults to 1800 seconds (30 minutes)\&. .sp Reloaded on reload signal\&. .RE .PP \fBautosave_on_changes\fR [ true | false ] .RS 4 If \fItrue\fR, mosquitto will count the number of subscription changes, retained messages received and queued messages and if the total exceeds \fBautosave_interval\fR then the in\-memory database will be saved to disk\&. If \fIfalse\fR, mosquitto will save the in\-memory database to disk by treating \fBautosave_interval\fR as a time in seconds\&. .sp Reloaded on reload signal\&. .RE .PP \fBclientid_prefixes\fR \fIprefix\fR .RS 4 If defined, only clients that have a clientid with a prefix that matches clientid_prefixes will be allowed to connect to the broker\&. For example, setting "secure\-" here would mean a client "secure\-client" could connect but another with clientid "mqtt" couldn\*(Aqt\&. By default, all client ids are valid\&. .sp Reloaded on reload signal\&. Note that currently connected clients will be unaffected by any changes\&. .RE .PP \fBconnection_messages\fR [ true | false ] .RS 4 If set to \fItrue\fR, the log will include entries when clients connect and disconnect\&. If set to \fIfalse\fR, these entries will not appear\&. .sp Reloaded on reload signal\&. .RE .PP \fBinclude_dir\fR \fIdir\fR .RS 4 External configuration files may be included by using the include_dir option\&. This defines a directory that will be searched for config files\&. All files that end in \*(Aq\&.conf\*(Aq will be loaded as a configuration file\&. It is best to have this as the last option in the main file\&. This option will only be processed from the main configuration file\&. The directory specified must not contain the main configuration file\&. .RE .PP \fBlog_dest\fR \fIdestinations\fR .RS 4 Send log messages to a particular destination\&. Possible destinations are: \fBstdout\fR \fBstderr\fR \fBsyslog\fR \fBtopic\fR\&. .sp \fBstdout\fR and \fBstderr\fR log to the console on the named output\&. .sp \fBsyslog\fR uses the userspace syslog facility which usually ends up in /var/log/messages or similar and topic logs to the broker topic \*(Aq$SYS/broker/log/\*(Aq, where severity is one of D, E, W, N, I, M which are debug, error, warning, notice, information and message\&. Message type severity is used by the subscribe and unsubscribe log_type options and publishes log messages at $SYS/broker/log/M/subscribe and $SYS/broker/log/M/unsubscribe\&. .sp The \fBfile\fR destination requires an additional parameter which is the file to be logged to, e\&.g\&. "log_dest file /var/log/mosquitto\&.log"\&. The file will be closed and reopened when the broker receives a HUP signal\&. Only a single file destination may be configured\&. .sp Use "log_dest none" if you wish to disable logging\&. Defaults to stderr\&. This option may be specified multiple times\&. .sp Note that if the broker is running as a Windows service it will default to "log_dest none" and neither stdout nor stderr logging is available\&. .sp Reloaded on reload signal\&. .RE .PP \fBlog_facility\fR \fIlocal facility\fR .RS 4 If using syslog logging (not on Windows), messages will be logged to the "daemon" facility by default\&. Use the \fBlog_facility\fR option to choose which of local0 to local7 to log to instead\&. The option value should be an integer value, e\&.g\&. "log_facility 5" to use local5\&. .RE .PP \fBlog_timestamp\fR [ true | false ] .RS 4 Boolean value, if set to \fItrue\fR a timestamp value will be added to each log entry\&. The default is \fItrue\fR\&. .sp Reloaded on reload signal\&. .RE .PP \fBlog_type\fR \fItypes\fR .RS 4 Choose types of messages to log\&. Possible types are: \fIdebug\fR, \fIerror\fR, \fIwarning\fR, \fInotice\fR, \fIinformation\fR, \fIsubscribe\fR, \fIunsubscribe\fR, \fIwebsockets\fR, \fInone\fR, \fIall\fR\&. .sp Defaults to \fIerror\fR, \fIwarning\fR, \fInotice \fRand \fIinformation\fR\&. This option may be specified multiple times\&. Note that the \fIdebug \fRtype (used for decoding incoming/outgoing network packets) is never logged in topics\&. .sp Reloaded on reload signal\&. .RE .PP \fBmax_inflight_messages\fR \fIcount\fR .RS 4 The maximum number of QoS 1 or 2 messages that can be in the process of being transmitted simultaneously\&. This includes messages currently going through handshakes and messages that are being retried\&. Defaults to 20\&. Set to 0 for no maximum\&. If set to 1, this will guarantee in\-order delivery of messages\&. .sp Reloaded on reload signal\&. .RE .PP \fBmax_queued_messages\fR \fIcount\fR .RS 4 The maximum number of QoS 1 or 2 messages to hold in the queue above those messages that are currently in flight\&. Defaults to 100\&. Set to 0 for no maximum (not recommended)\&. See also the \fBqueue_qos0_messages\fR option\&. .sp Reloaded on reload signal\&. .RE .PP \fBmessage_size_limit\fR \fIlimit\fR .RS 4 This option sets the maximum publish payload size that the broker will allow\&. Received messages that exceed this size will not be accepted by the broker\&. The default value is 0, which means that all valid MQTT messages are accepted\&. MQTT imposes a maximum payload size of 268435455 bytes\&. .RE .PP \fBpassword_file\fR \fIfile path\fR .RS 4 Set the path to a password file\&. If defined, the contents of the file are used to control client access to the broker\&. The file can be created using the \fBmosquitto_passwd\fR(1) utility\&. If mosquitto is compiled without TLS support (it is recommended that TLS support is included), then the password file should be a text file with each line in the format "username:password", where the colon and password are optional but recommended\&. If \fBallow_anonymous\fR is set to \fIfalse\fR, only users defined in this file will be able to connect\&. Setting \fBallow_anonymous\fR to \fItrue\fR when \fIpassword_file\fRis defined is valid and could be used with acl_file to have e\&.g\&. read only guest/anonymous accounts and defined users that can publish\&. .sp Reloaded on reload signal\&. The currently loaded username and password data will be freed and reloaded\&. Clients that are already connected will not be affected\&. .sp See also \fBmosquitto_passwd\fR(1)\&. .RE .PP \fBpersistence\fR [ true | false ] .RS 4 If \fItrue\fR, connection, subscription and message data will be written to the disk in mosquitto\&.db at the location dictated by persistence_location\&. When mosquitto is restarted, it will reload the information stored in mosquitto\&.db\&. The data will be written to disk when mosquitto closes and also at periodic intervals as defined by autosave_interval\&. Writing of the persistence database may also be forced by sending mosquitto the SIGUSR1 signal\&. If \fIfalse\fR, the data will be stored in memory only\&. Defaults to \fIfalse\fR\&. .sp Reloaded on reload signal\&. .RE .PP \fBpersistence_file\fR \fIfile name\fR .RS 4 The filename to use for the persistent database\&. Defaults to mosquitto\&.db\&. .sp Reloaded on reload signal\&. .RE .PP \fBpersistence_location\fR \fIpath\fR .RS 4 The path where the persistence database should be stored\&. Must end in a trailing slash\&. If not given, then the current directory is used\&. .sp Reloaded on reload signal\&. .RE .PP \fBpersistent_client_expiration\fR \fIduration\fR .RS 4 This option allows persistent clients (those with clean session set to false) to be removed if they do not reconnect within a certain time frame\&. This is a non\-standard option\&. As far as the MQTT spec is concerned, persistent clients persist forever\&. .sp Badly designed clients may set clean session to false whilst using a randomly generated client id\&. This leads to persistent clients that will never reconnect\&. This option allows these clients to be removed\&. .sp The expiration period should be an integer followed by one of h d w m y for hour, day, week, month and year respectively\&. For example: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} persistent_client_expiration 2m .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} persistent_client_expiration 14d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} persistent_client_expiration 1y .RE .sp As this is a non\-standard option, the default if not set is to never expire persistent clients\&. .sp Reloaded on reload signal\&. .RE .PP \fBpid_file\fR \fIfile path\fR .RS 4 Write a pid file to the file specified\&. If not given (the default), no pid file will be written\&. If the pid file cannot be written, mosquitto will exit\&. This option only has an effect is mosquitto is run in daemon mode\&. .sp If mosquitto is being automatically started by an init script it will usually be required to write a pid file\&. This should then be configured as e\&.g\&. /var/run/mosquitto\&.pid .sp Not reloaded on reload signal\&. .RE .PP \fBpsk_file\fR \fIfile path\fR .RS 4 Set the path to a pre\-shared\-key file\&. This option requires a listener to be have PSK support enabled\&. If defined, the contents of the file are used to control client access to the broker\&. Each line should be in the format "identity:key", where the key is a hexadecimal string with no leading "0x"\&. A client connecting to a listener that has PSK support enabled must provide a matching identity and PSK to allow the encrypted connection to proceed\&. .sp Reloaded on reload signal\&. The currently loaded identity and key data will be freed and reloaded\&. Clients that are already connected will not be affected\&. .RE .PP \fBqueue_qos0_messages\fR [ true | false ] .RS 4 Set to \fItrue\fR to queue messages with QoS 0 when a persistent client is disconnected\&. These messages are included in the limit imposed by max_queued_messages\&. Defaults to \fIfalse\fR\&. .sp Note that the MQTT v3\&.1 spec states that only QoS 1 and 2 messages should be saved in this situation so this is a non\-standard option\&. .sp Reloaded on reload signal\&. .RE .PP \fBretained_persistence\fR [ true | false ] .RS 4 This is a synonym of the \fBpersistence\fR option\&. .sp Reloaded on reload signal\&. .RE .PP \fBretry_interval\fR \fIseconds\fR .RS 4 The integer number of seconds after a QoS=1 or QoS=2 message has been sent that mosquitto will wait before retrying when no response is received\&. If unset, defaults to 20 seconds\&. .sp Reloaded on reload signal\&. .RE .PP \fBstore_clean_interval\fR \fIseconds\fR .RS 4 The integer number of seconds between the internal message store being cleaned of messages that are no longer referenced\&. Lower values will result in lower memory usage but more processor time, higher values will have the opposite effect\&. Setting a value of 0 means the unreferenced messages will be disposed of as quickly as possible\&. Defaults to 10 seconds\&. .sp Reloaded on reload signal\&. .RE .PP \fBsys_interval\fR \fIseconds\fR .RS 4 The integer number of seconds between updates of the $SYS subscription hierarchy, which provides status information about the broker\&. If unset, defaults to 10 seconds\&. .sp Set to 0 to disable publishing the $SYS hierarchy completely\&. .sp Reloaded on reload signal\&. .RE .PP \fBupgrade_outgoing_qos\fR [ true | false ] .RS 4 The MQTT specification requires that the QoS of a message delivered to a subscriber is never upgraded to match the QoS of the subscription\&. Enabling this option changes this behaviour\&. If \fBupgrade_outgoing_qos\fR is set \fItrue\fR, messages sent to a subscriber will always match the QoS of its subscription\&. This is a non\-standard option not provided for by the spec\&. Defaults to \fIfalse\fR\&. .sp Reloaded on reload signal\&. .RE .PP \fBuser\fR \fIusername\fR .RS 4 When run as root, change to this user and its primary group on startup\&. If mosquitto is unable to change to this user and group, it will exit with an error\&. The user specified must have read/write access to the persistence database if it is to be written\&. If run as a non\-root user, this setting has no effect\&. Defaults to mosquitto\&. .sp This setting has no effect on Windows and so you should run mosquitto as the user you wish it to run as\&. .sp Not reloaded on reload signal\&. .RE .SH "LISTENERS" .PP The network ports that mosquitto listens on can be controlled using listeners\&. The default listener options can be overridden and further listeners can be created\&. .SS "General Options" .PP \fBbind_address\fR \fIaddress\fR .RS 4 Listen for incoming network connections on the specified IP address/hostname only\&. This is useful to restrict access to certain network interfaces\&. To restrict access to mosquitto to the local host only, use "bind_address localhost"\&. This only applies to the default listener\&. Use the listener variable to control other listeners\&. .sp Not reloaded on reload signal\&. .RE .PP \fBhttp_dir\fR \fIdirectory\fR .RS 4 When a listener is using the websockets protocol, it is possible to serve http data as well\&. Set \fBhttp_dir\fR to a directory which contains the files you wish to serve\&. If this option is not specified, then no normal http connections will be possible\&. .sp Not reloaded on reload signal\&. .RE .PP \fBlistener\fR \fIport\fR \fI[bind address/host]\fR .RS 4 Listen for incoming network connection on the specified port\&. A second optional argument allows the listener to be bound to a specific ip address/hostname\&. If this variable is used and neither the global \fBbind_address\fR nor \fBport\fR options are used then the default listener will not be started\&. .sp The \fBbind address/host\fR option allows this listener to be bound to a specific IP address by passing an IP address or hostname\&. For websockets listeners, it is only possible to pass an IP address here\&. .sp This option may be specified multiple times\&. See also the \fBmount_point\fR option\&. .sp Not reloaded on reload signal\&. .RE .PP \fBmax_connections\fR \fIcount\fR .RS 4 Limit the total number of clients connected for the current listener\&. Set to \-1 to have "unlimited" connections\&. Note that other limits may be imposed that are outside the control of mosquitto\&. See e\&.g\&. \fBlimits.conf\fR(5)\&. .sp Not reloaded on reload signal\&. .RE .PP \fBmount_point\fR \fItopic prefix\fR .RS 4 This option is used with the listener option to isolate groups of clients\&. When a client connects to a listener which uses this option, the string argument is attached to the start of all topics for this client\&. This prefix is removed when any messages are sent to the client\&. This means a client connected to a listener with mount point \fIexample\fR can only see messages that are published in the topic hierarchy \fIexample\fR and above\&. .sp Not reloaded on reload signal\&. .RE .PP \fBport\fR \fIport number\fR .RS 4 Set the network port for the default listener to listen on\&. Defaults to 1883\&. .sp Not reloaded on reload signal\&. .RE .PP \fBprotocol\fR \fIvalue\fR .RS 4 Set the protocol to accept for this listener\&. Can be \fBmqtt\fR, the default, or \fBwebsockets\fR if available\&. .sp Websockets support is currently disabled by default at compile time\&. Certificate based TLS may be used with websockets, except that only the \fBcafile\fR, \fBcertfile\fR, \fBkeyfile\fR and \fBciphers\fR options are supported\&. .sp Not reloaded on reload signal\&. .RE .PP \fBuse_username_as_clientid\fR [ true | false ] .RS 4 Set \fBuse_username_as_clientid\fR to true to replace the clientid that a client connected with with its username\&. This allows authentication to be tied to the clientid, which means that it is possible to prevent one client disconnecting another by using the same clientid\&. Defaults to false\&. .sp If a client connects with no username it will be disconnected as not authorised when this option is set to true\&. Do not use in conjunction with \fBclientid_prefixes\fR\&. .sp See also \fBuse_identity_as_username\fR\&. .sp Not reloaded on reload signal\&. .RE .PP \fBwebsockets_log_level\fR \fIlevel\fR .RS 4 Change the websockets logging level\&. This is a global option, it is not possible to set per listener\&. This is an integer that is interpreted by libwebsockets as a bit mask for its lws_log_levels enum\&. See the libwebsockets documentation for more details\&. .sp To use this option, \fBlog_type websockets\fR must also be enabled\&. Defaults to 0\&. .RE .SS "Certificate based SSL/TLS Support" .PP The following options are available for all listeners to configure certificate based SSL support\&. See also "Pre\-shared\-key based SSL/TLS support"\&. .PP \fBcafile\fR \fIfile path\fR .RS 4 At least one of \fBcafile\fR or \fBcapath\fR must be provided to allow SSL support\&. .sp \fBcafile\fR is used to define the path to a file containing the PEM encoded CA certificates that are trusted\&. .RE .PP \fBcapath\fR \fIdirectory path\fR .RS 4 At least one of \fBcafile\fR or \fBcapath\fR must be provided to allow SSL support\&. .sp \fBcapath\fR is used to define a directory that contains PEM encoded CA certificates that are trusted\&. For \fBcapath\fR to work correctly, the certificates files must have "\&.pem" as the file ending and you must run "c_rehash " each time you add/remove a certificate\&. .RE .PP \fBcertfile\fR \fIfile path\fR .RS 4 Path to the PEM encoded server certificate\&. .RE .PP \fBciphers\fR \fIcipher:list\fR .RS 4 The list of allowed ciphers, each separated with a colon\&. Available ciphers can be obtained using the "openssl ciphers" command\&. .RE .PP \fBcrlfile\fR \fIfile path\fR .RS 4 If you have \fBrequire_certificate\fR set to \fItrue\fR, you can create a certificate revocation list file to revoke access to particular client certificates\&. If you have done this, use crlfile to point to the PEM encoded revocation file\&. .RE .PP \fBkeyfile\fR \fIfile path\fR .RS 4 Path to the PEM encoded keyfile\&. .RE .PP \fBrequire_certificate\fR [ true | false ] .RS 4 By default an SSL/TLS enabled listener will operate in a similar fashion to a https enabled web server, in that the server has a certificate signed by a CA and the client will verify that it is a trusted certificate\&. The overall aim is encryption of the network traffic\&. By setting \fBrequire_certificate\fR to \fItrue\fR, the client must provide a valid certificate in order for the network connection to proceed\&. This allows access to the broker to be controlled outside of the mechanisms provided by MQTT\&. .RE .PP \fBtls_version\fR \fIversion\fR .RS 4 Configure the version of the TLS protocol to be used for this listener\&. Possible values are \fItlsv1\&.2\fR, \fItlsv1\&.1\fR and \fItlsv1\fR\&. If left unset, the default of allowing all of TLS v1\&.2, v1\&.1 and v1\&.0 is used\&. .RE .PP \fBuse_identity_as_username\fR [ true | false ] .RS 4 If \fBrequire_certificate\fR is \fItrue\fR, you may set \fBuse_identity_as_username\fR to \fItrue\fR to use the CN value from the client certificate as a username\&. If this is \fItrue\fR, the \fBpassword_file\fR option will not be used for this listener\&. .RE .SS "Pre\-shared\-key based SSL/TLS Support" .PP The following options are available for all listeners to configure pre\-shared\-key based SSL support\&. See also "Certificate based SSL/TLS support"\&. .PP \fBciphers\fR \fIcipher:list\fR .RS 4 When using PSK, the encryption ciphers used will be chosen from the list of available PSK ciphers\&. If you want to control which ciphers are available, use this option\&. The list of available ciphers can be optained using the "openssl ciphers" command and should be provided in the same format as the output of that command\&. .RE .PP \fBpsk_hint\fR \fIhint\fR .RS 4 The \fBpsk_hint\fR option enables pre\-shared\-key support for this listener and also acts as an identifier for this listener\&. The hint is sent to clients and may be used locally to aid authentication\&. The hint is a free form string that doesn\*(Aqt have much meaning in itself, so feel free to be creative\&. .sp If this option is provided, see \fBpsk_file\fR to define the pre\-shared keys to be used or create a security plugin to handle them\&. .RE .PP \fBtls_version\fR \fIversion\fR .RS 4 Configure the version of the TLS protocol to be used for this listener\&. Possible values are \fItlsv1\&.2\fR, \fItlsv1\&.1\fR and \fItlsv1\fR\&. If left unset, the default of allowing all of TLS v1\&.2, v1\&.1 and v1\&.0 is used\&. .RE .PP \fBuse_identity_as_username\fR [ true | false ] .RS 4 Set \fBuse_identity_as_username\fR to have the psk identity sent by the client used as its username\&. The username will be checked as normal, so \fBpassword_file\fR or another means of authentication checking must be used\&. No password will be used\&. .RE .SH "CONFIGURING BRIDGES" .PP Multiple bridges (connections to other brokers) can be configured using the following variables\&. .PP Bridges cannot currently be reloaded on reload signal\&. .PP \fBaddress\fR \fIaddress[:port]\fR \fI[address[:port]]\fR, \fBaddresses\fR \fIaddress[:port]\fR \fI[address[:port]]\fR .RS 4 Specify the address and optionally the port of the bridge to connect to\&. This must be given for each bridge connection\&. If the port is not specified, the default of 1883 is used\&. .sp Multiple host addresses can be specified on the address config\&. See the \fBround_robin\fR option for more details on the behaviour of bridges with multiple addresses\&. .RE .PP \fBbridge_attempt_unsubscribe\fR [ true | false ] .RS 4 If a bridge has topics that have "out" direction, the default behaviour is to send an unsubscribe request to the remote broker on that topic\&. This means that changing a topic direction from "in" to "out" will not keep receiving incoming messages\&. Sending these unsubscribe requests is not always desirable, setting \fBbridge_attempt_unsubscribe\fR to \fIfalse\fR will disable sending the unsubscribe request\&. Defaults to \fItrue\fR\&. .RE .PP \fBbridge_protocol_version\fR \fIversion\fR .RS 4 Set the version of the MQTT protocol to use with for this bridge\&. Can be one of \fImqttv31\fR or \fImqttv311\fR\&. Defaults to \fImqttv31\fR\&. .RE .PP \fBcleansession\fR [ true | false ] .RS 4 Set the clean session option for this bridge\&. Setting to \fIfalse\fR (the default), means that all subscriptions on the remote broker are kept in case of the network connection dropping\&. If set to \fItrue\fR, all subscriptions and messages on the remote broker will be cleaned up if the connection drops\&. Note that setting to \fItrue\fR may cause a large amount of retained messages to be sent each time the bridge reconnects\&. .sp If you are using bridges with \fBcleansession\fR set to \fIfalse\fR (the default), then you may get unexpected behaviour from incoming topics if you change what topics you are subscribing to\&. This is because the remote broker keeps the subscription for the old topic\&. If you have this problem, connect your bridge with \fBcleansession\fR set to \fItrue\fR, then reconnect with cleansession set to \fIfalse\fR as normal\&. .RE .PP \fBconnection\fR \fIname\fR .RS 4 This variable marks the start of a new bridge connection\&. It is also used to give the bridge a name which is used as the client id on the remote broker\&. .RE .PP \fBkeepalive_interval\fR \fIseconds\fR .RS 4 Set the number of seconds after which the bridge should send a ping if no other traffic has occurred\&. Defaults to 60\&. A minimum value of 5 seconds is allowed\&. .RE .PP \fBidle_timeout\fR \fIseconds\fR .RS 4 Set the amount of time a bridge using the lazy start type must be idle before it will be stopped\&. Defaults to 60 seconds\&. .RE .PP \fBlocal_clientid\fR \fIid\fR .RS 4 Set the clientid to use on the local broker\&. If not defined, this defaults to \fBlocal\&.\fR\&. If you are bridging a broker to itself, it is important that local_clientid and remote_clientid do not match\&. .RE .PP \fBlocal_password\fR \fIpassword\fR .RS 4 Configure the password to be used when connecting this bridge to the local broker\&. This may be important when authentication and ACLs are being used\&. .RE .PP \fBlocal_username\fR \fIusername\fR .RS 4 Configure the username to be used when connecting this bridge to the local broker\&. This may be important when authentication and ACLs are being used\&. .RE .PP \fBnotifications\fR [ true | false ] .RS 4 If set to \fItrue\fR, publish notification messages to the local and remote brokers giving information about the state of the bridge connection\&. Retained messages are published to the topic $SYS/broker/connection//state unless otherwise set with \fBnotification_topic\fRs\&. If the message is 1 then the connection is active, or 0 if the connection has failed\&. Defaults to \fItrue\fR\&. .RE .PP \fBnotification_topic\fR \fItopic\fR .RS 4 Choose the topic on which notifications will be published for this bridge\&. If not set the messages will be sent on the topic $SYS/broker/connection//state\&. .RE .PP \fBremote_clientid\fR \fIid\fR .RS 4 Set the client id for this bridge connection\&. If not defined, this defaults to \*(Aqname\&.hostname\*(Aq, where name is the connection name and hostname is the hostname of this computer\&. .sp This replaces the old "clientid" option to avoid confusion with local/remote sides of the bridge\&. "clientid" remains valid for the time being\&. .RE .PP \fBremote_password\fR \fIvalue\fR .RS 4 Configure a password for the bridge\&. This is used for authentication purposes when connecting to a broker that supports MQTT v3\&.1 and up and requires a username and/or password to connect\&. This option is only valid if a remote_username is also supplied\&. .sp This replaces the old "password" option to avoid confusion with local/remote sides of the bridge\&. "password" remains valid for the time being\&. .RE .PP \fBremote_username\fR \fIname\fR .RS 4 Configure a username for the bridge\&. This is used for authentication purposes when connecting to a broker that supports MQTT v3\&.1 and up and requires a username and/or password to connect\&. See also the \fBremote_password\fR option\&. .sp This replaces the old "username" option to avoid confusion with local/remote sides of the bridge\&. "username" remains valid for the time being\&. .RE .PP \fBrestart_timeout\fR \fIvalue\fR .RS 4 Set the amount of time a bridge using the automatic start type will wait until attempting to reconnect\&. Defaults to 30 seconds\&. .RE .PP \fBround_robin\fR [ true | false ] .RS 4 If the bridge has more than one address given in the address/addresses configuration, the round_robin option defines the behaviour of the bridge on a failure of the bridge connection\&. If round_robin is \fIfalse\fR, the default value, then the first address is treated as the main bridge connection\&. If the connection fails, the other secondary addresses will be attempted in turn\&. Whilst connected to a secondary bridge, the bridge will periodically attempt to reconnect to the main bridge until successful\&. .sp If round_robin is \fItrue\fR, then all addresses are treated as equals\&. If a connection fails, the next address will be tried and if successful will remain connected until it fails\&. .RE .PP \fBstart_type\fR [ automatic | lazy | once ] .RS 4 Set the start type of the bridge\&. This controls how the bridge starts and can be one of three types: \fIautomatic\fR, \fIlazy \fRand \fIonce\fR\&. Note that RSMB provides a fourth start type "manual" which isn\*(Aqt currently supported by mosquitto\&. .sp \fIautomatic\fR is the default start type and means that the bridge connection will be started automatically when the broker starts and also restarted after a short delay (30 seconds) if the connection fails\&. .sp Bridges using the \fIlazy\fR start type will be started automatically when the number of queued messages exceeds the number set with the \fBthreshold\fR option\&. It will be stopped automatically after the time set by the \fBidle_timeout\fR parameter\&. Use this start type if you wish the connection to only be active when it is needed\&. .sp A bridge using the \fIonce\fR start type will be started automatically when the broker starts but will not be restarted if the connection fails\&. .RE .PP \fBthreshold\fR \fIcount\fR .RS 4 Set the number of messages that need to be queued for a bridge with lazy start type to be restarted\&. Defaults to 10 messages\&. .RE .PP \fBtopic\fR \fIpattern\fR [[[ out | in | both ] qos\-level] local\-prefix remote\-prefix] .RS 4 Define a topic pattern to be shared between the two brokers\&. Any topics matching the pattern (which may include wildcards) are shared\&. The second parameter defines the direction that the messages will be shared in, so it is possible to import messages from a remote broker using \fIin\fR, export messages to a remote broker using \fIout\fR or share messages in both directions\&. If this parameter is not defined, the default of \fIout\fR is used\&. The QoS level defines the publish/subscribe QoS level used for this topic and defaults to 0\&. .sp The \fIlocal\-prefix\fR and \fIremote\-prefix\fR options allow topics to be remapped when publishing to and receiving from remote brokers\&. This allows a topic tree from the local broker to be inserted into the topic tree of the remote broker at an appropriate place\&. .sp For incoming topics, the bridge will prepend the pattern with the remote prefix and subscribe to the resulting topic on the remote broker\&. When a matching incoming message is received, the remote prefix will be removed from the topic and then the local prefix added\&. .sp For outgoing topics, the bridge will prepend the pattern with the local prefix and subscribe to the resulting topic on the local broker\&. When an outgoing message is processed, the local prefix will be removed from the topic then the remote prefix added\&. .sp When using topic mapping, an empty prefix can be defined using the place marker \fI""\fR\&. Using the empty marker for the topic itself is also valid\&. The table below defines what combination of empty or value is valid\&. .TS allbox tab(:); lB lB lB lB lB. T{ \ \& T}:T{ \fITopic\fR T}:T{ \fILocal Prefix\fR T}:T{ \fIRemote Prefix\fR T}:T{ \fIValidity\fR T} .T& l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l. T{ 1 T}:T{ value T}:T{ value T}:T{ value T}:T{ valid T} T{ 2 T}:T{ value T}:T{ value T}:T{ "" T}:T{ valid T} T{ 3 T}:T{ value T}:T{ "" T}:T{ value T}:T{ valid T} T{ 4 T}:T{ value T}:T{ "" T}:T{ "" T}:T{ valid (no remapping) T} T{ 5 T}:T{ "" T}:T{ value T}:T{ value T}:T{ valid (remap single local topic to remote) T} T{ 6 T}:T{ "" T}:T{ value T}:T{ "" T}:T{ invalid T} T{ 7 T}:T{ "" T}:T{ "" T}:T{ value T}:T{ invalid T} T{ 8 T}:T{ "" T}:T{ "" T}:T{ "" T}:T{ invalid T} .TE .sp 1 To remap an entire topic tree, use e\&.g\&.: .sp .if n \{\ .RS 4 .\} .nf topic # both 2 local/topic/ remote/topic/ .fi .if n \{\ .RE .\} .sp This option can be specified multiple times per bridge\&. .sp Care must be taken to ensure that loops are not created with this option\&. If you are experiencing high CPU load from a broker, it is possible that you have a loop where each broker is forever forwarding each other the same messages\&. .sp See also the \fBcleansession\fR option if you have messages arriving on unexpected topics when using incoming topics\&. .PP \fBExample\ \&Bridge Topic Remapping.\ \&\fR The configuration below connects a bridge to the broker at \fBtest\&.mosquitto\&.org\fR\&. It subscribes to the remote topic \fB$SYS/broker/clients/total\fR and republishes the messages received to the local topic \fBtest/mosquitto/org/clients/total\fR .sp .if n \{\ .RS 4 .\} .nf connection test\-mosquitto\-org address test\&.mosquitto\&.org cleansession true topic clients/total in 0 test/mosquitto/org $SYS/broker/ .fi .if n \{\ .RE .\} .RE .PP \fBtry_private\fR [ true | false ] .RS 4 If try_private is set to \fItrue\fR, the bridge will attempt to indicate to the remote broker that it is a bridge not an ordinary client\&. If successful, this means that loop detection will be more effective and that retained messages will be propagated correctly\&. Not all brokers support this feature so it may be necessary to set \fBtry_private\fR to \fIfalse\fR if your bridge does not connect properly\&. .sp Defaults to \fItrue\fR\&. .RE .SS "SSL/TLS Support" .PP The following options are available for all bridges to configure SSL/TLS support\&. .PP \fBbridge_cafile\fR \fIfile path\fR .RS 4 One of \fBbridge_cafile\fR or \fBbridge_capath\fR must be provided to allow SSL/TLS support\&. .sp bridge_cafile is used to define the path to a file containing the PEM encoded CA certificates that have signed the certificate for the remote broker\&. .RE .PP \fBbridge_capath\fR \fIfile path\fR .RS 4 One of \fBbridge_capath\fR or \fBbridge_capath\fR must be provided to allow SSL/TLS support\&. .sp bridge_capath is used to define the path to a directory containing the PEM encoded CA certificates that have signed the certificate for the remote broker\&. For bridge_capath to work correctly, the certificate files must have "\&.crt" as the file ending and you must run "c_rehash " each time you add/remove a certificate\&. .RE .PP \fBbridge_certfile\fR \fIfile path\fR .RS 4 Path to the PEM encoded client certificate for this bridge, if required by the remote broker\&. .RE .PP \fBbridge_identity\fR \fIidentity\fR .RS 4 Pre\-shared\-key encryption provides an alternative to certificate based encryption\&. A bridge can be configured to use PSK with the \fBbridge_identity\fR and \fBbridge_psk\fR options\&. This is the client identity used with PSK encryption\&. Only one of certificate and PSK based encryption can be used on one bridge at once\&. .RE .PP \fBbridge_insecure\fR [ true | false ] .RS 4 When using certificate based TLS, the bridge will attempt to verify the hostname provided in the remote certificate matches the host/address being connected to\&. This may cause problems in testing scenarios, so \fBbridge_insecure\fR may be set to \fIfalse\fR to disable the hostname verification\&. .sp Setting this option to \fItrue\fR means that a malicious third party could potentially inpersonate your server, so it should always be set to \fIfalse\fR in production environments\&. .RE .PP \fBbridge_keyfile\fR \fIfile path\fR .RS 4 Path to the PEM encoded private key for this bridge, if required by the remote broker\&. .RE .PP \fBbridge_psk\fR \fIkey\fR .RS 4 Pre\-shared\-key encryption provides an alternative to certificate based encryption\&. A bridge can be configured to use PSK with the \fBbridge_identity\fR and \fBbridge_psk\fR options\&. This is the pre\-shared\-key in hexadecimal format with no "0x"\&. Only one of certificate and PSK based encryption can be used on one bridge at once\&. .RE .PP \fBbridge_tls_version\fR \fIversion\fR .RS 4 Configure the version of the TLS protocol to be used for this bridge\&. Possible values are \fItlsv1\&.2\fR, \fItlsv1\&.1\fR and \fItlsv1\fR\&. Defaults to \fItlsv1\&.2\fR\&. The remote broker must support the same version of TLS for the connection to succeed\&. .RE .SH "FILES" .PP mosquitto\&.conf .SH "BUGS" .PP \fBmosquitto\fR bug information can be found at \m[blue]\fB\%https://github.com/eclipse/mosquitto/issues\fR\m[] .SH "SEE ALSO" \fBmosquitto\fR(8), \fBmosquitto_passwd\fR(1), \fBmosquitto-tls\fR(7), \fBmqtt\fR(7), \fBlimits.conf\fR(5) .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/man/CMakeLists.txt0000664000175000017500000000051013245550210016172 0ustar rogerrogerinstall(FILES mosquitto_passwd.1 mosquitto_pub.1 mosquitto_sub.1 DESTINATION ${MANDIR}/man1) install(FILES libmosquitto.3 DESTINATION ${MANDIR}/man3) install(FILES mosquitto.conf.5 DESTINATION ${MANDIR}/man5) install(FILES mosquitto-tls.7 mqtt.7 DESTINATION ${MANDIR}/man7) install(FILES mosquitto.8 DESTINATION ${MANDIR}/man8) mosquitto-1.4.15/man/Makefile0000664000175000017500000000563313245550210015105 0ustar rogerrogerinclude ../config.mk .PHONY : all clean install uninstall dist all : mosquitto.8 mosquitto-tls.7 mosquitto.conf.5 mosquitto_passwd.1 mosquitto_pub.1 mosquitto_sub.1 mqtt.7 libmosquitto.3 clean : reallyclean : clean -rm -f *.orig -rm -f libmosquitto.3 -rm -f mosquitto.8 -rm -f mosquitto.conf.5 -rm -f mosquitto_passwd.1 -rm -f mosquitto_pub.1 -rm -f mosquitto_sub.1 -rm -f mosquitto-tls.7 -rm -f mqtt.7 dist : mosquitto.8 mosquitto-tls.7 mosquitto.conf.5 mosquitto_passwd.1 mosquitto_pub.1 mosquitto_sub.1 mqtt.7 libmosquitto.3 install : $(INSTALL) -d ${DESTDIR}$(mandir)/man8 $(INSTALL) -m 644 mosquitto.8 ${DESTDIR}${mandir}/man8/mosquitto.8 $(INSTALL) -d ${DESTDIR}$(mandir)/man5 $(INSTALL) -m 644 mosquitto.conf.5 ${DESTDIR}${mandir}/man5/mosquitto.conf.5 $(INSTALL) -d ${DESTDIR}$(mandir)/man1 $(INSTALL) -m 644 mosquitto_passwd.1 ${DESTDIR}${mandir}/man1/mosquitto_passwd.1 $(INSTALL) -m 644 mosquitto_pub.1 ${DESTDIR}${mandir}/man1/mosquitto_pub.1 $(INSTALL) -m 644 mosquitto_sub.1 ${DESTDIR}${mandir}/man1/mosquitto_sub.1 $(INSTALL) -d ${DESTDIR}$(mandir)/man7 $(INSTALL) -m 644 mqtt.7 ${DESTDIR}${mandir}/man7/mqtt.7 $(INSTALL) -m 644 mosquitto-tls.7 ${DESTDIR}${mandir}/man7/mosquitto-tls.7 $(INSTALL) -d ${DESTDIR}$(mandir)/man3 $(INSTALL) -m 644 libmosquitto.3 ${DESTDIR}${mandir}/man3/libmosquitto.3 uninstall : -rm -f ${DESTDIR}${mandir}/man8/mosquitto.8 -rm -f ${DESTDIR}${mandir}/man5/mosquitto.conf.5 -rm -f ${DESTDIR}${mandir}/man1/mosquitto_passwd.1 -rm -f ${DESTDIR}${mandir}/man1/mosquitto_pub.1 -rm -f ${DESTDIR}${mandir}/man1/mosquitto_sub.1 -rm -f ${DESTDIR}${mandir}/man7/mqtt.7 -rm -f ${DESTDIR}${mandir}/man7/mosquitto-tls.7 -rm -f ${DESTDIR}${mandir}/man3/libmosquitto.3 mosquitto.8 : mosquitto.8.xml $(XSLTPROC) $^ mosquitto.conf.5 : mosquitto.conf.5.xml manpage.xsl $(XSLTPROC) $< mosquitto_passwd.1 : mosquitto_passwd.1.xml $(XSLTPROC) $^ mosquitto_pub.1 : mosquitto_pub.1.xml $(XSLTPROC) $^ mosquitto_sub.1 : mosquitto_sub.1.xml $(XSLTPROC) $^ mqtt.7 : mqtt.7.xml $(XSLTPROC) $^ mosquitto-tls.7 : mosquitto-tls.7.xml $(XSLTPROC) $^ libmosquitto.3 : libmosquitto.3.xml $(XSLTPROC) $^ html : *.xml set -e; for m in *.xml; \ do \ hfile=$$(echo $${m} | sed -e 's#\(.*\)\.xml#\1#' | sed -e 's/\./-/g'); \ $(XSLTPROC) html.xsl $${m} > $${hfile}.html; \ done potgen : xml2po -o po/mosquitto/mosquitto.8.pot mosquitto.8.xml xml2po -o po/mosquitto.conf/mosquitto.conf.5.pot mosquitto.conf.5.xml xml2po -o po/mosquitto_passwd/mosquitto_passwd.1.pot mosquitto_passwd.1.xml xml2po -o po/mosquitto_pub/mosquitto_pub.1.pot mosquitto_pub.1.xml xml2po -o po/mosquitto_sub/mosquitto_sub.1.pot mosquitto_sub.1.xml xml2po -o po/mqtt/mqtt.7.pot mqtt.7.xml xml2po -o po/mosquitto-tls/mosquitto-tls.7.pot mosquitto-tls.7.xml xml2po -o po/libmosquitto/libmosquitto.3.pot libmosquitto.3.xml # To merge new translations do: # /usr/bin/xml2po -p de.po chapter1.xml > chapter1.de.xml mosquitto-1.4.15/man/mosquitto_sub.10000664000175000017500000003275113245550210016445 0ustar rogerroger'\" t .\" Title: mosquitto_sub .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: Commands .\" Source: Mosquitto Project .\" Language: English .\" .TH "MOSQUITTO_SUB" "1" "02/28/2018" "Mosquitto Project" "Commands" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mosquitto_sub \- an MQTT version 3\&.1 client for subscribing to topics .SH "SYNOPSIS" .HP \w'\fBmosquitto_sub\fR\ 'u \fBmosquitto_sub\fR [\fB\-A\fR\ \fIbind_address\fR] [\fB\-c\fR] [\fB\-C\fR\ \fImsg\ count\fR] [\fB\-d\fR] [\fB\-h\fR\ \fIhostname\fR] [\fB\-i\fR\ \fIclient_id\fR] [\fB\-I\fR\ \fIclient\ id\ prefix\fR] [\fB\-k\fR\ \fIkeepalive\ time\fR] [\fB\-p\fR\ \fIport\ number\fR] [\fB\-q\fR\ \fImessage\ QoS\fR] [\fB\-R\fR] [\fB\-S\fR] [\fB\-N\fR] [\fB\-\-quiet\fR] [\fB\-v\fR] [[\fB\-u\fR\ \fIusername\fR]\ [\fB\-P\fR\ \fIpassword\fR]] [\fB\-\-will\-topic\fR\ \fItopic\fR\ [\fB\-\-will\-payload\fR\ \fIpayload\fR]\ [\fB\-\-will\-qos\fR\ \fIqos\fR]\ [\fB\-\-will\-retain\fR]] [[{\fB\-\-cafile\fR\ \fIfile\fR\ |\ \fB\-\-capath\fR\ \fIdir\fR}\ [\fB\-\-cert\fR\ \fIfile\fR]\ [\fB\-\-key\fR\ \fIfile\fR]\ [\fB\-\-tls\-version\fR\ \fIversion\fR]\ [\fB\-\-insecure\fR]] | [\fB\-\-psk\fR\ \fIhex\-key\fR\ \fB\-\-psk\-identity\fR\ \fIidentity\fR\ [\fB\-\-tls\-version\fR\ \fIversion\fR]]] [\fB\-\-proxy\fR\ \fIsocks\-url\fR] [\fB\-V\fR\ \fIprotocol\-version\fR] [\fB\-T\fR\ \fIfilter\-out\fR...] \fB\-t\fR\ \fImessage\-topic\fR... .HP \w'\fBmosquitto_sub\fR\ 'u \fBmosquitto_sub\fR [\fB\-\-help\fR] .SH "DESCRIPTION" .PP \fBmosquitto_sub\fR is a simple MQTT version 3\&.1 client that will subscribe to a topic and print the messages that it receives\&. .SH "OPTIONS" .PP The options below may be given on the command line, but may also be placed in a config file located at \fB$XDG_CONFIG_HOME/mosquitto_sub\fR or \fB$HOME/\&.config/mosquitto_sub\fR with one pair of \fB\-option \fR\fB\fIvalue\fR\fR per line\&. The values in the config file will be used as defaults and can be overridden by using the command line\&. The exceptions to this are \fB\-t\fR and \fB\-T\fR, which if given in the config file will not be overridden\&. Note also that currently some options cannot be negated, e\&.g\&. \fB\-S\fR\&. Config file lines that have a \fB#\fR as the first character are treated as comments and not processed any further\&. .PP \fB\-A\fR .RS 4 Bind the outgoing connection to a local ip address/hostname\&. Use this argument if you need to restrict network communication to a particular interface\&. .RE .PP \fB\-c\fR, \fB\-\-disable\-clean\-session\fR .RS 4 Disable the \*(Aqclean session\*(Aq flag\&. This means that all of the subscriptions for the client will be maintained after it disconnects, along with subsequent QoS 1 and QoS 2 messages that arrive\&. When the client reconnects, it will receive all of the queued messages\&. .sp If using this option, it is recommended that the client id is set manually with \fB\-\-id\fR .RE .PP \fB\-\-cafile\fR .RS 4 Define the path to a file containing PEM encoded CA certificates that are trusted\&. Used to enable SSL communication\&. .sp See also \fB\-\-capath\fR .RE .PP \fB\-\-capath\fR .RS 4 Define the path to a directory containing PEM encoded CA certificates that are trusted\&. Used to enable SSL communication\&. .sp For \fB\-\-capath\fR to work correctly, the certificate files must have "\&.crt" as the file ending and you must run "c_rehash " each time you add/remove a certificate\&. .sp See also \fB\-\-cafile\fR .RE .PP \fB\-\-cert\fR .RS 4 Define the path to a file containing a PEM encoded certificate for this client, if required by the server\&. .sp See also \fB\-\-key\fR\&. .RE .PP \fB\-\-ciphers\fR .RS 4 An openssl compatible list of TLS ciphers to support in the client\&. See \fBciphers\fR(1) for more information\&. .RE .PP \fB\-C\fR .RS 4 Disconnect and exit the program immediately after the given count of messages have been received\&. This may be useful in shell scripts where on a single status value is required, for example\&. .sp Combine with \fB\-R\fR to print only the first set of fresh messages (i\&.e\&. that does not have the retained flag set), or with \fB\-T\fR to filter which topics are processed\&. .RE .PP \fB\-d\fR, \fB\-\-debug\fR .RS 4 Enable debug messages\&. .RE .PP \fB\-\-help\fR .RS 4 Display usage information\&. .RE .PP \fB\-h\fR, \fB\-\-host\fR .RS 4 Specify the host to connect to\&. Defaults to localhost\&. .RE .PP \fB\-i\fR, \fB\-\-id\fR .RS 4 The id to use for this client\&. If not given, defaults to mosquitto_sub_ appended with the process id of the client\&. Cannot be used at the same time as the \fB\-\-id\-prefix\fR argument\&. .RE .PP \fB\-I\fR, \fB\-\-id\-prefix\fR .RS 4 Provide a prefix that the client id will be built from by appending the process id of the client\&. This is useful where the broker is using the clientid_prefixes option\&. Cannot be used at the same time as the \fB\-\-id\fR argument\&. .RE .PP \fB\-\-insecure\fR .RS 4 When using certificate based encryption, this option disables verification of the server hostname in the server certificate\&. This can be useful when testing initial server configurations but makes it possible for a malicious third party to impersonate your server through DNS spoofing, for example\&. Use this option in testing \fIonly\fR\&. If you need to resort to using this option in a production environment, your setup is at fault and there is no point using encryption\&. .RE .PP \fB\-k\fR, \fB\-\-keepalive\fR .RS 4 The number of seconds between sending PING commands to the broker for the purposes of informing it we are still connected and functioning\&. Defaults to 60 seconds\&. .RE .PP \fB\-\-key\fR .RS 4 Define the path to a file containing a PEM encoded private key for this client, if required by the server\&. .sp See also \fB\-\-cert\fR\&. .RE .PP \fB\-N\fR .RS 4 Do not append an end of line character to the payload when printing\&. This allows streaming of payload data from multiple messages directly to another application unmodified\&. Only really makes sense when not using \fB\-v\fR\&. .RE .PP \fB\-p\fR, \fB\-\-port\fR .RS 4 Connect to the port specified instead of the default 1883\&. .RE .PP \fB\-P\fR, \fB\-\-pw\fR .RS 4 Provide a password to be used for authenticating with the broker\&. Using this argument without also specifying a username is invalid\&. This requires a broker that supports MQTT v3\&.1\&. See also the \fB\-\-username\fR option\&. .RE .PP \fB\-\-proxy\fR .RS 4 Specify a SOCKS5 proxy to connect through\&. "None" and "username" authentication types are supported\&. The \fBsocks\-url\fR must be of the form \fBsocks5h://[username[:password]@]host[:port]\fR\&. The protocol prefix \fBsocks5h\fR means that hostnames are resolved by the proxy\&. The symbols %25, %3A and %40 are URL decoded into %, : and @ respectively, if present in the username or password\&. .sp If username is not given, then no authentication is attempted\&. If the port is not given, then the default of 1080 is used\&. .sp More SOCKS versions may be available in the future, depending on demand, and will use different protocol prefixes as described in \fBcurl\fR(1)\&. .RE .PP \fB\-\-psk\fR .RS 4 Provide the hexadecimal (no leading 0x) pre\-shared\-key matching the one used on the broker to use TLS\-PSK encryption support\&. \fB\-\-psk\-identity\fR must also be provided to enable TLS\-PSK\&. .RE .PP \fB\-\-psk\-identity\fR .RS 4 The client identity to use with TLS\-PSK support\&. This may be used instead of a username if the broker is configured to do so\&. .RE .PP \fB\-q\fR, \fB\-\-qos\fR .RS 4 Specify the quality of service desired for the incoming messages, from 0, 1 and 2\&. Defaults to 0\&. See \fBmqtt\fR(7) for more information on QoS\&. .sp The QoS is identical for all topics subscribed to in a single instance of mosquitto_sub\&. .RE .PP \fB\-\-quiet\fR .RS 4 If this argument is given, no runtime errors will be printed\&. This excludes any error messages given in case of invalid user input (e\&.g\&. using \fB\-\-port\fR without a port)\&. .RE .PP \fB\-R\fR .RS 4 If this argument is given, messages that are received that have the retain bit set will not be printed\&. Messages with retain set are "stale", in that it is not known when they were originally published\&. When subscribing to a wildcard topic there may be a large number of retained messages\&. This argument suppresses their display\&. .RE .PP \fB\-S\fR .RS 4 Use SRV lookups to determine which host to connect to\&. Performs lookups to \fB_mqtt\&._tcp\&.\fR when used in conjunction with \fB\-h\fR, otherwise uses \fB_mqtt\&._tcp\&.\fR\&. .RE .PP \fB\-t\fR, \fB\-\-topic\fR .RS 4 The MQTT topic to subscribe to\&. See \fBmqtt\fR(7) for more information on MQTT topics\&. .sp This option may be repeated to subscribe to multiple topics\&. .RE .PP \fB\-T\fR, \fB\-\-filter\-out\fR .RS 4 Suppress printing of topics that match the filter\&. This allows subscribing to a wildcard topic and only printing a partial set of the wildcard hierarchy\&. .sp For example, subscribe to the BBC tree, but suppress output from Radio 3: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_sub \-t bbc/# \-T bbc/radio3 .RE .sp This option may be repeated to filter out multiple topics or topic trees\&. .RE .PP \fB\-\-tls\-version\fR .RS 4 Choose which TLS protocol version to use when communicating with the broker\&. Valid options are \fBtlsv1\&.2\fR, \fBtlsv1\&.1\fR and \fBtlsv1\fR\&. The default value is \fBtlsv1\&.2\fR\&. If the installed version of openssl is too old, only \fBtlsv1\fR will be available\&. Must match the protocol version used by the broker\&. .RE .PP \fB\-u\fR, \fB\-\-username\fR .RS 4 Provide a username to be used for authenticating with the broker\&. This requires a broker that supports MQTT v3\&.1\&. See also the \fB\-\-pw\fR argument\&. .RE .PP \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Print received messages verbosely\&. With this argument, messages will be printed as "topic payload"\&. When this argument is not given, the messages are printed as "payload"\&. .RE .PP \fB\-V\fR, \fB\-\-protocol\-version\fR .RS 4 Specify which version of the MQTT protocol should be used when connecting to the rmeote broker\&. Can be \fBmqttv31\fR or \fBmqttv311\fR\&. Defaults to \fBmqttv31\fR\&. .RE .PP \fB\-\-will\-payload\fR .RS 4 Specify a message that will be stored by the broker and sent out if this client disconnects unexpectedly\&. This must be used in conjunction with \fB\-\-will\-topic\fR\&. .RE .PP \fB\-\-will\-qos\fR .RS 4 The QoS to use for the Will\&. Defaults to 0\&. This must be used in conjunction with \fB\-\-will\-topic\fR\&. .RE .PP \fB\-\-will\-retain\fR .RS 4 If given, if the client disconnects unexpectedly the message sent out will be treated as a retained message\&. This must be used in conjunction with \fB\-\-will\-topic\fR\&. .RE .PP \fB\-\-will\-topic\fR .RS 4 The topic on which to send a Will, in the event that the client disconnects unexpectedly\&. .RE .SH "WILLS" .PP mosquitto_sub can register a message with the broker that will be sent out if it disconnects unexpectedly\&. See \fBmqtt\fR(7) for more information\&. .PP The minimum requirement for this is to use \fB\-\-will\-topic\fR to specify which topic the will should be sent out on\&. This will result in a non\-retained, zero length message with QoS 0\&. .PP Use the \fB\-\-will\-retain\fR, \fB\-\-will\-payload\fR and \fB\-\-will\-qos\fR arguments to modify the other will parameters\&. .SH "EXAMPLES" .PP Note that these really are examples \- the subscriptions will work if you run them as shown, but there must be something publishing messages on those topics for you to receive anything\&. .PP Subscribe to temperature information on localhost with QoS 1: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_sub \-t sensors/temperature \-q 1 .RE .PP Subscribe to hard drive temperature updates on multiple machines/hard drives\&. This expects each machine to be publishing its hard drive temperature to sensors/machines/HOSTNAME/temperature/HD_NAME\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_sub \-t sensors/machines/+/temperature/+ .RE .PP Subscribe to all broker status messages: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_sub \-v \-t \e$SYS/# .RE .SH "FILES" .PP $XDG_CONFIG_HOME/mosquitto_sub, $HOME/\&.config/mosquitto_sub .RS 4 Configuration file for default options\&. .RE .SH "BUGS" .PP \fBmosquitto\fR bug information can be found at \m[blue]\fB\%https://github.com/eclipse/mosquitto/issues\fR\m[] .SH "SEE ALSO" \fBmqtt\fR(7), \fBmosquitto_pub\fR(1), \fBmosquitto\fR(8), \fBlibmosquitto\fR(3), \fBmosquitto-tls\fR(7) .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/man/libmosquitto.30000664000175000017500000003030013245550210016251 0ustar rogerroger'\" t .\" Title: libmosquitto .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: Library calls .\" Source: Mosquitto Project .\" Language: English .\" .TH "LIBMOSQUITTO" "3" "02/28/2018" "Mosquitto Project" "Library calls" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libmosquitto \- MQTT version 3\&.1 client library .SH "DESCRIPTION" .PP This is an overview of how to use libmosquitto to create MQTT aware client programs\&. There may be separate man pages on each of the functions described here in the future\&. There is also a binding for libmosquitto for C++ and a Python implementation\&. They are not documented here but operate in a similar way\&. .PP This is fairly incomplete, please see mosquitto\&.h for a better description of the functions\&. .SH "LIBMOSQUITTO SYMBOL NAMES" .PP All public functions in libmosquitto have the prefix "mosquitto_"\&. Any other functions defined in the source code are to be treated as private functions and may change between any release\&. Do not use these functions! .SH "FUNCTIONS" .SS "Library version" .HP \w'int\ mosquitto_lib_version('u .BI "int mosquitto_lib_version(int\ *" "major" ", int\ *" "minor" ", int\ *" "revision" ");" .PP Obtain version information about the library\&. If any of major, minor or revision are not NULL they will return the corresponding version numbers\&. The return value is an integer representation of the complete version number (e\&.g\&. 1009001 for 1\&.9\&.1) that can be used for comparisons\&. .SS "Library initialisation and cleanup" .HP \w'int\ mosquitto_lib_init('u .BI "int mosquitto_lib_init(void);" .HP \w'int\ mosquitto_lib_cleanup('u .BI "int mosquitto_lib_cleanup(void);" .PP Call mosquitto_lib_init() before using any of the other library functions and mosquitto_lib_cleanup() after finishing with the library\&. .SS "Client constructor/destructor" .HP \w'struct\ mosquitto\ *mosquitto_new('u .BI "struct mosquitto *mosquitto_new(const\ char\ *" "id" ", bool\ " "clean_session" ", void\ *" "userdata" ");" .PP Create a new mosquitto client instance\&. .HP \w'void\ mosquitto_destroy('u .BI "void mosquitto_destroy(struct\ mosquitto\ *" "mosq" ");" .PP Use to free memory associated with a mosquitto client instance\&. .HP \w'int\ mosquitto_reinitialise('u .BI "int mosquitto_reinitialise(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "id" ", bool\ " "clean_session" ", void\ *" "userdata" ");" .SS "Authentication and encryption" .HP \w'int\ mosquitto_username_pw_set('u .BI "int mosquitto_username_pw_set(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "username" ", const\ char\ *" "password" ");" .HP \w'int\ mosquitto_tls_set('u .BI "int mosquitto_tls_set(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "cafile" ", const\ char\ *" "capath" ", const\ char\ *" "certfile" ", const\ char\ *" "keyfile" ", int\ " "(*pw_callback)(char\ *buf,\ int\ size,\ int\ rwflag,\ void\ *userdata)" ");" .HP \w'int\ mosquitto_tls_opts_set('u .BI "int mosquitto_tls_opts_set(struct\ mosquitto\ *" "mosq" ", int\ " "cert_reqs" ", const\ char\ *" "tls_version" ", const\ char\ *" "ciphers" ");" .HP \w'int\ mosquitto_tls_insecure_set('u .BI "int mosquitto_tls_insecure_set(struct\ mosquitto\ *" "mosq" ", bool\ " "value" ");" .HP \w'int\ mosquitto_tls_psk_set('u .BI "int mosquitto_tls_psk_set(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "psk" ", const\ char\ *" "identity" ", const\ char\ *" "ciphers" ");" .SS "Wills" .HP \w'int\ mosquitto_will_set('u .BI "int mosquitto_will_set(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "topic" ", int\ " "payloadlen" ", const\ void\ *" "payload" ", int\ " "qos" ", bool\ " "retain" ");" .HP \w'int\ mosquitto_will_clear('u .BI "int mosquitto_will_clear(" "struct\ mosquitto\ *mosq" ");" .SS "Connect/disconnect" .HP \w'int\ mosquitto_connect('u .BI "int mosquitto_connect(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "host" ", int\ " "port" ", int\ " "keepalive" ");" .HP \w'int\ mosquitto_connect_bind('u .BI "int mosquitto_connect_bind(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "host" ", int\ " "port" ", int\ " "keepalive" ", const\ char\ *" "bind_address" ");" .HP \w'int\ mosquitto_connect_async('u .BI "int mosquitto_connect_async(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "host" ", int\ " "port" ", int\ " "keepalive" ");" .HP \w'int\ mosquitto_connect_bind_async('u .BI "int mosquitto_connect_bind_async(struct\ mosquitto\ *" "mosq" ", const\ char\ *" "host" ", int\ " "port" ", int\ " "keepalive" ", const\ char\ *" "bind_address" ");" .HP \w'int\ mosquitto_reconnect('u .BI "int mosquitto_reconnect(struct\ mosquitto\ *" "mosq" ");" .HP \w'int\ mosquitto_reconnect_async('u .BI "int mosquitto_reconnect_async(struct\ mosquitto\ *" "mosq" ");" .HP \w'int\ mosquitto_disconnect('u .BI "int mosquitto_disconnect(struct\ mosquitto\ *" "mosq" ");" .SS "Publish" .HP \w'int\ mosquitto_publish('u .BI "int mosquitto_publish(struct\ mosquitto\ *" "mosq" ", int\ *" "mid" ", const\ char\ *" "topic" ", int\ " "payloadlen" ", const\ void\ *" "payload" ", int\ " "qos" ", bool\ " "retain" ");" .SS "Subscribe/unsubscribe" .HP \w'int\ mosquitto_subscribe('u .BI "int mosquitto_subscribe(struct\ mosquitto\ *" "mosq" ", int\ *" "mid" ", const\ char\ *" "sub" ", int\ " "qos" ");" .HP \w'int\ mosquitto_unsubscribe('u .BI "int mosquitto_unsubscribe(struct\ mosquitto\ *" "mosq" ", int\ *" "mid" ", const\ char\ *" "sub" ");" .SS "Network loop" .HP \w'int\ mosquitto_loop('u .BI "int mosquitto_loop(struct\ mosquitto\ *" "mosq" ", int\ " "timeout" ", int\ " "max_packets" ");" .HP \w'int\ mosquitto_loop_read('u .BI "int mosquitto_loop_read(struct\ mosquitto\ *" "mosq" ", int\ " "max_packets" ");" .HP \w'int\ mosquitto_loop_write('u .BI "int mosquitto_loop_write(struct\ mosquitto\ *" "mosq" ", int\ " "max_packets" ");" .HP \w'int\ mosquitto_loop_misc('u .BI "int mosquitto_loop_misc(struct\ mosquitto\ *" "mosq" ");" .HP \w'int\ mosquitto_loop_forever('u .BI "int mosquitto_loop_forever(struct\ mosquitto\ *" "mosq" ", int\ " "timeout" ", int\ " "max_packets" ");" .HP \w'int\ mosquitto_socket('u .BI "int mosquitto_socket(struct\ mosquitto\ *" "mosq" ");" .HP \w'bool\ mosquitto_want_write('u .BI "bool mosquitto_want_write(struct\ mosquitto\ *" "mosq" ");" .SS "Threaded network loop" .HP \w'int\ mosquitto_loop_start('u .BI "int mosquitto_loop_start(struct\ mosquitto\ *" "mosq" ");" .HP \w'int\ mosquitto_loop_stop('u .BI "int mosquitto_loop_stop(struct\ mosquitto\ *" "mosq" ", bool\ " "force" ");" .SS "Misc client functions" .HP \w'int\ mosquitto_max_inflight_messages_set('u .BI "int mosquitto_max_inflight_messages_set(struct\ mosquitto\ *" "mosq" ", unsigned\ int\ " "max_inflight_messages" ");" .HP \w'int\ mosquitto_message_retry_set('u .BI "int mosquitto_message_retry_set(struct\ mosquitto\ *" "mosq" ", unsigned\ int\ " "message_retry" ");" .HP \w'int\ mosquitto_reconnect_delay_set('u .BI "int mosquitto_reconnect_delay_set(struct\ mosquitto\ *" "mosq" ", unsigned\ int\ " "reconnect_delay" ", unsigned\ int\ " "reconnect_delay_max" ", bool\ " "reconnect_exponential_backoff" ");" .HP \w'int\ mosquitto_user_data_set('u .BI "int mosquitto_user_data_set(struct\ mosquitto\ *" "mosq" ", void\ *" "userdata" ");" .SS "Callbacks" .HP \w'int\ mosquitto_connect_callback_set('u .BI "int mosquitto_connect_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_connect)(struct\ mosquitto\ *,\ void\ *,\ int)" ");" .HP \w'int\ mosquitto_disconnect_callback_set('u .BI "int mosquitto_disconnect_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_disconnect)(struct\ mosquitto\ *,\ void\ *,\ int)" ");" .HP \w'int\ mosquitto_publish_callback_set('u .BI "int mosquitto_publish_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_publish)(struct\ mosquitto\ *,\ void\ *,\ int)" ");" .HP \w'int\ mosquitto_message_callback_set('u .BI "int mosquitto_message_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_message)(struct\ mosquitto\ *,\ void\ *,\ const\ struct\ mosquitto_message\ *)" ");" .HP \w'int\ mosquitto_subscribe_callback_set('u .BI "int mosquitto_subscribe_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_subscribe)(struct\ mosquitto\ *,\ void\ *,\ int,\ int,\ const\ int\ *)" ");" .HP \w'int\ mosquitto_unsubscribe_callback_set('u .BI "int mosquitto_unsubscribe_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_unsubscribe)(struct\ mosquitto\ *,\ void\ *,\ int)" ");" .HP \w'int\ mosquitto_log_callback_set('u .BI "int mosquitto_log_callback_set(struct\ mosquitto\ *" "mosq" ", void\ " "(*on_unsubscribe)(struct\ mosquitto\ *,\ void\ *,\ int,\ const\ char\ *)" ");" .SS "Utility functions" .HP \w'const\ char\ *mosquitto_connack_string('u .BI "const char *mosquitto_connack_string(int\ " "connack_code" ");" .HP \w'int\ mosquitto_message_copy('u .BI "int mosquitto_message_copy(struct\ mosquitto_message\ *" "dst" ", const\ struct\ mosquitto_message\ *" "src" ");" .HP \w'int\ mosquitto_message_free('u .BI "int mosquitto_message_free(struct\ mosquitto_message\ **" "message" ");" .HP \w'const\ char\ *mosquitto_strerror('u .BI "const char *mosquitto_strerror(int\ " "mosq_errno" ");" .HP \w'int\ mosquitto_sub_topic_tokenise('u .BI "int mosquitto_sub_topic_tokenise(const\ char\ *" "subtopic" ", char\ ***" "topics" ", int\ *" "count" ");" .HP \w'int\ mosquitto_sub_topic_tokens_free('u .BI "int mosquitto_sub_topic_tokens_free(char\ ***" "topics" ", int\ " "count" ");" .HP \w'int\ mosquitto_topic_matches_sub('u .BI "int mosquitto_topic_matches_sub(const\ char\ *" "sub" ", const\ char\ *" "topic" ", bool\ *" "result" ");" .SH "EXAMPLES" .PP .if n \{\ .RS 4 .\} .nf #include #include void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message\->payloadlen){ printf("%s %s\en", message\->topic, message\->payload); }else{ printf("%s (null)\en", message\->topic); } fflush(stdout); } void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) { int i; if(!result){ /* Subscribe to broker information topics on successful connect\&. */ mosquitto_subscribe(mosq, NULL, "$SYS/#", 2); }else{ fprintf(stderr, "Connect failed\en"); } } void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) { int i; printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; i mosquitto-1.4.15/man/mosquitto_pub.10000664000175000017500000003052213245550210016434 0ustar rogerroger'\" t .\" Title: mosquitto_pub .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: Commands .\" Source: Mosquitto Project .\" Language: English .\" .TH "MOSQUITTO_PUB" "1" "02/28/2018" "Mosquitto Project" "Commands" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mosquitto_pub \- an MQTT version 3\&.1/3\&.1\&.1 client for publishing simple messages .SH "SYNOPSIS" .HP \w'\fBmosquitto_pub\fR\ 'u \fBmosquitto_pub\fR [\fB\-A\fR\ \fIbind_address\fR] [\fB\-d\fR] [\fB\-h\fR\ \fIhostname\fR] [\fB\-i\fR\ \fIclient_id\fR] [\fB\-I\fR\ \fIclient\ id\ prefix\fR] [\fB\-k\fR\ \fIkeepalive\ time\fR] [\fB\-p\fR\ \fIport\ number\fR] [\fB\-q\fR\ \fImessage\ QoS\fR] [\fB\-\-quiet\fR] [\fB\-r\fR] [\fB\-S\fR] {\fB\-f\fR\ \fIfile\fR | \fB\-l\fR | \fB\-m\fR\ \fImessage\fR | \fB\-n\fR | \fB\-s\fR} [[\fB\-u\fR\ \fIusername\fR]\ [\fB\-P\fR\ \fIpassword\fR]] [\fB\-\-will\-topic\fR\ \fItopic\fR\ [\fB\-\-will\-payload\fR\ \fIpayload\fR]\ [\fB\-\-will\-qos\fR\ \fIqos\fR]\ [\fB\-\-will\-retain\fR]] [[{\fB\-\-cafile\fR\ \fIfile\fR\ |\ \fB\-\-capath\fR\ \fIdir\fR}\ [\fB\-\-cert\fR\ \fIfile\fR]\ [\fB\-\-key\fR\ \fIfile\fR]\ [\fB\-\-ciphers\fR\ \fIciphers\fR]\ [\fB\-\-tls\-version\fR\ \fIversion\fR]\ [\fB\-\-insecure\fR]] | [\fB\-\-psk\fR\ \fIhex\-key\fR\ \fB\-\-psk\-identity\fR\ \fIidentity\fR\ [\fB\-\-ciphers\fR\ \fIciphers\fR]\ [\fB\-\-tls\-version\fR\ \fIversion\fR]]] [\fB\-\-proxy\fR\ \fIsocks\-url\fR] [\fB\-V\fR\ \fIprotocol\-version\fR] \fB\-t\fR\ \fImessage\-topic\fR .HP \w'\fBmosquitto_pub\fR\ 'u \fBmosquitto_pub\fR [\fB\-\-help\fR] .SH "DESCRIPTION" .PP \fBmosquitto_pub\fR is a simple MQTT version 3\&.1 client that will publish a single message on a topic and exit\&. .SH "OPTIONS" .PP The options below may be given on the command line, but may also be placed in a config file located at \fB$XDG_CONFIG_HOME/mosquitto_pub\fR or \fB$HOME/\&.config/mosquitto_sub\fR with one pair of \fB\-option \fR\fB\fIvalue\fR\fR per line\&. The values in the config file will be used as defaults and can be overridden by using the command line\&. The exceptions to this are the message type options, of which only one can be specified\&. Note also that currently some options cannot be negated, e\&.g\&. \fB\-S\fR\&. Config file lines that have a \fB#\fR as the first character are treated as comments and not processed any further\&. .PP \fB\-A\fR .RS 4 Bind the outgoing connection to a local ip address/hostname\&. Use this argument if you need to restrict network communication to a particular interface\&. .RE .PP \fB\-\-cafile\fR .RS 4 Define the path to a file containing PEM encoded CA certificates that are trusted\&. Used to enable SSL communication\&. .sp See also \fB\-\-capath\fR .RE .PP \fB\-\-capath\fR .RS 4 Define the path to a directory containing PEM encoded CA certificates that are trusted\&. Used to enable SSL communication\&. .sp For \fB\-\-capath\fR to work correctly, the certificate files must have "\&.crt" as the file ending and you must run "c_rehash " each time you add/remove a certificate\&. .sp See also \fB\-\-cafile\fR .RE .PP \fB\-\-cert\fR .RS 4 Define the path to a file containing a PEM encoded certificate for this client, if required by the server\&. .sp See also \fB\-\-key\fR\&. .RE .PP \fB\-\-ciphers\fR .RS 4 An openssl compatible list of TLS ciphers to support in the client\&. See \fBciphers\fR(1) for more information\&. .RE .PP \fB\-d\fR, \fB\-\-debug\fR .RS 4 Enable debug messages\&. .RE .PP \fB\-f\fR, \fB\-\-file\fR .RS 4 Send the contents of a file as the message\&. .RE .PP \fB\-\-help\fR .RS 4 Display usage information\&. .RE .PP \fB\-h\fR, \fB\-\-host\fR .RS 4 Specify the host to connect to\&. Defaults to localhost\&. .RE .PP \fB\-i\fR, \fB\-\-id\fR .RS 4 The id to use for this client\&. If not given, defaults to mosquitto_pub_ appended with the process id of the client\&. Cannot be used at the same time as the \fB\-\-id\-prefix\fR argument\&. .RE .PP \fB\-I\fR, \fB\-\-id\-prefix\fR .RS 4 Provide a prefix that the client id will be built from by appending the process id of the client\&. This is useful where the broker is using the clientid_prefixes option\&. Cannot be used at the same time as the \fB\-\-id\fR argument\&. .RE .PP \fB\-\-insecure\fR .RS 4 When using certificate based encryption, this option disables verification of the server hostname in the server certificate\&. This can be useful when testing initial server configurations but makes it possible for a malicious third party to impersonate your server through DNS spoofing, for example\&. Use this option in testing \fIonly\fR\&. If you need to resort to using this option in a production environment, your setup is at fault and there is no point using encryption\&. .RE .PP \fB\-k\fR, \fB\-\-keepalive\fR .RS 4 The number of seconds between sending PING commands to the broker for the purposes of informing it we are still connected and functioning\&. Defaults to 60 seconds\&. .RE .PP \fB\-\-key\fR .RS 4 Define the path to a file containing a PEM encoded private key for this client, if required by the server\&. .sp See also \fB\-\-cert\fR\&. .RE .PP \fB\-l\fR, \fB\-\-stdin\-line\fR .RS 4 Send messages read from stdin, splitting separate lines into separate messages\&. Note that blank lines won\*(Aqt be sent\&. .RE .PP \fB\-m\fR, \fB\-\-message\fR .RS 4 Send a single message from the command line\&. .RE .PP \fB\-n\fR, \fB\-\-null\-message\fR .RS 4 Send a null (zero length) message\&. .RE .PP \fB\-p\fR, \fB\-\-port\fR .RS 4 Connect to the port specified instead of the default 1883\&. .RE .PP \fB\-P\fR, \fB\-\-pw\fR .RS 4 Provide a password to be used for authenticating with the broker\&. Using this argument without also specifying a username is invalid\&. This requires a broker that supports MQTT v3\&.1\&. See also the \fB\-\-username\fR option\&. .RE .PP \fB\-\-proxy\fR .RS 4 Specify a SOCKS5 proxy to connect through\&. "None" and "username" authentication types are supported\&. The \fBsocks\-url\fR must be of the form \fBsocks5h://[username[:password]@]host[:port]\fR\&. The protocol prefix \fBsocks5h\fR means that hostnames are resolved by the proxy\&. The symbols %25, %3A and %40 are URL decoded into %, : and @ respectively, if present in the username or password\&. .sp If username is not given, then no authentication is attempted\&. If the port is not given, then the default of 1080 is used\&. .sp More SOCKS versions may be available in the future, depending on demand, and will use different protocol prefixes as described in \fBcurl\fR(1)\&. .RE .PP \fB\-\-psk\fR .RS 4 Provide the hexadecimal (no leading 0x) pre\-shared\-key matching the one used on the broker to use TLS\-PSK encryption support\&. \fB\-\-psk\-identity\fR must also be provided to enable TLS\-PSK\&. .RE .PP \fB\-\-psk\-identity\fR .RS 4 The client identity to use with TLS\-PSK support\&. This may be used instead of a username if the broker is configured to do so\&. .RE .PP \fB\-q\fR, \fB\-\-qos\fR .RS 4 Specify the quality of service to use for the message, from 0, 1 and 2\&. Defaults to 0\&. .RE .PP \fB\-\-quiet\fR .RS 4 If this argument is given, no runtime errors will be printed\&. This excludes any error messages given in case of invalid user input (e\&.g\&. using \fB\-\-port\fR without a port)\&. .RE .PP \fB\-r\fR, \fB\-\-retain\fR .RS 4 If retain is given, the message will be retained as a "last known good" value on the broker\&. See \fBmqtt\fR(7) for more information\&. .RE .PP \fB\-s\fR, \fB\-\-stdin\-file\fR .RS 4 Send a message read from stdin, sending the entire content as a single message\&. .RE .PP \fB\-S\fR .RS 4 Use SRV lookups to determine which host to connect to\&. Performs lookups to \fB_mqtt\&._tcp\&.\fR when used in conjunction with \fB\-h\fR, otherwise uses \fB_mqtt\&._tcp\&.\fR\&. .RE .PP \fB\-t\fR, \fB\-\-topic\fR .RS 4 The MQTT topic on which to publish the message\&. See \fBmqtt\fR(7) for more information on MQTT topics\&. .RE .PP \fB\-\-tls\-version\fR .RS 4 Choose which TLS protocol version to use when communicating with the broker\&. Valid options are \fBtlsv1\&.2\fR, \fBtlsv1\&.1\fR and \fBtlsv1\fR\&. The default value is \fBtlsv1\&.2\fR\&. If the installed version of openssl is too old, only \fBtlsv1\fR will be available\&. Must match the protocol version used by the broker\&. .RE .PP \fB\-u\fR, \fB\-\-username\fR .RS 4 Provide a username to be used for authenticating with the broker\&. This requires a broker that supports MQTT v3\&.1\&. See also the \fB\-\-pw\fR argument\&. .RE .PP \fB\-V\fR, \fB\-\-protocol\-version\fR .RS 4 Specify which version of the MQTT protocol should be used when connecting to the rmeote broker\&. Can be \fBmqttv31\fR or \fBmqttv311\fR\&. Defaults to \fBmqttv31\fR\&. .RE .PP \fB\-\-will\-payload\fR .RS 4 Specify a message that will be stored by the broker and sent out if this client disconnects unexpectedly\&. This must be used in conjunction with \fB\-\-will\-topic\fR\&. .RE .PP \fB\-\-will\-qos\fR .RS 4 The QoS to use for the Will\&. Defaults to 0\&. This must be used in conjunction with \fB\-\-will\-topic\fR\&. .RE .PP \fB\-\-will\-retain\fR .RS 4 If given, if the client disconnects unexpectedly the message sent out will be treated as a retained message\&. This must be used in conjunction with \fB\-\-will\-topic\fR\&. .RE .PP \fB\-\-will\-topic\fR .RS 4 The topic on which to send a Will, in the event that the client disconnects unexpectedly\&. .RE .SH "WILLS" .PP mosquitto_sub can register a message with the broker that will be sent out if it disconnects unexpectedly\&. See \fBmqtt\fR(7) for more information\&. .PP The minimum requirement for this is to use \fB\-\-will\-topic\fR to specify which topic the will should be sent out on\&. This will result in a non\-retained, zero length message with QoS 0\&. .PP Use the \fB\-\-will\-retain\fR, \fB\-\-will\-payload\fR and \fB\-\-will\-qos\fR arguments to modify the other will parameters\&. .SH "EXAMPLES" .PP Publish temperature information to localhost with QoS 1: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_pub \-t sensors/temperature \-m 32 \-q 1 .RE .PP Publish timestamp and temperature information to a remote host on a non\-standard port and QoS 0: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_pub \-h 192\&.168\&.1\&.1 \-p 1885 \-t sensors/temperature \-m "1266193804 32" .RE .PP Publish light switch status\&. Message is set to retained because there may be a long period of time between light switch events: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_pub \-r \-t switches/kitchen_lights/status \-m "on" .RE .PP Send the contents of a file in two ways: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_pub \-t my/topic \-f \&./data .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_pub \-t my/topic \-s < \&./data .RE .PP Send parsed electricity usage data from a Current Cost meter, reading from stdin with one line/reading as one message: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} read_cc128\&.pl | mosquitto_pub \-t sensors/cc128 \-l .RE .SH "FILES" .PP $XDG_CONFIG_HOME/mosquitto_pub, $HOME/\&.config/mosquitto_pub .RS 4 Configuration file for default options\&. .RE .SH "BUGS" .PP \fBmosquitto\fR bug information can be found at \m[blue]\fB\%https://github.com/eclipse/mosquitto/issues\fR\m[] .SH "SEE ALSO" \fBmqtt\fR(7), \fBmosquitto_sub\fR(1), \fBmosquitto\fR(8), \fBlibmosquitto\fR(3), \fBmosquitto-tls\fR(7) .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/man/mosquitto_passwd.10000664000175000017500000000662713245550210017160 0ustar rogerroger'\" t .\" Title: mosquitto_passwd .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: Commands .\" Source: Mosquitto Project .\" Language: English .\" .TH "MOSQUITTO_PASSWD" "1" "02/28/2018" "Mosquitto Project" "Commands" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mosquitto_passwd \- manage password files for mosquitto .SH "SYNOPSIS" .HP \w'\fBmosquitto_passwd\fR\ 'u \fBmosquitto_passwd\fR [\fB\-c\fR | \fB\-D\fR] \fIpasswordfile\fR \fIusername\fR .HP \w'\fBmosquitto_passwd\fR\ 'u \fBmosquitto_passwd\fR \fB\-b\fR \fIpasswordfile\fR \fIusername\fR \fIpassword\fR .HP \w'\fBmosquitto_passwd\fR\ 'u \fBmosquitto_passwd\fR \fB\-U\fR \fIpasswordfile\fR .SH "DESCRIPTION" .PP \fBmosquitto_passwd\fR is a tool for managing password files for the mosquitto MQTT broker\&. .PP Usernames must not contain ":"\&. Passwords are stored in a similar format to \fBcrypt\fR(3)\&. .SH "OPTIONS" .PP \fB\-b\fR .RS 4 Run in batch mode\&. This allows the password to be provided at the command line which can be convenient but should be used with care because the password will be visible on the command line and in command history\&. .RE .PP \fB\-c\fR .RS 4 Create a new password file\&. If the file already exists, it will be overwritten\&. .RE .PP \fB\-D\fR .RS 4 Delete the specified user from the password file\&. .RE .PP \fB\-U\fR .RS 4 This option can be used to upgrade/convert a password file with plain text passwords into one using hashed passwords\&. It will modify the specified file\&. It does not detect whether passwords are already hashed, so using it on a password file that already contains hashed passwords will generate new hashes based on the old hashes and render the password file unusable\&. .RE .PP \fBpasswordfile\fR .RS 4 The password file to modify\&. .RE .PP \fBusername\fR .RS 4 The username to add/update/delete\&. .RE .PP \fBpassword\fR .RS 4 The password to use when in batch mode\&. .RE .SH "EXAMPLES" .PP Add a user to a new password file: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_passwd \-c /etc/mosquitto/passwd ral .RE .PP Delete a user from a password file .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} mosquitto_passwd \-D /etc/mosquitto/passwd ral .RE .SH "BUGS" .PP \fBmosquitto\fR bug information can be found at \m[blue]\fB\%https://github.com/eclipse/mosquitto/issues\fR\m[] .SH "SEE ALSO" \fBmosquitto\fR(8), \fBmosquitto.conf\fR(5), \fBmqtt\fR(7) .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/man/mqtt.70000664000175000017500000002052013245550210014512 0ustar rogerroger'\" t .\" Title: mqtt .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: Conventions and miscellaneous .\" Source: Mosquitto Project .\" Language: English .\" .TH "MQTT" "7" "02/28/2018" "Mosquitto Project" "Conventions and miscellaneous" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mqtt \- MQ Telemetry Transport .SH "SYNOPSIS" .HP \w'\fBMQTT\fR\ 'u \fBMQTT\fR .SH "DESCRIPTION" .PP \fBMQTT\fR is a lightweight publish/subscribe messaging protocol\&. It is useful for use with low power sensors, but is applicable to many scenarios\&. .PP This manual describes some of the features of MQTT version 3\&.1, to assist end users in getting the most out of the protocol\&. For more complete information on MQTT, see http://mqtt\&.org/\&. .SH "PUBLISH/SUBSCRIBE" .PP The MQTT protocol is based on the principle of publishing messages and subscribing to topics, or "pub/sub"\&. Multiple clients connect to a broker and subscribe to topics that they are interested in\&. Clients also connect to the broker and publish messages to topics\&. Many clients may subscribe to the same topics and do with the information as they please\&. The broker and MQTT act as a simple, common interface for everything to connect to\&. This means that you if you have clients that dump subscribed messages to a database, to Twitter, Cosm or even a simple text file, then it becomes very simple to add new sensors or other data input to a database, Twitter or so on\&. .SH "TOPICS/SUBSCRIPTIONS" .PP Messages in MQTT are published on topics\&. There is no need to configure a topic, publishing on it is enough\&. Topics are treated as a hierarchy, using a slash (/) as a separator\&. This allows sensible arrangement of common themes to be created, much in the same way as a filesystem\&. For example, multiple computers may all publish their hard drive temperature information on the following topic, with their own computer and hard drive name being replaced as appropriate: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} sensors/COMPUTER_NAME/temperature/HARDDRIVE_NAME .RE .PP Clients can receive messages by creating subscriptions\&. A subscription may be to an explicit topic, in which case only messages to that topic will be received, or it may include wildcards\&. Two wildcards are available, \fB+\fR or \fB#\fR\&. .PP \fB+\fR can be used as a wildcard for a single level of hierarchy\&. It could be used with the topic above to get information on all computers and hard drives as follows: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} sensors/+/temperature/+ .RE .PP As another example, for a topic of "a/b/c/d", the following example subscriptions will match: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/b/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/+/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/+/+/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/+/+/+ .RE .PP The following subscriptions will not match: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} b/+/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/+/+ .RE .PP \fB#\fR can be used as a wildcard for all remaining levels of hierarchy\&. This means that it must be the final character in a subscription\&. With a topic of "a/b/c/d", the following example subscriptions will match: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} # .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/# .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/# .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c/# .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/b/c/# .RE .PP Zero length topic levels are valid, which can lead to some slightly non\-obvious behaviour\&. For example, a topic of "a//topic" would correctly match against a subscription of "a/+/topic"\&. Likewise, zero length topic levels can exist at both the beginning and the end of a topic string, so "/a/topic" would match against a subscription of "+/a/topic", "#" or "/#", and a topic "a/topic/" would match against a subscription of "a/topic/+" or "a/topic/#"\&. .SH "QUALITY OF SERVICE" .PP MQTT defines three levels of Quality of Service (QoS)\&. The QoS defines how hard the broker/client will try to ensure that a message is received\&. Messages may be sent at any QoS level, and clients may attempt to subscribe to topics at any QoS level\&. This means that the client chooses the maximum QoS it will receive\&. For example, if a message is published at QoS 2 and a client is subscribed with QoS 0, the message will be delivered to that client with QoS 0\&. If a second client is also subscribed to the same topic, but with QoS 2, then it will receive the same message but with QoS 2\&. For a second example, if a client is subscribed with QoS 2 and a message is published on QoS 0, the client will receive it on QoS 0\&. .PP Higher levels of QoS are more reliable, but involve higher latency and have higher bandwidth requirements\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 0: The broker/client will deliver the message once, with no confirmation\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 1: The broker/client will deliver the message at least once, with confirmation required\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 2: The broker/client will deliver the message exactly once by using a four step handshake\&. .RE .SH "RETAINED MESSAGES" .PP All messages may be set to be retained\&. This means that the broker will keep the message even after sending it to all current subscribers\&. If a new subscription is made that matches the topic of the retained message, then the message will be sent to the client\&. This is useful as a "last known good" mechanism\&. If a topic is only updated infrequently, then without a retained message, a newly subscribed client may have to wait a long time to receive an update\&. With a retained message, the client will receive an instant update\&. .SH "CLEAN SESSION / DURABLE CONNECTIONS" .PP On connection, a client sets the "clean session" flag, which is sometimes also known as the "clean start" flag\&. If clean session is set to false, then the connection is treated as durable\&. This means that when the client disconnects, any subscriptions it has will remain and any subsequent QoS 1 or 2 messages will be stored until it connects again in the future\&. If clean session is true, then all subscriptions will be removed for the client when it disconnects\&. .SH "WILLS" .PP When a client connects to a broker, it may inform the broker that it has a will\&. This is a message that it wishes the broker to send when the client disconnects unexpectedly\&. The will message has a topic, QoS and retain status just the same as any other message\&. .SH "SEE ALSO" \fBmosquitto\fR(8), \fBmosquitto_pub\fR(1), \fBmosquitto_sub\fR(1) .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/man/mosquitto-tls.70000664000175000017500000000757413245550210016407 0ustar rogerroger'\" t .\" Title: mosquitto-tls .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: Conventions and miscellaneous .\" Source: Mosquitto Project .\" Language: English .\" .TH "MOSQUITTO\-TLS" "7" "02/28/2018" "Mosquitto Project" "Conventions and miscellaneous" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mosquitto-tls \- Configure SSL/TLS support for Mosquitto .SH "DESCRIPTION" .PP \fBmosquitto\fR provides SSL support for encrypted network connections and authentication\&. This manual describes how to create the files needed\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP It is important to use different certificate subject parameters for your CA, server and clients\&. If the certificates appear identical, even though generated separately, the broker/client will not be able to distinguish between them and you will experience difficult to diagnose errors\&. .sp .5v .RE .SH "CERTIFICATE AUTHORITY" .PP Generate a certificate authority certificate and key\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl req \-new \-x509 \-days \-extensions v3_ca \-keyout ca\&.key \-out ca\&.crt .RE .SH "SERVER" .PP Generate a server key\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl genrsa \-des3 \-out server\&.key 2048 .RE .PP Generate a server key without encryption\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl genrsa \-out server\&.key 2048 .RE .PP Generate a certificate signing request to send to the CA\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl req \-out server\&.csr \-key server\&.key \-new .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .PP When prompted for the CN (Common Name), please enter either your server (or broker) hostname or domain name\&. .sp .5v .RE .PP Send the CSR to the CA, or sign it with your CA key: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl x509 \-req \-in server\&.csr \-CA ca\&.crt \-CAkey ca\&.key \-CAcreateserial \-out server\&.crt \-days .RE .SH "CLIENT" .PP Generate a client key\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl genrsa \-des3 \-out client\&.key 2048 .RE .PP Generate a certificate signing request to send to the CA\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl req \-out client\&.csr \-key client\&.key \-new .RE .PP Send the CSR to the CA, or sign it with your CA key: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} openssl x509 \-req \-in client\&.csr \-CA ca\&.crt \-CAkey ca\&.key \-CAcreateserial \-out client\&.crt \-days .RE .SH "SEE ALSO" \fBmosquitto\fR(8), \fBmosquitto-conf\fR(5) .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/man/mosquitto_sub.1.xml0000664000175000017500000005214413245550210017242 0ustar rogerroger mosquitto_sub 1 Mosquitto Project Commands mosquitto_sub an MQTT version 3.1 client for subscribing to topics mosquitto_sub bind_address msg count hostname client_id client id prefix keepalive time port number message QoS username password topic payload qos file dir file file version hex-key identity version socks-url protocol-version filter-out message-topic mosquitto_sub Description mosquitto_sub is a simple MQTT version 3.1 client that will subscribe to a topic and print the messages that it receives. Options The options below may be given on the command line, but may also be placed in a config file located at or with one pair of per line. The values in the config file will be used as defaults and can be overridden by using the command line. The exceptions to this are and , which if given in the config file will not be overridden. Note also that currently some options cannot be negated, e.g. . Config file lines that have a as the first character are treated as comments and not processed any further. Bind the outgoing connection to a local ip address/hostname. Use this argument if you need to restrict network communication to a particular interface. Disable the 'clean session' flag. This means that all of the subscriptions for the client will be maintained after it disconnects, along with subsequent QoS 1 and QoS 2 messages that arrive. When the client reconnects, it will receive all of the queued messages. If using this option, it is recommended that the client id is set manually with Define the path to a file containing PEM encoded CA certificates that are trusted. Used to enable SSL communication. See also Define the path to a directory containing PEM encoded CA certificates that are trusted. Used to enable SSL communication. For to work correctly, the certificate files must have ".crt" as the file ending and you must run "c_rehash <path to capath>" each time you add/remove a certificate. See also Define the path to a file containing a PEM encoded certificate for this client, if required by the server. See also . An openssl compatible list of TLS ciphers to support in the client. See ciphers1 for more information. Disconnect and exit the program immediately after the given count of messages have been received. This may be useful in shell scripts where on a single status value is required, for example. Combine with to print only the first set of fresh messages (i.e. that does not have the retained flag set), or with to filter which topics are processed. Enable debug messages. Display usage information. Specify the host to connect to. Defaults to localhost. The id to use for this client. If not given, defaults to mosquitto_sub_ appended with the process id of the client. Cannot be used at the same time as the argument. Provide a prefix that the client id will be built from by appending the process id of the client. This is useful where the broker is using the clientid_prefixes option. Cannot be used at the same time as the argument. When using certificate based encryption, this option disables verification of the server hostname in the server certificate. This can be useful when testing initial server configurations but makes it possible for a malicious third party to impersonate your server through DNS spoofing, for example. Use this option in testing only. If you need to resort to using this option in a production environment, your setup is at fault and there is no point using encryption. The number of seconds between sending PING commands to the broker for the purposes of informing it we are still connected and functioning. Defaults to 60 seconds. Define the path to a file containing a PEM encoded private key for this client, if required by the server. See also . Do not append an end of line character to the payload when printing. This allows streaming of payload data from multiple messages directly to another application unmodified. Only really makes sense when not using . Connect to the port specified instead of the default 1883. Provide a password to be used for authenticating with the broker. Using this argument without also specifying a username is invalid. This requires a broker that supports MQTT v3.1. See also the option. Specify a SOCKS5 proxy to connect through. "None" and "username" authentication types are supported. The must be of the form . The protocol prefix means that hostnames are resolved by the proxy. The symbols %25, %3A and %40 are URL decoded into %, : and @ respectively, if present in the username or password. If username is not given, then no authentication is attempted. If the port is not given, then the default of 1080 is used. More SOCKS versions may be available in the future, depending on demand, and will use different protocol prefixes as described in curl 1 . Provide the hexadecimal (no leading 0x) pre-shared-key matching the one used on the broker to use TLS-PSK encryption support. must also be provided to enable TLS-PSK. The client identity to use with TLS-PSK support. This may be used instead of a username if the broker is configured to do so. Specify the quality of service desired for the incoming messages, from 0, 1 and 2. Defaults to 0. See mqtt7 for more information on QoS. The QoS is identical for all topics subscribed to in a single instance of mosquitto_sub. If this argument is given, no runtime errors will be printed. This excludes any error messages given in case of invalid user input (e.g. using without a port). If this argument is given, messages that are received that have the retain bit set will not be printed. Messages with retain set are "stale", in that it is not known when they were originally published. When subscribing to a wildcard topic there may be a large number of retained messages. This argument suppresses their display. Use SRV lookups to determine which host to connect to. Performs lookups to when used in conjunction with , otherwise uses . The MQTT topic to subscribe to. See mqtt7 for more information on MQTT topics. This option may be repeated to subscribe to multiple topics. Suppress printing of topics that match the filter. This allows subscribing to a wildcard topic and only printing a partial set of the wildcard hierarchy. For example, subscribe to the BBC tree, but suppress output from Radio 3: mosquitto_sub -t bbc/# -T bbc/radio3 This option may be repeated to filter out multiple topics or topic trees. Choose which TLS protocol version to use when communicating with the broker. Valid options are , and . The default value is . If the installed version of openssl is too old, only will be available. Must match the protocol version used by the broker. Provide a username to be used for authenticating with the broker. This requires a broker that supports MQTT v3.1. See also the argument. Print received messages verbosely. With this argument, messages will be printed as "topic payload". When this argument is not given, the messages are printed as "payload". Specify which version of the MQTT protocol should be used when connecting to the rmeote broker. Can be or . Defaults to . Specify a message that will be stored by the broker and sent out if this client disconnects unexpectedly. This must be used in conjunction with . The QoS to use for the Will. Defaults to 0. This must be used in conjunction with . If given, if the client disconnects unexpectedly the message sent out will be treated as a retained message. This must be used in conjunction with . The topic on which to send a Will, in the event that the client disconnects unexpectedly. Wills mosquitto_sub can register a message with the broker that will be sent out if it disconnects unexpectedly. See mqtt7 for more information. The minimum requirement for this is to use to specify which topic the will should be sent out on. This will result in a non-retained, zero length message with QoS 0. Use the , and arguments to modify the other will parameters. Examples Note that these really are examples - the subscriptions will work if you run them as shown, but there must be something publishing messages on those topics for you to receive anything. Subscribe to temperature information on localhost with QoS 1: mosquitto_sub -t sensors/temperature -q 1 Subscribe to hard drive temperature updates on multiple machines/hard drives. This expects each machine to be publishing its hard drive temperature to sensors/machines/HOSTNAME/temperature/HD_NAME. mosquitto_sub -t sensors/machines/+/temperature/+ Subscribe to all broker status messages: mosquitto_sub -v -t \$SYS/# Files $XDG_CONFIG_HOME/mosquitto_sub $HOME/.config/mosquitto_sub Configuration file for default options. Bugs mosquitto bug information can be found at See Also mqtt 7 mosquitto_pub 1 mosquitto 8 libmosquitto 3 mosquitto-tls 7 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/libmosquitto.3.xml0000664000175000017500000005076113245550210017065 0ustar rogerroger libmosquitto 3 Mosquitto Project Library calls libmosquitto MQTT version 3.1 client library Description This is an overview of how to use libmosquitto to create MQTT aware client programs. There may be separate man pages on each of the functions described here in the future. There is also a binding for libmosquitto for C++ and a Python implementation. They are not documented here but operate in a similar way. This is fairly incomplete, please see mosquitto.h for a better description of the functions. libmosquitto symbol names All public functions in libmosquitto have the prefix "mosquitto_". Any other functions defined in the source code are to be treated as private functions and may change between any release. Do not use these functions! Functions Library version int mosquitto_lib_version int *major int *minor int *revision Obtain version information about the library. If any of major, minor or revision are not NULL they will return the corresponding version numbers. The return value is an integer representation of the complete version number (e.g. 1009001 for 1.9.1) that can be used for comparisons. Library initialisation and cleanup int mosquitto_lib_init int mosquitto_lib_cleanup Call mosquitto_lib_init() before using any of the other library functions and mosquitto_lib_cleanup() after finishing with the library. Client constructor/destructor struct mosquitto *mosquitto_new const char *id bool clean_session void *userdata Create a new mosquitto client instance. void mosquitto_destroy struct mosquitto *mosq Use to free memory associated with a mosquitto client instance. int mosquitto_reinitialise struct mosquitto *mosq const char *id bool clean_session void *userdata Authentication and encryption int mosquitto_username_pw_set struct mosquitto *mosq const char *username const char *password int mosquitto_tls_set struct mosquitto *mosq const char *cafile const char *capath const char *certfile const char *keyfile int (*pw_callback)(char *buf, int size, int rwflag, void *userdata) int mosquitto_tls_opts_set struct mosquitto *mosq int cert_reqs const char *tls_version const char *ciphers int mosquitto_tls_insecure_set struct mosquitto *mosq bool value int mosquitto_tls_psk_set struct mosquitto *mosq const char *psk const char *identity const char *ciphers Wills int mosquitto_will_set struct mosquitto *mosq const char *topic int payloadlen const void *payload int qos bool retain int mosquitto_will_clear struct mosquitto *mosq Connect/disconnect int mosquitto_connect struct mosquitto *mosq const char *host int port int keepalive int mosquitto_connect_bind struct mosquitto *mosq const char *host int port int keepalive const char *bind_address int mosquitto_connect_async struct mosquitto *mosq const char *host int port int keepalive int mosquitto_connect_bind_async struct mosquitto *mosq const char *host int port int keepalive const char *bind_address int mosquitto_reconnect struct mosquitto *mosq int mosquitto_reconnect_async struct mosquitto *mosq int mosquitto_disconnect struct mosquitto *mosq Publish int mosquitto_publish struct mosquitto *mosq int *mid const char *topic int payloadlen const void *payload int qos bool retain Subscribe/unsubscribe int mosquitto_subscribe struct mosquitto *mosq int *mid const char *sub int qos int mosquitto_unsubscribe struct mosquitto *mosq int *mid const char *sub Network loop int mosquitto_loop struct mosquitto *mosq int timeout int max_packets int mosquitto_loop_read struct mosquitto *mosq int max_packets int mosquitto_loop_write struct mosquitto *mosq int max_packets int mosquitto_loop_misc struct mosquitto *mosq int mosquitto_loop_forever struct mosquitto *mosq int timeout int max_packets int mosquitto_socket struct mosquitto *mosq bool mosquitto_want_write struct mosquitto *mosq Threaded network loop int mosquitto_loop_start struct mosquitto *mosq int mosquitto_loop_stop struct mosquitto *mosq bool force Misc client functions int mosquitto_max_inflight_messages_set struct mosquitto *mosq unsigned int max_inflight_messages int mosquitto_message_retry_set struct mosquitto *mosq unsigned int message_retry int mosquitto_reconnect_delay_set struct mosquitto *mosq unsigned int reconnect_delay unsigned int reconnect_delay_max bool reconnect_exponential_backoff int mosquitto_user_data_set struct mosquitto *mosq void *userdata Callbacks int mosquitto_connect_callback_set struct mosquitto *mosq void (*on_connect)(struct mosquitto *, void *, int) int mosquitto_disconnect_callback_set struct mosquitto *mosq void (*on_disconnect)(struct mosquitto *, void *, int) int mosquitto_publish_callback_set struct mosquitto *mosq void (*on_publish)(struct mosquitto *, void *, int) int mosquitto_message_callback_set struct mosquitto *mosq void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *) int mosquitto_subscribe_callback_set struct mosquitto *mosq void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *) int mosquitto_unsubscribe_callback_set struct mosquitto *mosq void (*on_unsubscribe)(struct mosquitto *, void *, int) int mosquitto_log_callback_set struct mosquitto *mosq void (*on_unsubscribe)(struct mosquitto *, void *, int, const char *) Utility functions const char *mosquitto_connack_string int connack_code int mosquitto_message_copy struct mosquitto_message *dst const struct mosquitto_message *src int mosquitto_message_free struct mosquitto_message **message const char *mosquitto_strerror int mosq_errno int mosquitto_sub_topic_tokenise const char *subtopic char ***topics int *count int mosquitto_sub_topic_tokens_free char ***topics int count int mosquitto_topic_matches_sub const char *sub const char *topic bool *result Examples #include <stdio.h> #include <mosquitto.h> void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message->payloadlen){ printf("%s %s\n", message->topic, message->payload); }else{ printf("%s (null)\n", message->topic); } fflush(stdout); } void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) { int i; if(!result){ /* Subscribe to broker information topics on successful connect. */ mosquitto_subscribe(mosq, NULL, "$SYS/#", 2); }else{ fprintf(stderr, "Connect failed\n"); } } void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) { int i; printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; i<qos_count; i++){ printf(", %d", granted_qos[i]); } printf("\n"); } void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str) { /* Pring all log messages regardless of level. */ printf("%s\n", str); } int main(int argc, char *argv[]) { int i; char *host = "localhost"; int port = 1883; int keepalive = 60; bool clean_session = true; struct mosquitto *mosq = NULL; mosquitto_lib_init(); mosq = mosquitto_new(NULL, clean_session, NULL); if(!mosq){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); if(mosquitto_connect(mosq, host, port, keepalive)){ fprintf(stderr, "Unable to connect.\n"); return 1; } mosquitto_loop_forever(mosq, -1, 1); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; } See Also mosquitto 8 mqtt 7 Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/mosquitto.8.xml0000664000175000017500000005052713245550210016403 0ustar rogerroger mosquitto 8 Mosquitto Project System management commands mosquitto an MQTT broker mosquitto -c config file -d --daemon -p port number -v Description mosquitto is a broker for the MQTT protocol version 3.1. Options Load configuration from a file. If not given, the default values as described in mosquitto.conf5 are used. Run mosquitto in the background as a daemon. All other behaviour remains the same. Listen on the port specified instead of the default 1883. This acts in addition to the port setting in the config file. May be specified multiple times to open multiple sockets listening on different ports. This socket will be bound to all network interfaces. Use verbose logging. This is equivalent to setting to in the configuration file. This overrides and logging options given in the configuration file. Configuration The broker can be configured using a configuration file as described in mosquitto.conf5 and this is the main point of information for mosquitto. The files required for SSL/TLS support are described in mosquitto-tls7. Broker Status Clients can find information about the broker by subscribing to topics in the $SYS hierarchy as follows. Topics marked as static are only sent once per client on subscription. All other topics are updated every seconds. If is 0, then updates are not sent. Note that if you are using a command line client to interact with the $SYS topics and your shell interprets $ as an environment variable, you need to place the topic in single quotes '$SYS/...' or to escape the dollar symbol: \$SYS/... otherwise the $SYS will be treated as an environment variable. The total number of bytes received since the broker started. The total number of bytes sent since the broker started. (deprecated) The number of currently connected clients. The number of disconnected persistent clients that have been expired and removed through the persistent_client_expiration option. (deprecated) The total number of persistent clients (with clean session disabled) that are registered at the broker but are currently disconnected. The maximum number of clients that have been connected to the broker at the same time. The total number of active and inactive clients currently connected and registered on the broker. When bridges are configured to/from the broker, common practice is to provide a status topic that indicates the state of the connection. This is provided within $SYS/broker/connection/ by default. If the value of the topic is 1 the connection is active, if 0 then it is not active. See the Bridges section below for more information on bridges. The current size of the heap memory in use by mosquitto. Note that this topic may be unavailable depending on compile time options. The largest amount of heap memory used by mosquitto. Note that this topic may be unavailable depending on compile time options. The moving average of the number of CONNECT packets received by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of connections received in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of bytes received by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of bytes received in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of bytes sent by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of bytes sent in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of all types of MQTT messages received by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of messages received in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of all types of MQTT messages sent by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of messages send in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of publish messages dropped by the broker over different time intervals. This shows the rate at which durable clients that are disconnected are losing messages. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of messages dropped in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of publish messages received by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of publish messages received in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of publish messages sent by the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of publish messages sent in 1 minute, averaged over 1, 5 or 15 minutes. The moving average of the number of socket connections opened to the broker over different time intervals. The final "+" of the hierarchy can be 1min, 5min or 15min. The value returned represents the number of socket connections in 1 minute, averaged over 1, 5 or 15 minutes. The number of messages with QoS>0 that are awaiting acknowledgments. The total number of messages of any type received since the broker started. The total number of messages of any type sent since the broker started. The number of messages currently held in the message store. This includes retained messages and messages queued for durable clients. The total number of publish messages that have been dropped due to inflight/queuing limits. See the max_inflight_messages and max_queued_messages options in mosquitto.conf5 for more information. The total number of PUBLISH messages received since the broker started. The total number of PUBLISH messages sent since the broker started. The total number of retained messages active on the broker. The total number of subscriptions active on the broker. The timestamp at which this particular build of the broker was made. Static. The amount of time in seconds the broker has been online. The version of the broker. Static. Wildcard Topic Subscriptions In addition to allowing clients to subscribe to specific topics, mosquitto also allows the use of two wildcards in subscriptions. is the wildcard used to match a single level of hierarchy. For example, for a topic of "a/b/c/d", the following example subscriptions will match: a/b/c/d +/b/c/d a/+/c/d a/+/+/d +/+/+/+ The following subscriptions will not match: a/b/c b/+/c/d +/+/+ The second wildcard is and is used to match all subsequent levels of hierarchy. With a topic of "a/b/c/d", the following example subscriptions will match: a/b/c/d # a/# a/b/# a/b/c/# +/b/c/# The $SYS hierarchy does not match a subscription of "#". If you want to observe the entire $SYS hierarchy, subscribe to $SYS/#. Note that the wildcards must be only ever used on their own, so a subscription of "a/b+/c" is not valid use of a wildcard. The wildcard must only ever be used as the final character of a subscription. Bridges Multiple brokers can be connected together with the bridging functionality. This is useful where it is desirable to share information between locations, but where not all of the information needs to be shared. An example could be where a number of users are running a broker to help record power usage and for a number of other reasons. The power usage could be shared through bridging all of the user brokers to a common broker, allowing the power usage of all users to be collected and compared. The other information would remain local to each broker. For information on configuring bridges, see mosquitto.conf5. Signals SIGHUP Upon receiving the SIGHUP signal, mosquitto will attempt to reload configuration file data, assuming that the argument was provided when mosquitto was started. Not all configuration parameters can be reloaded without restarting. See mosquitto.conf5 for details. SIGUSR1 Upon receiving the SIGUSR1 signal, mosquitto will write the persistence database to disk. This signal is only acted upon if persistence is enabled. SIGUSR2 The SIGUSR2 signal causes mosquitto to print out the current subscription tree, along with information about where retained messages exist. This is intended as a testing feature only and may be removed at any time. Files /etc/mosquitto/mosquitto.conf Configuration file. See mosquitto.conf5. /var/lib/mosquitto/mosquitto.db Persistent message data storage location if persist enabled. /etc/hosts.allow /etc/hosts.deny Host access control via tcp-wrappers as described in hosts_access5. Bugs mosquitto bug information can be found at See Also mqtt 7 mosquitto-tls 7 mosquitto.conf 5 hosts_access 5 mosquitto_passwd 1 mosquitto_pub 1 mosquitto_sub 1 libmosquitto 3 Thanks Thanks to Andy Stanford-Clark for being one of the people who came up with MQTT in the first place. Thanks to Andy and Nicholas O'Leary for providing clarifications of the protocol. Thanks also to everybody at the Ubuntu UK Podcast and Linux Outlaws for organising OggCamp, where Andy gave a talk that inspired mosquitto. Author Roger Light roger@atchoo.org mosquitto-1.4.15/man/mosquitto.80000664000175000017500000003405313245550210015600 0ustar rogerroger'\" t .\" Title: mosquitto .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 02/28/2018 .\" Manual: System management commands .\" Source: Mosquitto Project .\" Language: English .\" .TH "MOSQUITTO" "8" "02/28/2018" "Mosquitto Project" "System management commands" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mosquitto \- an MQTT broker .SH "SYNOPSIS" .HP \w'\fBmosquitto\fR\ 'u \fBmosquitto\fR [\-c\ \fIconfig\ file\fR] [\-d | \-\-daemon] [\-p\ \fIport\ number\fR] [\-v] .SH "DESCRIPTION" .PP \fBmosquitto\fR is a broker for the MQTT protocol version 3\&.1\&. .SH "OPTIONS" .PP \fB\-c\fR, \fB\-\-config\-file\fR .RS 4 Load configuration from a file\&. If not given, the default values as described in \fBmosquitto.conf\fR(5) are used\&. .RE .PP \fB\-d\fR, \fB\-\-daemon\fR .RS 4 Run \fBmosquitto\fR in the background as a daemon\&. All other behaviour remains the same\&. .RE .PP \fB\-p\fR, \fB\-\-port\fR .RS 4 Listen on the port specified instead of the default 1883\&. This acts in addition to the port setting in the config file\&. May be specified multiple times to open multiple sockets listening on different ports\&. This socket will be bound to all network interfaces\&. .RE .PP \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose logging\&. This is equivalent to setting \fBlog_type\fR to \fBall\fR in the configuration file\&. This overrides and logging options given in the configuration file\&. .RE .SH "CONFIGURATION" .PP The broker can be configured using a configuration file as described in \fBmosquitto.conf\fR(5) and this is the main point of information for mosquitto\&. The files required for SSL/TLS support are described in \fBmosquitto-tls\fR(7)\&. .SH "BROKER STATUS" .PP Clients can find information about the broker by subscribing to topics in the $SYS hierarchy as follows\&. Topics marked as static are only sent once per client on subscription\&. All other topics are updated every \fBsys_interval\fR seconds\&. If \fBsys_interval\fR is 0, then updates are not sent\&. .PP Note that if you are using a command line client to interact with the $SYS topics and your shell interprets $ as an environment variable, you need to place the topic in single quotes \*(Aq$SYS/\&.\&.\&.\*(Aq or to escape the dollar symbol: \e$SYS/\&.\&.\&. otherwise the $SYS will be treated as an environment variable\&. .PP \fB$SYS/broker/bytes/received\fR .RS 4 The total number of bytes received since the broker started\&. .RE .PP \fB$SYS/broker/bytes/sent\fR .RS 4 The total number of bytes sent since the broker started\&. .RE .PP \fB$SYS/broker/clients/connected\fR, \fB$SYS/broker/clients/active\fR (deprecated) .RS 4 The number of currently connected clients\&. .RE .PP \fB$SYS/broker/clients/expired\fR .RS 4 The number of disconnected persistent clients that have been expired and removed through the persistent_client_expiration option\&. .RE .PP \fB$SYS/broker/clients/disconnected\fR, \fB$SYS/broker/clients/inactive\fR (deprecated) .RS 4 The total number of persistent clients (with clean session disabled) that are registered at the broker but are currently disconnected\&. .RE .PP \fB$SYS/broker/clients/maximum\fR .RS 4 The maximum number of clients that have been connected to the broker at the same time\&. .RE .PP \fB$SYS/broker/clients/total\fR .RS 4 The total number of active and inactive clients currently connected and registered on the broker\&. .RE .PP \fB$SYS/broker/connection/#\fR .RS 4 When bridges are configured to/from the broker, common practice is to provide a status topic that indicates the state of the connection\&. This is provided within $SYS/broker/connection/ by default\&. If the value of the topic is 1 the connection is active, if 0 then it is not active\&. See the Bridges section below for more information on bridges\&. .RE .PP \fB$SYS/broker/heap/current size\fR .RS 4 The current size of the heap memory in use by mosquitto\&. Note that this topic may be unavailable depending on compile time options\&. .RE .PP \fB$SYS/broker/heap/maximum size\fR .RS 4 The largest amount of heap memory used by mosquitto\&. Note that this topic may be unavailable depending on compile time options\&. .RE .PP \fB$SYS/broker/load/connections/+\fR .RS 4 The moving average of the number of CONNECT packets received by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of connections received in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/bytes/received/+\fR .RS 4 The moving average of the number of bytes received by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of bytes received in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/bytes/sent/+\fR .RS 4 The moving average of the number of bytes sent by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of bytes sent in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/messages/received/+\fR .RS 4 The moving average of the number of all types of MQTT messages received by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of messages received in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/messages/sent/+\fR .RS 4 The moving average of the number of all types of MQTT messages sent by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of messages send in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/publish/dropped/+\fR .RS 4 The moving average of the number of publish messages dropped by the broker over different time intervals\&. This shows the rate at which durable clients that are disconnected are losing messages\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of messages dropped in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/publish/received/+\fR .RS 4 The moving average of the number of publish messages received by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of publish messages received in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/publish/sent/+\fR .RS 4 The moving average of the number of publish messages sent by the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of publish messages sent in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/load/sockets/+\fR .RS 4 The moving average of the number of socket connections opened to the broker over different time intervals\&. The final "+" of the hierarchy can be 1min, 5min or 15min\&. The value returned represents the number of socket connections in 1 minute, averaged over 1, 5 or 15 minutes\&. .RE .PP \fB$SYS/broker/messages/inflight\fR .RS 4 The number of messages with QoS>0 that are awaiting acknowledgments\&. .RE .PP \fB$SYS/broker/messages/received\fR .RS 4 The total number of messages of any type received since the broker started\&. .RE .PP \fB$SYS/broker/messages/sent\fR .RS 4 The total number of messages of any type sent since the broker started\&. .RE .PP \fB$SYS/broker/messages/stored\fR .RS 4 The number of messages currently held in the message store\&. This includes retained messages and messages queued for durable clients\&. .RE .PP \fB$SYS/broker/publish/messages/dropped\fR .RS 4 The total number of publish messages that have been dropped due to inflight/queuing limits\&. See the max_inflight_messages and max_queued_messages options in \fBmosquitto.conf\fR(5) for more information\&. .RE .PP \fB$SYS/broker/publish/messages/received\fR .RS 4 The total number of PUBLISH messages received since the broker started\&. .RE .PP \fB$SYS/broker/publish/messages/sent\fR .RS 4 The total number of PUBLISH messages sent since the broker started\&. .RE .PP \fB$SYS/broker/retained messages/count\fR .RS 4 The total number of retained messages active on the broker\&. .RE .PP \fB$SYS/broker/subscriptions/count\fR .RS 4 The total number of subscriptions active on the broker\&. .RE .PP \fB$SYS/broker/timestamp\fR .RS 4 The timestamp at which this particular build of the broker was made\&. Static\&. .RE .PP \fB$SYS/broker/uptime\fR .RS 4 The amount of time in seconds the broker has been online\&. .RE .PP \fB$SYS/broker/version\fR .RS 4 The version of the broker\&. Static\&. .RE .SH "WILDCARD TOPIC SUBSCRIPTIONS" .PP In addition to allowing clients to subscribe to specific topics, mosquitto also allows the use of two wildcards in subscriptions\&. \fB+\fR is the wildcard used to match a single level of hierarchy\&. For example, for a topic of "a/b/c/d", the following example subscriptions will match: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/b/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/+/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/+/+/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/+/+/+ .RE .PP The following subscriptions will not match: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} b/+/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/+/+ .RE .PP The second wildcard is \fB#\fR and is used to match all subsequent levels of hierarchy\&. With a topic of "a/b/c/d", the following example subscriptions will match: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c/d .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} # .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/# .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/# .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a/b/c/# .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} +/b/c/# .RE .PP The $SYS hierarchy does not match a subscription of "#"\&. If you want to observe the entire $SYS hierarchy, subscribe to $SYS/#\&. .PP Note that the wildcards must be only ever used on their own, so a subscription of "a/b+/c" is not valid use of a wildcard\&. The \fB#\fR wildcard must only ever be used as the final character of a subscription\&. .SH "BRIDGES" .PP Multiple brokers can be connected together with the bridging functionality\&. This is useful where it is desirable to share information between locations, but where not all of the information needs to be shared\&. An example could be where a number of users are running a broker to help record power usage and for a number of other reasons\&. The power usage could be shared through bridging all of the user brokers to a common broker, allowing the power usage of all users to be collected and compared\&. The other information would remain local to each broker\&. .PP For information on configuring bridges, see \fBmosquitto.conf\fR(5)\&. .SH "SIGNALS" .PP SIGHUP .RS 4 Upon receiving the SIGHUP signal, mosquitto will attempt to reload configuration file data, assuming that the \fB\-c\fR argument was provided when mosquitto was started\&. Not all configuration parameters can be reloaded without restarting\&. See \fBmosquitto.conf\fR(5) for details\&. .RE .PP SIGUSR1 .RS 4 Upon receiving the SIGUSR1 signal, mosquitto will write the persistence database to disk\&. This signal is only acted upon if persistence is enabled\&. .RE .PP SIGUSR2 .RS 4 The SIGUSR2 signal causes mosquitto to print out the current subscription tree, along with information about where retained messages exist\&. This is intended as a testing feature only and may be removed at any time\&. .RE .SH "FILES" .PP /etc/mosquitto/mosquitto\&.conf .RS 4 Configuration file\&. See \fBmosquitto.conf\fR(5)\&. .RE .PP /var/lib/mosquitto/mosquitto\&.db .RS 4 Persistent message data storage location if persist enabled\&. .RE .PP /etc/hosts\&.allow, /etc/hosts\&.deny .RS 4 Host access control via tcp\-wrappers as described in \fBhosts_access\fR(5)\&. .RE .SH "BUGS" .PP \fBmosquitto\fR bug information can be found at \m[blue]\fB\%https://github.com/eclipse/mosquitto/issues\fR\m[] .SH "SEE ALSO" \fBmqtt\fR(7), \fBmosquitto-tls\fR(7), \fBmosquitto.conf\fR(5), \fBhosts_access\fR(5), \fBmosquitto_passwd\fR(1), \fBmosquitto_pub\fR(1), \fBmosquitto_sub\fR(1), \fBlibmosquitto\fR(3) .SH "THANKS" .PP Thanks to Andy Stanford\-Clark for being one of the people who came up with MQTT in the first place\&. Thanks to Andy and Nicholas O\*(AqLeary for providing clarifications of the protocol\&. .PP Thanks also to everybody at the Ubuntu UK Podcast and Linux Outlaws for organising OggCamp, where Andy gave a talk that inspired mosquitto\&. .SH "AUTHOR" .PP Roger Light mosquitto-1.4.15/CONTRIBUTING.md0000664000175000017500000000754513245550210015127 0ustar rogerrogerContributing to Mosquitto ========================= Thank you for your interest in this project. Project description: -------------------- The Mosquitto project has been created to provide a light weight, open-source implementation, of an MQTT broker to allow new, existing, and emerging applications for Machine-to-Machine (M2M) and Internet of Things (IoT). - - Source ------ The Mosquitto code is stored in a git repository. - http://github.com/eclipse/mosquitto You can contribute bugfixes and new features by sending pull requests through GitHub. ## Legal In order for your contribution to be accepted, it must comply with the Eclipse Foundation IP policy. Please read the [Eclipse Foundation policy on accepting contributions via Git](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git). 1. Sign the [Eclipse CLA](http://www.eclipse.org/legal/CLA.php) 1. Register for an Eclipse Foundation User ID. You can register [here](https://dev.eclipse.org/site_login/createaccount.php). 2. Log into the [Projects Portal](https://projects.eclipse.org/), and click on the '[Eclipse CLA](https://projects.eclipse.org/user/sign/cla)' link. 2. Go to your [account settings](https://dev.eclipse.org/site_login/myaccount.php#open_tab_accountsettings) and add your GitHub username to your account. 3. Make sure that you _sign-off_ your Git commits in the following format: ``` Signed-off-by: John Smith ``` This is usually at the bottom of the commit message. You can automate this by adding the '-s' flag when you make the commits. e.g. ```git commit -s -m "Adding a cool feature"``` 4. Ensure that the email address that you make your commits with is the same one you used to sign up to the Eclipse Foundation website with. ## Contributing a change 1. [Fork the repository on GitHub](https://github.com/eclipse/mosquitto/fork) 2. Clone the forked repository onto your computer: ``` git clone https://github.com//mosquitto.git ``` 3. If you are adding a new feature, then create a new branch from the latest ```develop``` branch with ```git checkout -b YOUR_BRANCH_NAME origin/develop``` 4. If you are fixing a bug, then create a new branch from the latest ```fixes``` branch with ```git checkout -b YOUR_BRANCH_NAME origin/fixes``` 5. Make your changes 6. Ensure that all new and existing tests pass. 7. Commit the changes into the branch: ``` git commit -s ``` Make sure that your commit message is meaningful and describes your changes correctly. 8. If you have a lot of commits for the change, squash them into a single / few commits. 9. Push the changes in your branch to your forked repository. 10. Finally, go to [https://github.com/eclipse/mosquitto](https://github.com/eclipse/mosquitto) and create a pull request from your "YOUR_BRANCH_NAME" branch to the ```develop``` or ```fixes``` branch as appropriate to request review and merge of the commits in your pushed branch. What happens next depends on the content of the patch. If it is 100% authored by the contributor and is less than 1000 lines (and meets the needs of the project), then it can be pulled into the main repository. If not, more steps are required. These are detailed in the [legal process poster](http://www.eclipse.org/legal/EclipseLegalProcessPoster.pdf). Contact: -------- Contact the project developers via the project's development [mailing list](https://dev.eclipse.org/mailman/listinfo/mosquitto-dev). Search for bugs: ---------------- This project uses [Github](https://github.com/eclipse/mosquitto/issues) to track ongoing development and issues. Create a new bug: ----------------- Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome! - [Create new Paho bug](https://github.com/eclipse/mosquitto/issues) mosquitto-1.4.15/lib/0000775000175000017500000000000013245550210013431 5ustar rogerrogermosquitto-1.4.15/lib/messages_mosq.c0000664000175000017500000002413613245550210016451 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 #include #include #include #include #include #include #include #include void _mosquitto_message_cleanup(struct mosquitto_message_all **message) { struct mosquitto_message_all *msg; if(!message || !*message) return; msg = *message; if(msg->msg.topic) _mosquitto_free(msg->msg.topic); if(msg->msg.payload) _mosquitto_free(msg->msg.payload); _mosquitto_free(msg); } void _mosquitto_message_cleanup_all(struct mosquitto *mosq) { struct mosquitto_message_all *tmp; assert(mosq); while(mosq->in_messages){ tmp = mosq->in_messages->next; _mosquitto_message_cleanup(&mosq->in_messages); mosq->in_messages = tmp; } while(mosq->out_messages){ tmp = mosq->out_messages->next; _mosquitto_message_cleanup(&mosq->out_messages); mosq->out_messages = tmp; } } 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_malloc(src->payloadlen); 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 _mosquitto_message_delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir) { struct mosquitto_message_all *message; int rc; assert(mosq); rc = _mosquitto_message_remove(mosq, mid, dir, &message); if(rc == MOSQ_ERR_SUCCESS){ _mosquitto_message_cleanup(&message); } return rc; } void mosquitto_message_free(struct mosquitto_message **message) { struct mosquitto_message *msg; if(!message || !*message) return; msg = *message; if(msg->topic) _mosquitto_free(msg->topic); if(msg->payload) _mosquitto_free(msg->payload); _mosquitto_free(msg); } /* * Function: _mosquitto_message_queue * * Returns: * 0 - to indicate an outgoing message can be started * 1 - to indicate that the outgoing message queue is full (inflight limit has been reached) */ int _mosquitto_message_queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir) { int rc = 0; /* mosq->*_message_mutex should be locked before entering this function */ assert(mosq); assert(message); if(dir == mosq_md_out){ mosq->out_queue_len++; message->next = NULL; if(mosq->out_messages_last){ mosq->out_messages_last->next = message; }else{ mosq->out_messages = message; } mosq->out_messages_last = message; if(message->msg.qos > 0){ if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){ mosq->inflight_messages++; }else{ rc = 1; } } }else{ mosq->in_queue_len++; message->next = NULL; if(mosq->in_messages_last){ mosq->in_messages_last->next = message; }else{ mosq->in_messages = message; } mosq->in_messages_last = message; } return rc; } void _mosquitto_messages_reconnect_reset(struct mosquitto *mosq) { struct mosquitto_message_all *message; struct mosquitto_message_all *prev = NULL; assert(mosq); pthread_mutex_lock(&mosq->in_message_mutex); message = mosq->in_messages; mosq->in_queue_len = 0; while(message){ mosq->in_queue_len++; message->timestamp = 0; if(message->msg.qos != 2){ if(prev){ prev->next = message->next; _mosquitto_message_cleanup(&message); message = prev; }else{ mosq->in_messages = message->next; _mosquitto_message_cleanup(&message); message = mosq->in_messages; } }else{ /* Message state can be preserved here because it should match * whatever the client has got. */ } prev = message; message = message->next; } mosq->in_messages_last = prev; pthread_mutex_unlock(&mosq->in_message_mutex); pthread_mutex_lock(&mosq->out_message_mutex); mosq->inflight_messages = 0; message = mosq->out_messages; mosq->out_queue_len = 0; while(message){ mosq->out_queue_len++; message->timestamp = 0; if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){ if(message->msg.qos > 0){ mosq->inflight_messages++; } if(message->msg.qos == 1){ message->state = mosq_ms_wait_for_puback; }else if(message->msg.qos == 2){ /* Should be able to preserve state. */ } }else{ message->state = mosq_ms_invalid; } prev = message; message = message->next; } mosq->out_messages_last = prev; pthread_mutex_unlock(&mosq->out_message_mutex); } int _mosquitto_message_remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message) { struct mosquitto_message_all *cur, *prev = NULL; bool found = false; int rc; assert(mosq); assert(message); if(dir == mosq_md_out){ pthread_mutex_lock(&mosq->out_message_mutex); cur = mosq->out_messages; while(cur){ if(cur->msg.mid == mid){ if(prev){ prev->next = cur->next; }else{ mosq->out_messages = cur->next; } *message = cur; mosq->out_queue_len--; if(cur->next == NULL){ mosq->out_messages_last = prev; }else if(!mosq->out_messages){ mosq->out_messages_last = NULL; } if(cur->msg.qos > 0){ mosq->inflight_messages--; } found = true; break; } prev = cur; cur = cur->next; } if(found){ cur = mosq->out_messages; while(cur){ if(mosq->max_inflight_messages == 0 || mosq->inflight_messages < mosq->max_inflight_messages){ if(cur->msg.qos > 0 && cur->state == mosq_ms_invalid){ mosq->inflight_messages++; 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 = _mosquitto_send_publish(mosq, cur->msg.mid, cur->msg.topic, cur->msg.payloadlen, cur->msg.payload, cur->msg.qos, cur->msg.retain, cur->dup); if(rc){ pthread_mutex_unlock(&mosq->out_message_mutex); return rc; } } }else{ pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; } cur = cur->next; } pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; }else{ pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_NOT_FOUND; } }else{ pthread_mutex_lock(&mosq->in_message_mutex); cur = mosq->in_messages; while(cur){ if(cur->msg.mid == mid){ if(prev){ prev->next = cur->next; }else{ mosq->in_messages = cur->next; } *message = cur; mosq->in_queue_len--; if(cur->next == NULL){ mosq->in_messages_last = prev; }else if(!mosq->in_messages){ mosq->in_messages_last = NULL; } found = true; break; } prev = cur; cur = cur->next; } pthread_mutex_unlock(&mosq->in_message_mutex); if(found){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_NOT_FOUND; } } } #ifdef WITH_THREADING void _mosquitto_message_retry_check_actual(struct mosquitto *mosq, struct mosquitto_message_all *messages, pthread_mutex_t *mutex) #else void _mosquitto_message_retry_check_actual(struct mosquitto *mosq, struct mosquitto_message_all *messages) #endif { time_t now = mosquitto_time(); assert(mosq); #ifdef WITH_THREADING pthread_mutex_lock(mutex); #endif while(messages){ if(messages->timestamp + mosq->message_retry < now){ switch(messages->state){ case mosq_ms_wait_for_puback: case mosq_ms_wait_for_pubrec: messages->timestamp = now; messages->dup = true; _mosquitto_send_publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup); break; case mosq_ms_wait_for_pubrel: messages->timestamp = now; messages->dup = true; _mosquitto_send_pubrec(mosq, messages->msg.mid); break; case mosq_ms_wait_for_pubcomp: messages->timestamp = now; messages->dup = true; _mosquitto_send_pubrel(mosq, messages->msg.mid); break; default: break; } } messages = messages->next; } #ifdef WITH_THREADING pthread_mutex_unlock(mutex); #endif } void _mosquitto_message_retry_check(struct mosquitto *mosq) { #ifdef WITH_THREADING _mosquitto_message_retry_check_actual(mosq, mosq->out_messages, &mosq->out_message_mutex); _mosquitto_message_retry_check_actual(mosq, mosq->in_messages, &mosq->in_message_mutex); #else _mosquitto_message_retry_check_actual(mosq, mosq->out_messages); _mosquitto_message_retry_check_actual(mosq, mosq->in_messages); #endif } void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry) { assert(mosq); if(mosq) mosq->message_retry = message_retry; } int _mosquitto_message_out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state) { struct mosquitto_message_all *message; assert(mosq); pthread_mutex_lock(&mosq->out_message_mutex); message = mosq->out_messages; while(message){ if(message->msg.mid == mid){ message->state = state; message->timestamp = mosquitto_time(); pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; } message = message->next; } pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_NOT_FOUND; } int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages) { if(!mosq) return MOSQ_ERR_INVAL; mosq->max_inflight_messages = max_inflight_messages; return MOSQ_ERR_SUCCESS; } mosquitto-1.4.15/lib/net_mosq.h0000664000175000017500000000675213245550210015441 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 _NET_MOSQ_H_ #define _NET_MOSQ_H_ #ifndef WIN32 #include #else #include typedef int ssize_t; #endif #include #include #ifdef WITH_BROKER struct mosquitto_db; #endif #ifdef WIN32 # define COMPAT_CLOSE(a) closesocket(a) # define COMPAT_ECONNRESET WSAECONNRESET # define COMPAT_EWOULDBLOCK WSAEWOULDBLOCK #else # define COMPAT_CLOSE(a) close(a) # define COMPAT_ECONNRESET ECONNRESET # define COMPAT_EWOULDBLOCK EWOULDBLOCK #endif /* For when not using winsock libraries. */ #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif /* Macros for accessing the MSB and LSB of a uint16_t */ #define MOSQ_MSB(A) (uint8_t)((A & 0xFF00) >> 8) #define MOSQ_LSB(A) (uint8_t)(A & 0x00FF) void _mosquitto_net_init(void); void _mosquitto_net_cleanup(void); void _mosquitto_packet_cleanup(struct _mosquitto_packet *packet); int _mosquitto_packet_queue(struct mosquitto *mosq, struct _mosquitto_packet *packet); int _mosquitto_socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking); #ifdef WITH_BROKER int _mosquitto_socket_close(struct mosquitto_db *db, struct mosquitto *mosq); #else int _mosquitto_socket_close(struct mosquitto *mosq); #endif int _mosquitto_try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking); int _mosquitto_try_connect_step1(struct mosquitto *mosq, const char *host); int _mosquitto_try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock); int _mosquitto_socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking); int _mosquitto_socket_nonblock(mosq_sock_t sock); int _mosquitto_socketpair(mosq_sock_t *sp1, mosq_sock_t *sp2); int _mosquitto_read_byte(struct _mosquitto_packet *packet, uint8_t *byte); int _mosquitto_read_bytes(struct _mosquitto_packet *packet, void *bytes, uint32_t count); int _mosquitto_read_string(struct _mosquitto_packet *packet, char **str); int _mosquitto_read_uint16(struct _mosquitto_packet *packet, uint16_t *word); void _mosquitto_write_byte(struct _mosquitto_packet *packet, uint8_t byte); void _mosquitto_write_bytes(struct _mosquitto_packet *packet, const void *bytes, uint32_t count); void _mosquitto_write_string(struct _mosquitto_packet *packet, const char *str, uint16_t length); void _mosquitto_write_uint16(struct _mosquitto_packet *packet, uint16_t word); ssize_t _mosquitto_net_read(struct mosquitto *mosq, void *buf, size_t count); ssize_t _mosquitto_net_write(struct mosquitto *mosq, void *buf, size_t count); int _mosquitto_packet_write(struct mosquitto *mosq); #ifdef WITH_BROKER int _mosquitto_packet_read(struct mosquitto_db *db, struct mosquitto *mosq); #else int _mosquitto_packet_read(struct mosquitto *mosq); #endif #ifdef WITH_TLS int _mosquitto_socket_apply_tls(struct mosquitto *mosq); int mosquitto__socket_connect_tls(struct mosquitto *mosq); #endif #endif mosquitto-1.4.15/lib/send_client_mosq.c0000664000175000017500000001466713245550210017141 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include #include #include #ifdef WITH_BROKER #include #endif int _mosquitto_send_connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session) { struct _mosquitto_packet *packet = NULL; int payloadlen; uint8_t will = 0; uint8_t byte; int rc; uint8_t version; char *clientid, *username, *password; int headerlen; assert(mosq); assert(mosq->id); #if defined(WITH_BROKER) && defined(WITH_BRIDGE) if(mosq->bridge){ clientid = mosq->bridge->remote_clientid; username = mosq->bridge->remote_username; password = mosq->bridge->remote_password; }else{ clientid = mosq->id; username = mosq->username; password = mosq->password; } #else clientid = mosq->id; username = mosq->username; password = mosq->password; #endif if(mosq->protocol == mosq_p_mqtt31){ version = MQTT_PROTOCOL_V31; headerlen = 12; }else if(mosq->protocol == mosq_p_mqtt311){ version = MQTT_PROTOCOL_V311; headerlen = 10; }else{ return MOSQ_ERR_INVAL; } packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; payloadlen = 2+strlen(clientid); if(mosq->will){ will = 1; assert(mosq->will->topic); payloadlen += 2+strlen(mosq->will->topic) + 2+mosq->will->payloadlen; } if(username){ payloadlen += 2+strlen(username); if(password){ payloadlen += 2+strlen(password); } } packet->command = CONNECT; packet->remaining_length = headerlen+payloadlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header */ if(version == MQTT_PROTOCOL_V31){ _mosquitto_write_string(packet, PROTOCOL_NAME_v31, strlen(PROTOCOL_NAME_v31)); }else if(version == MQTT_PROTOCOL_V311){ _mosquitto_write_string(packet, PROTOCOL_NAME_v311, strlen(PROTOCOL_NAME_v311)); } #if defined(WITH_BROKER) && defined(WITH_BRIDGE) if(mosq->bridge && mosq->bridge->try_private && mosq->bridge->try_private_accepted){ version |= 0x80; }else{ } #endif _mosquitto_write_byte(packet, version); byte = (clean_session&0x1)<<1; if(will){ byte = byte | ((mosq->will->retain&0x1)<<5) | ((mosq->will->qos&0x3)<<3) | ((will&0x1)<<2); } if(username){ byte = byte | 0x1<<7; if(mosq->password){ byte = byte | 0x1<<6; } } _mosquitto_write_byte(packet, byte); _mosquitto_write_uint16(packet, keepalive); /* Payload */ _mosquitto_write_string(packet, clientid, strlen(clientid)); if(will){ _mosquitto_write_string(packet, mosq->will->topic, strlen(mosq->will->topic)); _mosquitto_write_string(packet, (const char *)mosq->will->payload, mosq->will->payloadlen); } if(username){ _mosquitto_write_string(packet, username, strlen(username)); if(password){ _mosquitto_write_string(packet, password, strlen(password)); } } mosq->keepalive = keepalive; #ifdef WITH_BROKER # ifdef WITH_BRIDGE _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending CONNECT", clientid); # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending CONNECT", clientid); #endif return _mosquitto_packet_queue(mosq, packet); } int _mosquitto_send_disconnect(struct mosquitto *mosq) { assert(mosq); #ifdef WITH_BROKER # ifdef WITH_BRIDGE _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending DISCONNECT", mosq->id); # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending DISCONNECT", mosq->id); #endif return _mosquitto_send_simple_command(mosq, DISCONNECT); } int _mosquitto_send_subscribe(struct mosquitto *mosq, int *mid, const char *topic, uint8_t topic_qos) { /* FIXME - only deals with a single topic */ struct _mosquitto_packet *packet = NULL; uint32_t packetlen; uint16_t local_mid; int rc; assert(mosq); assert(topic); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packetlen = 2 + 2+strlen(topic) + 1; packet->command = SUBSCRIBE | (1<<1); packet->remaining_length = packetlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header */ local_mid = _mosquitto_mid_generate(mosq); if(mid) *mid = (int)local_mid; _mosquitto_write_uint16(packet, local_mid); /* Payload */ _mosquitto_write_string(packet, topic, strlen(topic)); _mosquitto_write_byte(packet, topic_qos); #ifdef WITH_BROKER # ifdef WITH_BRIDGE _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic, topic_qos); # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic, topic_qos); #endif return _mosquitto_packet_queue(mosq, packet); } int _mosquitto_send_unsubscribe(struct mosquitto *mosq, int *mid, const char *topic) { /* FIXME - only deals with a single topic */ struct _mosquitto_packet *packet = NULL; uint32_t packetlen; uint16_t local_mid; int rc; assert(mosq); assert(topic); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packetlen = 2 + 2+strlen(topic); packet->command = UNSUBSCRIBE | (1<<1); packet->remaining_length = packetlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header */ local_mid = _mosquitto_mid_generate(mosq); if(mid) *mid = (int)local_mid; _mosquitto_write_uint16(packet, local_mid); /* Payload */ _mosquitto_write_string(packet, topic, strlen(topic)); #ifdef WITH_BROKER # ifdef WITH_BRIDGE _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic); # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic); #endif return _mosquitto_packet_queue(mosq, packet); } mosquitto-1.4.15/lib/send_mosq.h0000664000175000017500000000345113245550210015575 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 _SEND_MOSQ_H_ #define _SEND_MOSQ_H_ #include int _mosquitto_send_simple_command(struct mosquitto *mosq, uint8_t command); int _mosquitto_send_command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup); int _mosquitto_send_real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup); int _mosquitto_send_connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session); int _mosquitto_send_disconnect(struct mosquitto *mosq); int _mosquitto_send_pingreq(struct mosquitto *mosq); int _mosquitto_send_pingresp(struct mosquitto *mosq); int _mosquitto_send_puback(struct mosquitto *mosq, uint16_t mid); int _mosquitto_send_pubcomp(struct mosquitto *mosq, uint16_t mid); int _mosquitto_send_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup); int _mosquitto_send_pubrec(struct mosquitto *mosq, uint16_t mid); int _mosquitto_send_pubrel(struct mosquitto *mosq, uint16_t mid); int _mosquitto_send_subscribe(struct mosquitto *mosq, int *mid, const char *topic, uint8_t topic_qos); int _mosquitto_send_unsubscribe(struct mosquitto *mosq, int *mid, const char *topic); #endif mosquitto-1.4.15/lib/cpp/0000775000175000017500000000000013245550210014213 5ustar rogerrogermosquitto-1.4.15/lib/cpp/mosquittopp.h0000664000175000017500000001027413245550210016774 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 MOSQUITTOPP_H #define MOSQUITTOPP_H #ifdef _WIN32 # ifdef mosquittopp_EXPORTS # define mosqpp_EXPORT __declspec(dllexport) # else # define mosqpp_EXPORT __declspec(dllimport) # endif #else # define mosqpp_EXPORT #endif #include #include #include namespace mosqpp { mosqpp_EXPORT const char *strerror(int mosq_errno); mosqpp_EXPORT const char *connack_string(int connack_code); mosqpp_EXPORT int sub_topic_tokenise(const char *subtopic, char ***topics, int *count); mosqpp_EXPORT int sub_topic_tokens_free(char ***topics, int count); mosqpp_EXPORT int lib_version(int *major, int *minor, int *revision); mosqpp_EXPORT int lib_init(); mosqpp_EXPORT int lib_cleanup(); mosqpp_EXPORT int topic_matches_sub(const char *sub, const char *topic, bool *result); /* * Class: mosquittopp * * A mosquitto client class. This is a C++ wrapper class for the mosquitto C * library. Please see mosquitto.h for details of the functions. */ class mosqpp_EXPORT mosquittopp { private: struct mosquitto *m_mosq; public: mosquittopp(const char *id=NULL, bool clean_session=true); virtual ~mosquittopp(); int reinitialise(const char *id, bool clean_session); int socket(); int will_set(const char *topic, int payloadlen=0, const void *payload=NULL, int qos=0, bool retain=false); int will_clear(); int username_pw_set(const char *username, const char *password=NULL); int connect(const char *host, int port=1883, int keepalive=60); int connect_async(const char *host, int port=1883, int keepalive=60); int connect(const char *host, int port, int keepalive, const char *bind_address); int connect_async(const char *host, int port, int keepalive, const char *bind_address); int reconnect(); int reconnect_async(); int disconnect(); int publish(int *mid, const char *topic, int payloadlen=0, const void *payload=NULL, int qos=0, bool retain=false); int subscribe(int *mid, const char *sub, int qos=0); int unsubscribe(int *mid, const char *sub); void reconnect_delay_set(unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); int max_inflight_messages_set(unsigned int max_inflight_messages); void message_retry_set(unsigned int message_retry); void user_data_set(void *userdata); int tls_set(const char *cafile, const char *capath=NULL, const char *certfile=NULL, const char *keyfile=NULL, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)=NULL); int tls_opts_set(int cert_reqs, const char *tls_version=NULL, const char *ciphers=NULL); int tls_insecure_set(bool value); int tls_psk_set(const char *psk, const char *identity, const char *ciphers=NULL); int opts_set(enum mosq_opt_t option, void *value); int loop(int timeout=-1, int max_packets=1); int loop_misc(); int loop_read(int max_packets=1); int loop_write(int max_packets=1); int loop_forever(int timeout=-1, int max_packets=1); int loop_start(); int loop_stop(bool force=false); bool want_write(); int threaded_set(bool threaded=true); int socks5_set(const char *host, int port=1080, const char *username=NULL, const char *password=NULL); // names in the functions commented to prevent unused parameter warning virtual void on_connect(int /*rc*/) {return;} virtual void on_disconnect(int /*rc*/) {return;} virtual void on_publish(int /*mid*/) {return;} virtual void on_message(const struct mosquitto_message * /*message*/) {return;} virtual void on_subscribe(int /*mid*/, int /*qos_count*/, const int * /*granted_qos*/) {return;} virtual void on_unsubscribe(int /*mid*/) {return;} virtual void on_log(int /*level*/, const char * /*str*/) {return;} virtual void on_error() {return;} }; } #endif mosquitto-1.4.15/lib/cpp/CMakeLists.txt0000664000175000017500000000110213245550210016745 0ustar rogerrogerinclude_directories(${mosquitto_SOURCE_DIR}/lib ${mosquitto_SOURCE_DIR}/lib/cpp ${STDBOOL_H_PATH} ${STDINT_H_PATH}) link_directories(${mosquitto_BINARY_DIR}/lib) add_library(mosquittopp SHARED mosquittopp.cpp mosquittopp.h) target_link_libraries(mosquittopp libmosquitto) set_target_properties(mosquittopp PROPERTIES VERSION ${VERSION} SOVERSION 1 ) install(TARGETS mosquittopp RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") install(FILES mosquittopp.h DESTINATION "${INCLUDEDIR}") if (UNIX) install(CODE "EXEC_PROGRAM(/sbin/ldconfig)") endif (UNIX) mosquitto-1.4.15/lib/cpp/Makefile0000664000175000017500000000212013245550210015646 0ustar rogerrogerinclude ../../config.mk ifneq ($(UNAME),SunOS) LIB_LDFLAGS:=$(LDFLAGS) -Wl,-soname,libmosquittopp.so.${SOVERSION} endif .PHONY : clean install all : libmosquittopp.so.${SOVERSION} install : all $(INSTALL) -d ${DESTDIR}$(prefix)/lib${LIB_SUFFIX}/ $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} libmosquittopp.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so.${SOVERSION} ln -sf libmosquittopp.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so $(INSTALL) -d ${DESTDIR}${prefix}/include/ $(INSTALL) mosquittopp.h ${DESTDIR}${prefix}/include/mosquittopp.h uninstall : -rm -f ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so.${SOVERSION} -rm -f ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so -rm -f ${DESTDIR}${prefix}/include/mosquittopp.h clean : -rm -f *.o libmosquittopp.so.${SOVERSION} libmosquittopp.so.${SOVERSION} : mosquittopp.o ${CROSS_COMPILE}$(CXX) -shared $(LIB_LDFLAGS) $< -o $@ ../libmosquitto.so.${SOVERSION} mosquittopp.o : mosquittopp.cpp mosquittopp.h ${CROSS_COMPILE}$(CXX) $(LIB_CXXFLAGS) -c $< -o $@ mosquitto-1.4.15/lib/cpp/mosquittopp.cpp0000664000175000017500000002010613245550210017322 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 #include #include namespace mosqpp { static void on_connect_wrapper(struct mosquitto *mosq, void *userdata, int rc) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_connect(rc); } static void on_disconnect_wrapper(struct mosquitto *mosq, void *userdata, int rc) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_disconnect(rc); } static void on_publish_wrapper(struct mosquitto *mosq, void *userdata, int mid) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_publish(mid); } static void on_message_wrapper(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_message(message); } static void on_subscribe_wrapper(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_subscribe(mid, qos_count, granted_qos); } static void on_unsubscribe_wrapper(struct mosquitto *mosq, void *userdata, int mid) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_unsubscribe(mid); } static void on_log_wrapper(struct mosquitto *mosq, void *userdata, int level, const char *str) { class mosquittopp *m = (class mosquittopp *)userdata; m->on_log(level, str); } int 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 lib_init() { return mosquitto_lib_init(); } int lib_cleanup() { return mosquitto_lib_cleanup(); } const char* strerror(int mosq_errno) { return mosquitto_strerror(mosq_errno); } const char* connack_string(int connack_code) { return mosquitto_connack_string(connack_code); } int sub_topic_tokenise(const char *subtopic, char ***topics, int *count) { return mosquitto_sub_topic_tokenise(subtopic, topics, count); } int sub_topic_tokens_free(char ***topics, int count) { return mosquitto_sub_topic_tokens_free(topics, count); } int topic_matches_sub(const char *sub, const char *topic, bool *result) { return mosquitto_topic_matches_sub(sub, topic, result); } mosquittopp::mosquittopp(const char *id, bool clean_session) { m_mosq = mosquitto_new(id, clean_session, this); mosquitto_connect_callback_set(m_mosq, on_connect_wrapper); mosquitto_disconnect_callback_set(m_mosq, on_disconnect_wrapper); mosquitto_publish_callback_set(m_mosq, on_publish_wrapper); mosquitto_message_callback_set(m_mosq, on_message_wrapper); mosquitto_subscribe_callback_set(m_mosq, on_subscribe_wrapper); mosquitto_unsubscribe_callback_set(m_mosq, on_unsubscribe_wrapper); mosquitto_log_callback_set(m_mosq, on_log_wrapper); } mosquittopp::~mosquittopp() { mosquitto_destroy(m_mosq); } int mosquittopp::reinitialise(const char *id, bool clean_session) { int rc; rc = mosquitto_reinitialise(m_mosq, id, clean_session, this); if(rc == MOSQ_ERR_SUCCESS){ mosquitto_connect_callback_set(m_mosq, on_connect_wrapper); mosquitto_disconnect_callback_set(m_mosq, on_disconnect_wrapper); mosquitto_publish_callback_set(m_mosq, on_publish_wrapper); mosquitto_message_callback_set(m_mosq, on_message_wrapper); mosquitto_subscribe_callback_set(m_mosq, on_subscribe_wrapper); mosquitto_unsubscribe_callback_set(m_mosq, on_unsubscribe_wrapper); mosquitto_log_callback_set(m_mosq, on_log_wrapper); } return rc; } int mosquittopp::connect(const char *host, int port, int keepalive) { return mosquitto_connect(m_mosq, host, port, keepalive); } int mosquittopp::connect(const char *host, int port, int keepalive, const char *bind_address) { return mosquitto_connect_bind(m_mosq, host, port, keepalive, bind_address); } int mosquittopp::connect_async(const char *host, int port, int keepalive) { return mosquitto_connect_async(m_mosq, host, port, keepalive); } int mosquittopp::connect_async(const char *host, int port, int keepalive, const char *bind_address) { return mosquitto_connect_bind_async(m_mosq, host, port, keepalive, bind_address); } int mosquittopp::reconnect() { return mosquitto_reconnect(m_mosq); } int mosquittopp::reconnect_async() { return mosquitto_reconnect_async(m_mosq); } int mosquittopp::disconnect() { return mosquitto_disconnect(m_mosq); } int mosquittopp::socket() { return mosquitto_socket(m_mosq); } int mosquittopp::will_set(const char *topic, int payloadlen, const void *payload, int qos, bool retain) { return mosquitto_will_set(m_mosq, topic, payloadlen, payload, qos, retain); } int mosquittopp::will_clear() { return mosquitto_will_clear(m_mosq); } int mosquittopp::username_pw_set(const char *username, const char *password) { return mosquitto_username_pw_set(m_mosq, username, password); } int mosquittopp::publish(int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { return mosquitto_publish(m_mosq, mid, topic, payloadlen, payload, qos, retain); } void mosquittopp::reconnect_delay_set(unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff) { mosquitto_reconnect_delay_set(m_mosq, reconnect_delay, reconnect_delay_max, reconnect_exponential_backoff); } int mosquittopp::max_inflight_messages_set(unsigned int max_inflight_messages) { return mosquitto_max_inflight_messages_set(m_mosq, max_inflight_messages); } void mosquittopp::message_retry_set(unsigned int message_retry) { mosquitto_message_retry_set(m_mosq, message_retry); } int mosquittopp::subscribe(int *mid, const char *sub, int qos) { return mosquitto_subscribe(m_mosq, mid, sub, qos); } int mosquittopp::unsubscribe(int *mid, const char *sub) { return mosquitto_unsubscribe(m_mosq, mid, sub); } int mosquittopp::loop(int timeout, int max_packets) { return mosquitto_loop(m_mosq, timeout, max_packets); } int mosquittopp::loop_misc() { return mosquitto_loop_misc(m_mosq); } int mosquittopp::loop_read(int max_packets) { return mosquitto_loop_read(m_mosq, max_packets); } int mosquittopp::loop_write(int max_packets) { return mosquitto_loop_write(m_mosq, max_packets); } int mosquittopp::loop_forever(int timeout, int max_packets) { return mosquitto_loop_forever(m_mosq, timeout, max_packets); } int mosquittopp::loop_start() { return mosquitto_loop_start(m_mosq); } int mosquittopp::loop_stop(bool force) { return mosquitto_loop_stop(m_mosq, force); } bool mosquittopp::want_write() { return mosquitto_want_write(m_mosq); } int mosquittopp::opts_set(enum mosq_opt_t option, void *value) { return mosquitto_opts_set(m_mosq, option, value); } int mosquittopp::threaded_set(bool threaded) { return mosquitto_threaded_set(m_mosq, threaded); } void mosquittopp::user_data_set(void *userdata) { mosquitto_user_data_set(m_mosq, userdata); } int mosquittopp::socks5_set(const char *host, int port, const char *username, const char *password) { return mosquitto_socks5_set(m_mosq, host, port, username, password); } int mosquittopp::tls_set(const char *cafile, const char *capath, const char *certfile, const char *keyfile, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)) { return mosquitto_tls_set(m_mosq, cafile, capath, certfile, keyfile, pw_callback); } int mosquittopp::tls_opts_set(int cert_reqs, const char *tls_version, const char *ciphers) { return mosquitto_tls_opts_set(m_mosq, cert_reqs, tls_version, ciphers); } int mosquittopp::tls_insecure_set(bool value) { return mosquitto_tls_insecure_set(m_mosq, value); } int mosquittopp::tls_psk_set(const char *psk, const char *identity, const char *ciphers) { return mosquitto_tls_psk_set(m_mosq, psk, identity, ciphers); } } mosquitto-1.4.15/lib/net_mosq.c0000664000175000017500000010227213245550210015426 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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. */ #define _GNU_SOURCE #include #include #include #include #include #ifndef WIN32 #define _GNU_SOURCE #include #include #include #else #include #include #endif #ifdef __ANDROID__ #include #include #include #endif #ifdef __FreeBSD__ # include #endif #ifdef __SYMBIAN32__ #include #endif #ifdef __QNX__ #ifndef AI_ADDRCONFIG #define AI_ADDRCONFIG 0 #endif #include #include #endif #ifdef WITH_TLS #include #include #include #include #endif #ifdef WITH_BROKER # include # ifdef WITH_SYS_TREE extern uint64_t g_bytes_received; extern uint64_t g_bytes_sent; extern unsigned long g_msgs_received; extern unsigned long g_msgs_sent; extern unsigned long g_pub_msgs_received; extern unsigned long g_pub_msgs_sent; # endif # ifdef WITH_WEBSOCKETS # include # endif #else # include #endif #include #include #include #include #include #include #include "config.h" #ifdef WITH_TLS int tls_ex_index_mosq = -1; #endif void _mosquitto_net_init(void) { #ifdef WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); #endif #ifdef WITH_SRV ares_library_init(ARES_LIB_INIT_ALL); #endif #ifdef WITH_TLS SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); if(tls_ex_index_mosq == -1){ tls_ex_index_mosq = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL); } #endif } void _mosquitto_net_cleanup(void) { #ifdef WITH_TLS #if OPENSSL_VERSION_NUMBER < 0x10100000L ERR_remove_state(0); #endif ENGINE_cleanup(); CONF_modules_unload(1); ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif #ifdef WITH_SRV ares_library_cleanup(); #endif #ifdef WIN32 WSACleanup(); #endif } void _mosquitto_packet_cleanup(struct _mosquitto_packet *packet) { if(!packet) return; /* Free data and reset values */ packet->command = 0; packet->remaining_count = 0; packet->remaining_mult = 1; packet->remaining_length = 0; if(packet->payload) _mosquitto_free(packet->payload); packet->payload = NULL; packet->to_process = 0; packet->pos = 0; } int _mosquitto_packet_queue(struct mosquitto *mosq, struct _mosquitto_packet *packet) { #ifndef WITH_BROKER char sockpair_data = 0; #endif assert(mosq); assert(packet); packet->pos = 0; packet->to_process = packet->packet_length; packet->next = NULL; pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet){ mosq->out_packet_last->next = packet; }else{ mosq->out_packet = packet; } mosq->out_packet_last = packet; pthread_mutex_unlock(&mosq->out_packet_mutex); #ifdef WITH_BROKER # ifdef WITH_WEBSOCKETS if(mosq->wsi){ libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); return 0; }else{ return _mosquitto_packet_write(mosq); } # else return _mosquitto_packet_write(mosq); # endif #else /* Write a single byte to sockpairW (connected to sockpairR) to break out * of select() if in threaded mode. */ if(mosq->sockpairW != INVALID_SOCKET){ #ifndef WIN32 if(write(mosq->sockpairW, &sockpair_data, 1)){ } #else send(mosq->sockpairW, &sockpair_data, 1, 0); #endif } if(mosq->in_callback == false && mosq->threaded == mosq_ts_none){ return _mosquitto_packet_write(mosq); }else{ return MOSQ_ERR_SUCCESS; } #endif } /* Close a socket associated with a context and set it to -1. * Returns 1 on failure (context is NULL) * Returns 0 on success. */ #ifdef WITH_BROKER int _mosquitto_socket_close(struct mosquitto_db *db, struct mosquitto *mosq) #else int _mosquitto_socket_close(struct mosquitto *mosq) #endif { int rc = 0; assert(mosq); #ifdef WITH_TLS #ifdef WITH_WEBSOCKETS if(!mosq->wsi) #endif { if(mosq->ssl){ SSL_shutdown(mosq->ssl); SSL_free(mosq->ssl); mosq->ssl = NULL; } if(mosq->ssl_ctx){ SSL_CTX_free(mosq->ssl_ctx); mosq->ssl_ctx = NULL; } } #endif #ifdef WITH_WEBSOCKETS if(mosq->wsi) { if(mosq->state != mosq_cs_disconnecting){ mosq->state = mosq_cs_disconnect_ws; } libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); }else #endif { if((int)mosq->sock >= 0){ #ifdef WITH_BROKER HASH_DELETE(hh_sock, db->contexts_by_sock, mosq); #endif rc = COMPAT_CLOSE(mosq->sock); mosq->sock = INVALID_SOCKET; } } #ifdef WITH_BROKER if(mosq->listener){ mosq->listener->client_count--; assert(mosq->listener->client_count >= 0); mosq->listener = NULL; } #endif return rc; } #ifdef REAL_WITH_TLS_PSK static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { struct mosquitto *mosq; int len; mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq); if(!mosq) return 0; snprintf(identity, max_identity_len, "%s", mosq->tls_psk_identity); len = _mosquitto_hex2bin(mosq->tls_psk, psk, max_psk_len); if (len < 0) return 0; return len; } #endif #if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS) /* Async connect, part 1 (dns lookup) */ int _mosquitto_try_connect_step1(struct mosquitto *mosq, const char *host) { int s; void *sevp = NULL; if(mosq->adns){ _mosquitto_free(mosq->adns); } mosq->adns = _mosquitto_calloc(1, sizeof(struct gaicb)); if(!mosq->adns){ return MOSQ_ERR_NOMEM; } mosq->adns->ar_name = host; s = getaddrinfo_a(GAI_NOWAIT, &mosq->adns, 1, sevp); if(s){ errno = s; _mosquitto_free(mosq->adns); mosq->adns = NULL; return MOSQ_ERR_EAI; } return MOSQ_ERR_SUCCESS; } /* Async connect part 2, the connection. */ int _mosquitto_try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock) { struct addrinfo *ainfo, *rp; int rc; ainfo = mosq->adns->ar_result; for(rp = ainfo; rp != NULL; rp = rp->ai_next){ *sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(*sock == INVALID_SOCKET) continue; if(rp->ai_family == PF_INET){ ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port); }else if(rp->ai_family == PF_INET6){ ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port); }else{ COMPAT_CLOSE(*sock); continue; } /* Set non-blocking */ if(_mosquitto_socket_nonblock(*sock)){ continue; } rc = connect(*sock, rp->ai_addr, rp->ai_addrlen); #ifdef WIN32 errno = WSAGetLastError(); #endif if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){ if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){ rc = MOSQ_ERR_CONN_PENDING; } /* Set non-blocking */ if(_mosquitto_socket_nonblock(*sock)){ continue; } break; } COMPAT_CLOSE(*sock); *sock = INVALID_SOCKET; } freeaddrinfo(mosq->adns->ar_result); mosq->adns->ar_result = NULL; _mosquitto_free(mosq->adns); mosq->adns = NULL; if(!rp){ return MOSQ_ERR_ERRNO; } return rc; } #endif int _mosquitto_try_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking) { struct addrinfo hints; struct addrinfo *ainfo, *rp; struct addrinfo *ainfo_bind, *rp_bind; int s; int rc = MOSQ_ERR_SUCCESS; #ifdef WIN32 uint32_t val = 1; #endif *sock = INVALID_SOCKET; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; s = getaddrinfo(host, NULL, &hints, &ainfo); if(s){ errno = s; return MOSQ_ERR_EAI; } if(bind_address){ s = getaddrinfo(bind_address, NULL, &hints, &ainfo_bind); if(s){ freeaddrinfo(ainfo); errno = s; return MOSQ_ERR_EAI; } } for(rp = ainfo; rp != NULL; rp = rp->ai_next){ *sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(*sock == INVALID_SOCKET) continue; if(rp->ai_family == PF_INET){ ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port); }else if(rp->ai_family == PF_INET6){ ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port); }else{ COMPAT_CLOSE(*sock); continue; } if(bind_address){ for(rp_bind = ainfo_bind; rp_bind != NULL; rp_bind = rp_bind->ai_next){ if(bind(*sock, rp_bind->ai_addr, rp_bind->ai_addrlen) == 0){ break; } } if(!rp_bind){ COMPAT_CLOSE(*sock); continue; } } if(!blocking){ /* Set non-blocking */ if(_mosquitto_socket_nonblock(*sock)){ continue; } } rc = connect(*sock, rp->ai_addr, rp->ai_addrlen); #ifdef WIN32 errno = WSAGetLastError(); #endif if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){ if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){ rc = MOSQ_ERR_CONN_PENDING; } if(blocking){ /* Set non-blocking */ if(_mosquitto_socket_nonblock(*sock)){ continue; } } break; } COMPAT_CLOSE(*sock); *sock = INVALID_SOCKET; } freeaddrinfo(ainfo); if(bind_address){ freeaddrinfo(ainfo_bind); } if(!rp){ return MOSQ_ERR_ERRNO; } return rc; } #ifdef WITH_TLS int mosquitto__socket_connect_tls(struct mosquitto *mosq) { int ret, err; ERR_clear_error(); ret = SSL_connect(mosq->ssl); if(ret != 1) { err = SSL_get_error(mosq->ssl, ret); #ifdef WIN32 if (err == SSL_ERROR_SYSCALL) { mosq->want_connect = true; return MOSQ_ERR_SUCCESS; } #endif if(err == SSL_ERROR_WANT_READ){ mosq->want_connect = true; /* We always try to read anyway */ }else if(err == SSL_ERROR_WANT_WRITE){ mosq->want_write = true; mosq->want_connect = true; }else{ COMPAT_CLOSE(mosq->sock); mosq->sock = INVALID_SOCKET; return MOSQ_ERR_TLS; } }else{ mosq->want_connect = false; } return MOSQ_ERR_SUCCESS; } #endif int _mosquitto_socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking) { #ifdef WITH_TLS int ret; BIO *bio; #endif #ifdef WITH_TLS if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){ #if OPENSSL_VERSION_NUMBER >= 0x10001000L if(!mosq->tls_version || !strcmp(mosq->tls_version, "tlsv1.2")){ mosq->ssl_ctx = SSL_CTX_new(TLSv1_2_client_method()); }else if(!strcmp(mosq->tls_version, "tlsv1.1")){ mosq->ssl_ctx = SSL_CTX_new(TLSv1_1_client_method()); }else if(!strcmp(mosq->tls_version, "tlsv1")){ mosq->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); }else{ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version); COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_INVAL; } #else if(!mosq->tls_version || !strcmp(mosq->tls_version, "tlsv1")){ mosq->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); }else{ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version); COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_INVAL; } #endif if(!mosq->ssl_ctx){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to create TLS context."); COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } #if OPENSSL_VERSION_NUMBER >= 0x10000000 /* Disable compression */ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_COMPRESSION); #endif #ifdef SSL_MODE_RELEASE_BUFFERS /* Use even less memory per SSL connection. */ SSL_CTX_set_mode(mosq->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); #endif if(mosq->tls_ciphers){ ret = SSL_CTX_set_cipher_list(mosq->ssl_ctx, mosq->tls_ciphers); if(ret == 0){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", mosq->tls_ciphers); COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } } if(mosq->tls_cafile || mosq->tls_capath){ ret = SSL_CTX_load_verify_locations(mosq->ssl_ctx, mosq->tls_cafile, mosq->tls_capath); if(ret == 0){ #ifdef WITH_BROKER if(mosq->tls_cafile && mosq->tls_capath){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\" and bridge_capath \"%s\".", mosq->tls_cafile, mosq->tls_capath); }else if(mosq->tls_cafile){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\".", mosq->tls_cafile); }else{ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_capath \"%s\".", mosq->tls_capath); } #else if(mosq->tls_cafile && mosq->tls_capath){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\" and capath \"%s\".", mosq->tls_cafile, mosq->tls_capath); }else if(mosq->tls_cafile){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\".", mosq->tls_cafile); }else{ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check capath \"%s\".", mosq->tls_capath); } #endif COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } if(mosq->tls_cert_reqs == 0){ SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_NONE, NULL); }else{ SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_PEER, _mosquitto_server_certificate_verify); } if(mosq->tls_pw_callback){ SSL_CTX_set_default_passwd_cb(mosq->ssl_ctx, mosq->tls_pw_callback); SSL_CTX_set_default_passwd_cb_userdata(mosq->ssl_ctx, mosq); } if(mosq->tls_certfile){ ret = SSL_CTX_use_certificate_chain_file(mosq->ssl_ctx, mosq->tls_certfile); if(ret != 1){ #ifdef WITH_BROKER _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate, check bridge_certfile \"%s\".", mosq->tls_certfile); #else _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate \"%s\".", mosq->tls_certfile); #endif COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } } if(mosq->tls_keyfile){ ret = SSL_CTX_use_PrivateKey_file(mosq->ssl_ctx, mosq->tls_keyfile, SSL_FILETYPE_PEM); if(ret != 1){ #ifdef WITH_BROKER _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file, check bridge_keyfile \"%s\".", mosq->tls_keyfile); #else _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file \"%s\".", mosq->tls_keyfile); #endif COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } ret = SSL_CTX_check_private_key(mosq->ssl_ctx); if(ret != 1){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Client certificate/key are inconsistent."); COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } } #ifdef REAL_WITH_TLS_PSK }else if(mosq->tls_psk){ SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback); #endif } mosq->ssl = SSL_new(mosq->ssl_ctx); if(!mosq->ssl){ COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } SSL_set_ex_data(mosq->ssl, tls_ex_index_mosq, mosq); bio = BIO_new_socket(mosq->sock, BIO_NOCLOSE); if(!bio){ COMPAT_CLOSE(mosq->sock); return MOSQ_ERR_TLS; } SSL_set_bio(mosq->ssl, bio, bio); if(mosquitto__socket_connect_tls(mosq)){ return MOSQ_ERR_TLS; } } #endif return MOSQ_ERR_SUCCESS; } /* Create a socket and connect it to 'ip' on port 'port'. * Returns -1 on failure (ip is NULL, socket creation/connection error) * Returns sock number on success. */ int _mosquitto_socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking) { mosq_sock_t sock = INVALID_SOCKET; int rc; if(!mosq || !host || !port) return MOSQ_ERR_INVAL; rc = _mosquitto_try_connect(mosq, host, port, &sock, bind_address, blocking); if(rc > 0) return rc; mosq->sock = sock; rc = _mosquitto_socket_connect_step3(mosq, host, port, bind_address, blocking); return rc; } int _mosquitto_read_byte(struct _mosquitto_packet *packet, uint8_t *byte) { assert(packet); if(packet->pos+1 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; *byte = packet->payload[packet->pos]; packet->pos++; return MOSQ_ERR_SUCCESS; } void _mosquitto_write_byte(struct _mosquitto_packet *packet, uint8_t byte) { assert(packet); assert(packet->pos+1 <= packet->packet_length); packet->payload[packet->pos] = byte; packet->pos++; } int _mosquitto_read_bytes(struct _mosquitto_packet *packet, void *bytes, uint32_t count) { assert(packet); if(packet->pos+count > packet->remaining_length) return MOSQ_ERR_PROTOCOL; memcpy(bytes, &(packet->payload[packet->pos]), count); packet->pos += count; return MOSQ_ERR_SUCCESS; } void _mosquitto_write_bytes(struct _mosquitto_packet *packet, const void *bytes, uint32_t count) { assert(packet); assert(packet->pos+count <= packet->packet_length); memcpy(&(packet->payload[packet->pos]), bytes, count); packet->pos += count; } int _mosquitto_read_string(struct _mosquitto_packet *packet, char **str) { uint16_t len; int rc; assert(packet); rc = _mosquitto_read_uint16(packet, &len); if(rc) return rc; if(packet->pos+len > packet->remaining_length) return MOSQ_ERR_PROTOCOL; *str = _mosquitto_malloc(len+1); if(*str){ memcpy(*str, &(packet->payload[packet->pos]), len); (*str)[len] = '\0'; packet->pos += len; }else{ return MOSQ_ERR_NOMEM; } return MOSQ_ERR_SUCCESS; } void _mosquitto_write_string(struct _mosquitto_packet *packet, const char *str, uint16_t length) { assert(packet); _mosquitto_write_uint16(packet, length); _mosquitto_write_bytes(packet, str, length); } int _mosquitto_read_uint16(struct _mosquitto_packet *packet, uint16_t *word) { uint8_t msb, lsb; assert(packet); if(packet->pos+2 > packet->remaining_length) return MOSQ_ERR_PROTOCOL; msb = packet->payload[packet->pos]; packet->pos++; lsb = packet->payload[packet->pos]; packet->pos++; *word = (msb<<8) + lsb; return MOSQ_ERR_SUCCESS; } void _mosquitto_write_uint16(struct _mosquitto_packet *packet, uint16_t word) { _mosquitto_write_byte(packet, MOSQ_MSB(word)); _mosquitto_write_byte(packet, MOSQ_LSB(word)); } ssize_t _mosquitto_net_read(struct mosquitto *mosq, void *buf, size_t count) { #ifdef WITH_TLS int ret; int err; char ebuf[256]; unsigned long e; #endif assert(mosq); errno = 0; #ifdef WITH_TLS if(mosq->ssl){ ERR_clear_error(); ret = SSL_read(mosq->ssl, buf, count); if(ret <= 0){ err = SSL_get_error(mosq->ssl, ret); if(err == SSL_ERROR_WANT_READ){ ret = -1; errno = EAGAIN; }else if(err == SSL_ERROR_WANT_WRITE){ ret = -1; mosq->want_write = true; errno = EAGAIN; }else{ e = ERR_get_error(); while(e){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error: %s", ERR_error_string(e, ebuf)); e = ERR_get_error(); } errno = EPROTO; } } return (ssize_t )ret; }else{ /* Call normal read/recv */ #endif #ifndef WIN32 return read(mosq->sock, buf, count); #else return recv(mosq->sock, buf, count, 0); #endif #ifdef WITH_TLS } #endif } ssize_t _mosquitto_net_write(struct mosquitto *mosq, void *buf, size_t count) { #ifdef WITH_TLS int ret; int err; char ebuf[256]; unsigned long e; #endif assert(mosq); errno = 0; #ifdef WITH_TLS if(mosq->ssl){ mosq->want_write = false; ERR_clear_error(); ret = SSL_write(mosq->ssl, buf, count); if(ret < 0){ err = SSL_get_error(mosq->ssl, ret); if(err == SSL_ERROR_WANT_READ){ ret = -1; errno = EAGAIN; }else if(err == SSL_ERROR_WANT_WRITE){ ret = -1; mosq->want_write = true; errno = EAGAIN; }else{ e = ERR_get_error(); while(e){ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error: %s", ERR_error_string(e, ebuf)); e = ERR_get_error(); } errno = EPROTO; } } return (ssize_t )ret; }else{ /* Call normal write/send */ #endif #ifndef WIN32 return write(mosq->sock, buf, count); #else return send(mosq->sock, buf, count, 0); #endif #ifdef WITH_TLS } #endif } int _mosquitto_packet_write(struct mosquitto *mosq) { ssize_t write_length; struct _mosquitto_packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = 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); #if defined(WITH_TLS) && !defined(WITH_BROKER) if((mosq->state == mosq_cs_connect_pending)||mosq->want_connect){ #else if(mosq->state == mosq_cs_connect_pending){ #endif pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; } while(mosq->current_out_packet){ packet = mosq->current_out_packet; while(packet->to_process > 0){ write_length = _mosquitto_net_write(mosq, &(packet->payload[packet->pos]), packet->to_process); if(write_length > 0){ #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_sent += write_length; #endif packet->to_process -= write_length; packet->pos += write_length; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; }else{ pthread_mutex_unlock(&mosq->current_out_packet_mutex); switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_msgs_sent++; if(((packet->command)&0xF6) == PUBLISH){ g_pub_msgs_sent++; } # endif #else if(((packet->command)&0xF6) == PUBLISH){ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_publish){ /* This is a QoS=0 message */ mosq->in_callback = true; mosq->on_publish(mosq, mosq->userdata, packet->mid); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); }else if(((packet->command)&0xF0) == DISCONNECT){ /* FIXME what cleanup needs doing here? * incoming/outgoing messages? */ _mosquitto_socket_close(mosq); /* Start of duplicate, possibly unnecessary code. * This does leave things in a consistent state at least. */ /* 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); _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->next_msg_out = mosquitto_time() + mosq->keepalive; pthread_mutex_unlock(&mosq->msgtime_mutex); /* End of duplicate, possibly unnecessary code */ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_disconnect){ mosq->in_callback = true; mosq->on_disconnect(mosq, mosq->userdata, 0); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; } #endif /* 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); _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->next_msg_out = mosquitto_time() + mosq->keepalive; pthread_mutex_unlock(&mosq->msgtime_mutex); } pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; } #ifdef WITH_BROKER int _mosquitto_packet_read(struct mosquitto_db *db, struct mosquitto *mosq) #else int _mosquitto_packet_read(struct mosquitto *mosq) #endif { uint8_t byte; ssize_t read_length; int rc = 0; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosq->state == mosq_cs_connect_pending){ return MOSQ_ERR_SUCCESS; } /* This gets called if pselect() indicates that there is network data * available - ie. at least one byte. What we do depends on what data we * already have. * If we've not got a command, attempt to read one and save it. This should * always work because it's only a single byte. * Then try to read the remaining length. This may fail because it is may * be more than one byte - will need to save data pending next read if it * does fail. * Then try to read the remaining payload, where 'payload' here means the * combined variable header and actual payload. This is the most likely to * fail due to longer length, so save current data and current position. * After all data is read, send to _mosquitto_handle_packet() to deal with. * Finally, free the memory and reset everything to starting conditions. */ if(!mosq->in_packet.command){ read_length = _mosquitto_net_read(mosq, &byte, 1); if(read_length == 1){ mosq->in_packet.command = byte; #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_bytes_received++; # endif /* Clients must send CONNECT as their first command. */ if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CONNECT) return MOSQ_ERR_PROTOCOL; #endif }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } /* remaining_count is the number of bytes that the remaining_length * parameter occupied in this incoming packet. We don't use it here as such * (it is used when allocating an outgoing packet), but we must be able to * determine whether all of the remaining_length parameter has been read. * remaining_count has three states here: * 0 means that we haven't read any remaining_length bytes * <0 means we have read some remaining_length bytes but haven't finished * >0 means we have finished reading the remaining_length bytes. */ if(mosq->in_packet.remaining_count <= 0){ do{ read_length = _mosquitto_net_read(mosq, &byte, 1); if(read_length == 1){ mosq->in_packet.remaining_count--; /* Max 4 bytes length for remaining length as defined by protocol. * Anything more likely means a broken/malicious client. */ if(mosq->in_packet.remaining_count < -4) return MOSQ_ERR_PROTOCOL; #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_received++; #endif mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult; mosq->in_packet.remaining_mult *= 128; }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } }while((byte & 128) != 0); /* We have finished reading remaining_length, so make remaining_count * positive. */ mosq->in_packet.remaining_count *= -1; #ifdef WITH_BROKER /* Check packet sizes before allocating memory. * Will need modifying for MQTT v5. */ switch(mosq->in_packet.command & 0xF0){ case CONNECT: if(mosq->in_packet.remaining_length > 327699){ return MOSQ_ERR_PROTOCOL; } break; case PUBACK: case PUBREC: case PUBREL: case PUBCOMP: case UNSUBACK: if(mosq->in_packet.remaining_length != 2){ return MOSQ_ERR_PROTOCOL; } break; case PINGREQ: case PINGRESP: case DISCONNECT: if(mosq->in_packet.remaining_length != 0){ return MOSQ_ERR_PROTOCOL; } break; } #endif if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = _mosquitto_malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload) return MOSQ_ERR_NOMEM; mosq->in_packet.to_process = mosq->in_packet.remaining_length; } } while(mosq->in_packet.to_process>0){ read_length = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(read_length > 0){ #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_received += read_length; #endif mosq->in_packet.to_process -= read_length; mosq->in_packet.pos += read_length; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ if(mosq->in_packet.to_process > 1000){ /* Update last_msg_in time if more than 1000 bytes left to * receive. Helps when receiving large messages. * This is an arbitrary limit, but with some consideration. * If a client can't send 1000 bytes in a second it * probably shouldn't be using a 1 second keep alive. */ pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); } return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } /* All data for this packet is read. */ mosq->in_packet.pos = 0; #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_msgs_received++; if(((mosq->in_packet.command)&0xF5) == PUBLISH){ g_pub_msgs_received++; } # endif rc = mqtt3_packet_handle(db, mosq); #else rc = _mosquitto_packet_handle(mosq); #endif /* Free data and reset values */ _mosquitto_packet_cleanup(&mosq->in_packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); return rc; } int _mosquitto_socket_nonblock(mosq_sock_t sock) { #ifndef WIN32 int opt; /* Set non-blocking */ opt = fcntl(sock, F_GETFL, 0); if(opt == -1){ COMPAT_CLOSE(sock); return 1; } if(fcntl(sock, F_SETFL, opt | O_NONBLOCK) == -1){ /* If either fcntl fails, don't want to allow this client to connect. */ COMPAT_CLOSE(sock); return 1; } #else unsigned long opt = 1; if(ioctlsocket(sock, FIONBIO, &opt)){ COMPAT_CLOSE(sock); return 1; } #endif return 0; } #ifndef WITH_BROKER int _mosquitto_socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW) { #ifdef WIN32 int family[2] = {AF_INET, AF_INET6}; int i; struct sockaddr_storage ss; struct sockaddr_in *sa = (struct sockaddr_in *)&ss; struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&ss; socklen_t ss_len; mosq_sock_t spR, spW; mosq_sock_t listensock; *pairR = INVALID_SOCKET; *pairW = INVALID_SOCKET; for(i=0; i<2; i++){ memset(&ss, 0, sizeof(ss)); if(family[i] == AF_INET){ sa->sin_family = family[i]; sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK); sa->sin_port = 0; ss_len = sizeof(struct sockaddr_in); }else if(family[i] == AF_INET6){ sa6->sin6_family = family[i]; sa6->sin6_addr = in6addr_loopback; sa6->sin6_port = 0; ss_len = sizeof(struct sockaddr_in6); }else{ return MOSQ_ERR_INVAL; } listensock = socket(family[i], SOCK_STREAM, IPPROTO_TCP); if(listensock == -1){ continue; } if(bind(listensock, (struct sockaddr *)&ss, ss_len) == -1){ COMPAT_CLOSE(listensock); continue; } if(listen(listensock, 1) == -1){ COMPAT_CLOSE(listensock); continue; } memset(&ss, 0, sizeof(ss)); ss_len = sizeof(ss); if(getsockname(listensock, (struct sockaddr *)&ss, &ss_len) < 0){ COMPAT_CLOSE(listensock); continue; } if(family[i] == AF_INET){ sa->sin_family = family[i]; sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK); ss_len = sizeof(struct sockaddr_in); }else if(family[i] == AF_INET6){ sa6->sin6_family = family[i]; sa6->sin6_addr = in6addr_loopback; ss_len = sizeof(struct sockaddr_in6); } spR = socket(family[i], SOCK_STREAM, IPPROTO_TCP); if(spR == -1){ COMPAT_CLOSE(listensock); continue; } if(_mosquitto_socket_nonblock(spR)){ COMPAT_CLOSE(listensock); continue; } if(connect(spR, (struct sockaddr *)&ss, ss_len) < 0){ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){ COMPAT_CLOSE(spR); COMPAT_CLOSE(listensock); continue; } } spW = accept(listensock, NULL, 0); if(spW == -1){ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){ COMPAT_CLOSE(spR); COMPAT_CLOSE(listensock); continue; } } if(_mosquitto_socket_nonblock(spW)){ COMPAT_CLOSE(spR); COMPAT_CLOSE(listensock); continue; } COMPAT_CLOSE(listensock); *pairR = spR; *pairW = spW; return MOSQ_ERR_SUCCESS; } return MOSQ_ERR_UNKNOWN; #else int sv[2]; if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1){ return MOSQ_ERR_ERRNO; } if(_mosquitto_socket_nonblock(sv[0])){ COMPAT_CLOSE(sv[1]); return MOSQ_ERR_ERRNO; } if(_mosquitto_socket_nonblock(sv[1])){ COMPAT_CLOSE(sv[0]); return MOSQ_ERR_ERRNO; } *pairR = sv[0]; *pairW = sv[1]; return MOSQ_ERR_SUCCESS; #endif } #endif mosquitto-1.4.15/lib/time_mosq.c0000664000175000017500000000322313245550210015572 0ustar rogerroger/* Copyright (c) 2013-2018 Roger Light 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. */ #ifdef __APPLE__ #include #include #endif #ifdef WIN32 # define _WIN32_WINNT _WIN32_WINNT_VISTA # include #else # include #endif #include #include "mosquitto.h" #include "time_mosq.h" #ifdef WIN32 static bool tick64 = false; void _windows_time_version_check(void) { OSVERSIONINFO vi; tick64 = false; memset(&vi, 0, sizeof(OSVERSIONINFO)); vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(GetVersionEx(&vi)){ if(vi.dwMajorVersion > 5){ tick64 = true; } } } #endif time_t mosquitto_time(void) { #ifdef WIN32 if(tick64){ return GetTickCount64()/1000; }else{ return GetTickCount()/1000; /* FIXME - need to deal with overflow. */ } #elif _POSIX_TIMERS>0 && defined(_POSIX_MONOTONIC_CLOCK) struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); return tp.tv_sec; #elif defined(__APPLE__) static mach_timebase_info_data_t tb; uint64_t ticks; uint64_t sec; ticks = mach_absolute_time(); if(tb.denom == 0){ mach_timebase_info(&tb); } sec = ticks*tb.numer/tb.denom/1000000000; return (time_t)sec; #else return time(NULL); #endif } mosquitto-1.4.15/lib/CMakeLists.txt0000664000175000017500000000430113245550210016167 0ustar rogerrogeradd_subdirectory(cpp) option(WITH_THREADING "Include client library threading support?" ON) if (${WITH_THREADING} STREQUAL ON) add_definitions("-DWITH_THREADING") if (WIN32) set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x86\\pthreadVC2.lib) set (PTHREAD_INCLUDE_DIR C:\\pthreads\\Pre-built.2\\include) else (WIN32) find_library(LIBPTHREAD pthread) if (LIBPTHREAD) set (PTHREAD_LIBRARIES pthread) else (LIBPTHREAD) set (PTHREAD_LIBRARIES "") endif() set (PTHREAD_INCLUDE_DIR "") endif (WIN32) else (${WITH_THREADING} STREQUAL ON) set (PTHREAD_LIBRARIES "") set (PTHREAD_INCLUDE_DIR "") endif (${WITH_THREADING} STREQUAL ON) include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/lib ${STDBOOL_H_PATH} ${STDINT_H_PATH} ${OPENSSL_INCLUDE_DIR} ${PTHREAD_INCLUDE_DIR}) link_directories(${mosquitto_SOURCE_DIR}/lib) add_library(libmosquitto SHARED logging_mosq.c logging_mosq.h memory_mosq.c memory_mosq.h messages_mosq.c messages_mosq.h mosquitto.c mosquitto.h mosquitto_internal.h mqtt3_protocol.h net_mosq.c net_mosq.h read_handle.c read_handle.h read_handle_client.c read_handle_shared.c send_client_mosq.c send_mosq.c send_mosq.h socks_mosq.c srv_mosq.c thread_mosq.c time_mosq.c tls_mosq.c util_mosq.c util_mosq.h will_mosq.c will_mosq.h) set (LIBRARIES ${OPENSSL_LIBRARIES} ${PTHREAD_LIBRARIES}) if (UNIX AND NOT APPLE) find_library(LIBRT rt) if (LIBRT) set (LIBRARIES ${LIBRARIES} rt) endif (LIBRT) endif (UNIX AND NOT APPLE) if (WIN32) set (LIBRARIES ${LIBRARIES} ws2_32) endif (WIN32) if (${WITH_SRV} STREQUAL ON) # Simple detect c-ares find_path(ARES_HEADER ares.h) if (ARES_HEADER) add_definitions("-DWITH_SRV") set (LIBRARIES ${LIBRARIES} cares) else (ARES_HEADER) message(WARNING "c-ares library not found.") endif (ARES_HEADER) endif (${WITH_SRV} STREQUAL ON) target_link_libraries(libmosquitto ${LIBRARIES}) set_target_properties(libmosquitto PROPERTIES OUTPUT_NAME mosquitto VERSION ${VERSION} SOVERSION 1 ) install(TARGETS libmosquitto RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") install(FILES mosquitto.h DESTINATION "${INCLUDEDIR}") if (UNIX) install(CODE "EXEC_PROGRAM(/sbin/ldconfig)") endif (UNIX) mosquitto-1.4.15/lib/mosquitto.c0000664000175000017500000010776213245550210015656 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 #include #include #include #include #ifndef WIN32 #include #include #include #else #include #include typedef int ssize_t; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #if !defined(WIN32) && !defined(__SYMBIAN32__) #define HAVE_PSELECT #endif void _mosquitto_destroy(struct mosquitto *mosq); static int _mosquitto_reconnect(struct mosquitto *mosq, bool blocking); static int _mosquitto_connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); 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(GetTickCount()); #else struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_sec*1000 + tv.tv_usec/1000); #endif _mosquitto_net_init(); return MOSQ_ERR_SUCCESS; } int mosquitto_lib_cleanup(void) { _mosquitto_net_cleanup(); return MOSQ_ERR_SUCCESS; } struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *userdata) { struct mosquitto *mosq = NULL; int rc; if(clean_session == 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_session, 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_session, void *userdata) { int i; if(!mosq) return MOSQ_ERR_INVAL; if(clean_session == 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_mqtt31; mosq->sock = INVALID_SOCKET; mosq->sockpairR = INVALID_SOCKET; mosq->sockpairW = INVALID_SOCKET; mosq->keepalive = 60; mosq->message_retry = 20; mosq->last_retry_check = 0; mosq->clean_session = clean_session; if(id){ if(STREMPTY(id)){ return MOSQ_ERR_INVAL; } mosq->id = _mosquitto_strdup(id); }else{ 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] = '/'; for(i=5; i<23; i++){ mosq->id[i] = (rand()%73)+48; } } mosq->in_packet.payload = NULL; _mosquitto_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->in_messages = NULL; mosq->in_messages_last = NULL; mosq->out_messages = NULL; mosq->out_messages_last = NULL; mosq->max_inflight_messages = 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->in_queue_len = 0; mosq->out_queue_len = 0; 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->tls_cert_reqs = SSL_VERIFY_PEER; mosq->tls_insecure = false; mosq->want_write = 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->in_message_mutex, NULL); pthread_mutex_init(&mosq->out_message_mutex, NULL); pthread_mutex_init(&mosq->mid_mutex, NULL); mosq->thread_id = pthread_self(); #endif return MOSQ_ERR_SUCCESS; } int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { if(!mosq) return MOSQ_ERR_INVAL; return _mosquitto_will_set(mosq, topic, payloadlen, payload, qos, retain); } int mosquitto_will_clear(struct mosquitto *mosq) { if(!mosq) return MOSQ_ERR_INVAL; return _mosquitto_will_clear(mosq); } int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password) { if(!mosq) return MOSQ_ERR_INVAL; if(mosq->username){ _mosquitto_free(mosq->username); mosq->username = NULL; } if(mosq->password){ _mosquitto_free(mosq->password); mosq->password = NULL; } if(username){ mosq->username = _mosquitto_strdup(username); if(!mosq->username) return MOSQ_ERR_NOMEM; if(password){ mosq->password = _mosquitto_strdup(password); if(!mosq->password){ _mosquitto_free(mosq->username); mosq->username = NULL; return MOSQ_ERR_NOMEM; } } } return MOSQ_ERR_SUCCESS; } int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff) { if(!mosq) return MOSQ_ERR_INVAL; mosq->reconnect_delay = reconnect_delay; mosq->reconnect_delay_max = reconnect_delay_max; mosq->reconnect_exponential_backoff = reconnect_exponential_backoff; return MOSQ_ERR_SUCCESS; } void _mosquitto_destroy(struct mosquitto *mosq) { struct _mosquitto_packet *packet; if(!mosq) return; #ifdef WITH_THREADING 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; } 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->in_message_mutex); pthread_mutex_destroy(&mosq->out_message_mutex); pthread_mutex_destroy(&mosq->mid_mutex); } #endif if(mosq->sock != INVALID_SOCKET){ _mosquitto_socket_close(mosq); } _mosquitto_message_cleanup_all(mosq); _mosquitto_will_clear(mosq); #ifdef WITH_TLS if(mosq->ssl){ SSL_free(mosq->ssl); } if(mosq->ssl_ctx){ SSL_CTX_free(mosq->ssl_ctx); } if(mosq->tls_cafile) _mosquitto_free(mosq->tls_cafile); if(mosq->tls_capath) _mosquitto_free(mosq->tls_capath); if(mosq->tls_certfile) _mosquitto_free(mosq->tls_certfile); if(mosq->tls_keyfile) _mosquitto_free(mosq->tls_keyfile); if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL; if(mosq->tls_version) _mosquitto_free(mosq->tls_version); if(mosq->tls_ciphers) _mosquitto_free(mosq->tls_ciphers); if(mosq->tls_psk) _mosquitto_free(mosq->tls_psk); if(mosq->tls_psk_identity) _mosquitto_free(mosq->tls_psk_identity); #endif if(mosq->address){ _mosquitto_free(mosq->address); mosq->address = NULL; } if(mosq->id){ _mosquitto_free(mosq->id); mosq->id = NULL; } if(mosq->username){ _mosquitto_free(mosq->username); mosq->username = NULL; } if(mosq->password){ _mosquitto_free(mosq->password); mosq->password = NULL; } if(mosq->host){ _mosquitto_free(mosq->host); mosq->host = NULL; } if(mosq->bind_address){ _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; } _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); } _mosquitto_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; } static int _mosquitto_connect_init(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address) { if(!mosq) return MOSQ_ERR_INVAL; if(!host || port <= 0) return MOSQ_ERR_INVAL; if(mosq->host) _mosquitto_free(mosq->host); mosq->host = _mosquitto_strdup(host); if(!mosq->host) return MOSQ_ERR_NOMEM; mosq->port = port; if(mosq->bind_address) _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; 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(_mosquitto_socketpair(&mosq->sockpairR, &mosq->sockpairW)){ _mosquitto_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) { int rc; rc = _mosquitto_connect_init(mosq, host, port, keepalive, bind_address); if(rc) return rc; pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_new; pthread_mutex_unlock(&mosq->state_mutex); return _mosquitto_reconnect(mosq, true); } 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; pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_connect_async; pthread_mutex_unlock(&mosq->state_mutex); return _mosquitto_reconnect(mosq, false); } int mosquitto_reconnect_async(struct mosquitto *mosq) { return _mosquitto_reconnect(mosq, false); } int mosquitto_reconnect(struct mosquitto *mosq) { return _mosquitto_reconnect(mosq, true); } static int _mosquitto_reconnect(struct mosquitto *mosq, bool blocking) { int rc; struct _mosquitto_packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; pthread_mutex_lock(&mosq->state_mutex); #ifdef WITH_SOCKS if(mosq->socks5_host){ mosq->state = mosq_cs_socks5_new; }else #endif { mosq->state = mosq_cs_new; } pthread_mutex_unlock(&mosq->state_mutex); 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; _mosquitto_packet_cleanup(&mosq->in_packet); pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); 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; } _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); } pthread_mutex_unlock(&mosq->out_packet_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); _mosquitto_messages_reconnect_reset(mosq); if(mosq->sock != INVALID_SOCKET){ _mosquitto_socket_close(mosq); //close socket } #ifdef WITH_SOCKS if(mosq->socks5_host){ rc = _mosquitto_socket_connect(mosq, mosq->socks5_host, mosq->socks5_port, mosq->bind_address, blocking); }else #endif { rc = _mosquitto_socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking); } if(rc>0){ return rc; } #ifdef WITH_SOCKS if(mosq->socks5_host){ return mosquitto__socks5_send(mosq); }else #endif { return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session); } } int mosquitto_disconnect(struct mosquitto *mosq) { if(!mosq) return MOSQ_ERR_INVAL; pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_disconnecting; pthread_mutex_unlock(&mosq->state_mutex); if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; return _mosquitto_send_disconnect(mosq); } int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { struct mosquitto_message_all *message; uint16_t local_mid; int queue_status; if(!mosq || !topic || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(STREMPTY(topic)) return MOSQ_ERR_INVAL; 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; } local_mid = _mosquitto_mid_generate(mosq); if(mid){ *mid = local_mid; } if(qos == 0){ return _mosquitto_send_publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false); }else{ message = _mosquitto_calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; message->next = NULL; message->timestamp = mosquitto_time(); message->msg.mid = local_mid; message->msg.topic = _mosquitto_strdup(topic); if(!message->msg.topic){ _mosquitto_message_cleanup(&message); return MOSQ_ERR_NOMEM; } if(payloadlen){ message->msg.payloadlen = payloadlen; message->msg.payload = _mosquitto_malloc(payloadlen*sizeof(uint8_t)); if(!message->msg.payload){ _mosquitto_message_cleanup(&message); 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; pthread_mutex_lock(&mosq->out_message_mutex); queue_status = _mosquitto_message_queue(mosq, message, mosq_md_out); if(queue_status == 0){ if(qos == 1){ message->state = mosq_ms_wait_for_puback; }else if(qos == 2){ message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); return _mosquitto_send_publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; } } } int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos) { if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; return _mosquitto_send_subscribe(mosq, mid, sub, qos); } int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub) { if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosquitto_sub_topic_check(sub)) return MOSQ_ERR_INVAL; return _mosquitto_send_unsubscribe(mosq, mid, sub); } int mosquitto_tls_set(struct mosquitto *mosq, const char *cafile, const char *capath, const char *certfile, const char *keyfile, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)) { #ifdef WITH_TLS FILE *fptr; if(!mosq || (!cafile && !capath) || (certfile && !keyfile) || (!certfile && keyfile)) return MOSQ_ERR_INVAL; if(cafile){ fptr = _mosquitto_fopen(cafile, "rt", false); if(fptr){ fclose(fptr); }else{ return MOSQ_ERR_INVAL; } mosq->tls_cafile = _mosquitto_strdup(cafile); if(!mosq->tls_cafile){ return MOSQ_ERR_NOMEM; } }else if(mosq->tls_cafile){ _mosquitto_free(mosq->tls_cafile); mosq->tls_cafile = NULL; } if(capath){ mosq->tls_capath = _mosquitto_strdup(capath); if(!mosq->tls_capath){ return MOSQ_ERR_NOMEM; } }else if(mosq->tls_capath){ _mosquitto_free(mosq->tls_capath); mosq->tls_capath = NULL; } if(certfile){ fptr = _mosquitto_fopen(certfile, "rt", false); if(fptr){ fclose(fptr); }else{ if(mosq->tls_cafile){ _mosquitto_free(mosq->tls_cafile); mosq->tls_cafile = NULL; } if(mosq->tls_capath){ _mosquitto_free(mosq->tls_capath); mosq->tls_capath = NULL; } return MOSQ_ERR_INVAL; } mosq->tls_certfile = _mosquitto_strdup(certfile); if(!mosq->tls_certfile){ return MOSQ_ERR_NOMEM; } }else{ if(mosq->tls_certfile) _mosquitto_free(mosq->tls_certfile); mosq->tls_certfile = NULL; } if(keyfile){ fptr = _mosquitto_fopen(keyfile, "rt", false); if(fptr){ fclose(fptr); }else{ if(mosq->tls_cafile){ _mosquitto_free(mosq->tls_cafile); mosq->tls_cafile = NULL; } if(mosq->tls_capath){ _mosquitto_free(mosq->tls_capath); mosq->tls_capath = NULL; } if(mosq->tls_certfile){ _mosquitto_free(mosq->tls_certfile); mosq->tls_certfile = NULL; } return MOSQ_ERR_INVAL; } mosq->tls_keyfile = _mosquitto_strdup(keyfile); if(!mosq->tls_keyfile){ return MOSQ_ERR_NOMEM; } }else{ if(mosq->tls_keyfile) _mosquitto_free(mosq->tls_keyfile); mosq->tls_keyfile = NULL; } mosq->tls_pw_callback = pw_callback; return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif } int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers) { #ifdef WITH_TLS if(!mosq) return MOSQ_ERR_INVAL; mosq->tls_cert_reqs = cert_reqs; if(tls_version){ #if OPENSSL_VERSION_NUMBER >= 0x10001000L if(!strcasecmp(tls_version, "tlsv1.2") || !strcasecmp(tls_version, "tlsv1.1") || !strcasecmp(tls_version, "tlsv1")){ mosq->tls_version = _mosquitto_strdup(tls_version); if(!mosq->tls_version) return MOSQ_ERR_NOMEM; }else{ return MOSQ_ERR_INVAL; } #else if(!strcasecmp(tls_version, "tlsv1")){ mosq->tls_version = _mosquitto_strdup(tls_version); if(!mosq->tls_version) return MOSQ_ERR_NOMEM; }else{ return MOSQ_ERR_INVAL; } #endif }else{ #if OPENSSL_VERSION_NUMBER >= 0x10001000L mosq->tls_version = _mosquitto_strdup("tlsv1.2"); #else mosq->tls_version = _mosquitto_strdup("tlsv1"); #endif if(!mosq->tls_version) return MOSQ_ERR_NOMEM; } if(ciphers){ mosq->tls_ciphers = _mosquitto_strdup(ciphers); if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM; }else{ mosq->tls_ciphers = NULL; } return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif } int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value) { #ifdef WITH_TLS if(!mosq) return MOSQ_ERR_INVAL; mosq->tls_insecure = value; return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif } int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers) { #ifdef REAL_WITH_TLS_PSK if(!mosq || !psk || !identity) return MOSQ_ERR_INVAL; /* Check for hex only digits */ if(strspn(psk, "0123456789abcdefABCDEF") < strlen(psk)){ return MOSQ_ERR_INVAL; } mosq->tls_psk = _mosquitto_strdup(psk); if(!mosq->tls_psk) return MOSQ_ERR_NOMEM; mosq->tls_psk_identity = _mosquitto_strdup(identity); if(!mosq->tls_psk_identity){ _mosquitto_free(mosq->tls_psk); return MOSQ_ERR_NOMEM; } if(ciphers){ mosq->tls_ciphers = _mosquitto_strdup(ciphers); if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM; }else{ mosq->tls_ciphers = NULL; } return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #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; 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){ pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_connect_srv){ rc = ares_fds(mosq->achan, &readfds, &writefds); if(rc > maxfd){ maxfd = rc; } }else{ pthread_mutex_unlock(&mosq->state_mutex); return MOSQ_ERR_NO_CONN; } pthread_mutex_unlock(&mosq->state_mutex); } #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)){ #ifdef WITH_TLS if(mosq->want_connect){ rc = mosquitto__socket_connect_tls(mosq); if(rc) return rc; }else #endif { do{ rc = mosquitto_loop_read(mosq, max_packets); if(rc || mosq->sock == INVALID_SOCKET){ return rc; } }while(SSL_DATA_PENDING(mosq)); } } 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 = mosquitto__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 int reconnects = 0; unsigned long reconnect_delay; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->state == mosq_cs_connect_async){ mosquitto_reconnect(mosq); } while(run){ do{ rc = mosquitto_loop(mosq, timeout, max_packets); if (reconnects !=0 && rc == MOSQ_ERR_SUCCESS){ reconnects = 0; } }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; pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ run = 0; pthread_mutex_unlock(&mosq->state_mutex); }else{ pthread_mutex_unlock(&mosq->state_mutex); if(mosq->reconnect_delay > 0 && mosq->reconnect_exponential_backoff){ reconnect_delay = mosq->reconnect_delay*reconnects*reconnects; }else{ reconnect_delay = mosq->reconnect_delay; } if(reconnect_delay > mosq->reconnect_delay_max){ reconnect_delay = mosq->reconnect_delay_max; }else{ reconnects++; } #ifdef WIN32 Sleep(reconnect_delay*1000); #else sleep(reconnect_delay); #endif pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ run = 0; pthread_mutex_unlock(&mosq->state_mutex); }else{ pthread_mutex_unlock(&mosq->state_mutex); rc = mosquitto_reconnect(mosq); } } }while(run && rc != MOSQ_ERR_SUCCESS); } return rc; } int mosquitto_loop_misc(struct mosquitto *mosq) { time_t now; int rc; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; _mosquitto_check_keepalive(mosq); now = mosquitto_time(); if(mosq->last_retry_check+1 < now){ _mosquitto_message_retry_check(mosq); mosq->last_retry_check = now; } if(mosq->ping_t && now - mosq->ping_t >= mosq->keepalive){ /* mosq->ping_t != 0 means we are waiting for a pingresp. * This hasn't happened in the keepalive time so we should disconnect. */ _mosquitto_socket_close(mosq); pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ rc = MOSQ_ERR_SUCCESS; }else{ rc = 1; } pthread_mutex_unlock(&mosq->state_mutex); 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; } pthread_mutex_unlock(&mosq->callback_mutex); return MOSQ_ERR_CONN_LOST; } return MOSQ_ERR_SUCCESS; } static int _mosquitto_loop_rc_handle(struct mosquitto *mosq, int rc) { if(rc){ _mosquitto_socket_close(mosq); pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ rc = MOSQ_ERR_SUCCESS; } pthread_mutex_unlock(&mosq->state_mutex); 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; } pthread_mutex_unlock(&mosq->callback_mutex); return rc; } return rc; } int mosquitto_loop_read(struct mosquitto *mosq, int max_packets) { int rc; int i; if(max_packets < 1) return MOSQ_ERR_INVAL; pthread_mutex_lock(&mosq->out_message_mutex); max_packets = mosq->out_queue_len; pthread_mutex_unlock(&mosq->out_message_mutex); pthread_mutex_lock(&mosq->in_message_mutex); max_packets += mosq->in_queue_len; pthread_mutex_unlock(&mosq->in_message_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; isocks5_host){ rc = mosquitto__socks5_read(mosq); }else #endif { rc = _mosquitto_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->out_message_mutex); max_packets = mosq->out_queue_len; pthread_mutex_unlock(&mosq->out_message_mutex); pthread_mutex_lock(&mosq->in_message_mutex); max_packets += mosq->in_queue_len; pthread_mutex_unlock(&mosq->in_message_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; iout_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; } int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value) { int ival; if(!mosq || !value) return MOSQ_ERR_INVAL; switch(option){ case MOSQ_OPT_PROTOCOL_VERSION: ival = *((int *)value); if(ival == MQTT_PROTOCOL_V31){ mosq->protocol = mosq_p_mqtt31; }else if(ival == MQTT_PROTOCOL_V311){ mosq->protocol = mosq_p_mqtt311; }else{ return MOSQ_ERR_INVAL; } break; default: return MOSQ_ERR_INVAL; } return MOSQ_ERR_SUCCESS; } 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_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_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_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_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_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_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); } void mosquitto_user_data_set(struct mosquitto *mosq, void *userdata) { if(mosq){ mosq->userdata = userdata; } } const char *mosquitto_strerror(int mosq_errno) { switch(mosq_errno){ 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."; 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."; } } 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-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 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 MOSQUITTO_H #define MOSQUITTO_H #ifdef __cplusplus extern "C" { #endif #if defined(WIN32) && !defined(WITH_BROKER) # ifdef libmosquitto_EXPORTS # define libmosq_EXPORT __declspec(dllexport) # else # define libmosq_EXPORT __declspec(dllimport) # endif #else # define libmosq_EXPORT #endif #ifdef WIN32 # ifndef __cplusplus # define bool char # define true 1 # define false 0 # endif #else # ifndef __cplusplus # include # endif #endif #define LIBMOSQUITTO_MAJOR 1 #define LIBMOSQUITTO_MINOR 4 #define LIBMOSQUITTO_REVISION 15 /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) /* Log types */ #define MOSQ_LOG_NONE 0x00 #define MOSQ_LOG_INFO 0x01 #define MOSQ_LOG_NOTICE 0x02 #define MOSQ_LOG_WARNING 0x04 #define MOSQ_LOG_ERR 0x08 #define MOSQ_LOG_DEBUG 0x10 #define MOSQ_LOG_SUBSCRIBE 0x20 #define MOSQ_LOG_UNSUBSCRIBE 0x40 #define MOSQ_LOG_WEBSOCKETS 0x80 #define MOSQ_LOG_ALL 0xFFFF /* Error values */ enum mosq_err_t { MOSQ_ERR_CONN_PENDING = -1, MOSQ_ERR_SUCCESS = 0, MOSQ_ERR_NOMEM = 1, MOSQ_ERR_PROTOCOL = 2, MOSQ_ERR_INVAL = 3, MOSQ_ERR_NO_CONN = 4, MOSQ_ERR_CONN_REFUSED = 5, MOSQ_ERR_NOT_FOUND = 6, MOSQ_ERR_CONN_LOST = 7, MOSQ_ERR_TLS = 8, MOSQ_ERR_PAYLOAD_SIZE = 9, MOSQ_ERR_NOT_SUPPORTED = 10, MOSQ_ERR_AUTH = 11, MOSQ_ERR_ACL_DENIED = 12, MOSQ_ERR_UNKNOWN = 13, MOSQ_ERR_ERRNO = 14, MOSQ_ERR_EAI = 15, MOSQ_ERR_PROXY = 16 }; /* Error values */ enum mosq_opt_t { MOSQ_OPT_PROTOCOL_VERSION = 1, }; /* MQTT specification restricts client ids to a maximum of 23 characters */ #define MOSQ_MQTT_ID_MAX_LENGTH 23 #define MQTT_PROTOCOL_V31 3 #define MQTT_PROTOCOL_V311 4 struct mosquitto_message{ int mid; char *topic; void *payload; int payloadlen; int qos; bool retain; }; struct mosquitto; /* * Topic: Threads * libmosquitto provides thread safe operation, with the exception of * which is not thread safe. * * If your application uses threads you must use to * tell the library this is the case, otherwise it makes some optimisations * for the single threaded case that may result in unexpected behaviour for * the multi threaded case. */ /*************************************************** * Important note * * The following functions that deal with network operations will return * MOSQ_ERR_SUCCESS on success, but this does not mean that the operation has * taken place. An attempt will be made to write the network data, but if the * socket is not available for writing at that time then the packet will not be * sent. To ensure the packet is sent, call mosquitto_loop() (which must also * be called to process incoming network data). * This is especially important when disconnecting a client that has a will. If * the broker does not receive the DISCONNECT command, it will assume that the * client has disconnected unexpectedly and send the will. * * mosquitto_connect() * mosquitto_disconnect() * mosquitto_subscribe() * mosquitto_unsubscribe() * mosquitto_publish() ***************************************************/ /* * Function: mosquitto_lib_version * * Can be used to obtain version information for the mosquitto library. * This allows the application to compare the library version against the * version it was compiled against by using the LIBMOSQUITTO_MAJOR, * LIBMOSQUITTO_MINOR and LIBMOSQUITTO_REVISION defines. * * Parameters: * major - an integer pointer. If not NULL, the major version of the * library will be returned in this variable. * minor - an integer pointer. If not NULL, the minor version of the * library will be returned in this variable. * revision - an integer pointer. If not NULL, the revision of the library will * be returned in this variable. * * Returns: * LIBMOSQUITTO_VERSION_NUMBER, which is a unique number based on the major, * minor and revision values. * See Also: * , */ libmosq_EXPORT int mosquitto_lib_version(int *major, int *minor, int *revision); /* * Function: mosquitto_lib_init * * Must be called before any other mosquitto functions. * * This function is *not* thread safe. * * Returns: * MOSQ_ERR_SUCCESS - always * * See Also: * , */ libmosq_EXPORT int mosquitto_lib_init(void); /* * Function: mosquitto_lib_cleanup * * Call to free resources associated with the library. * * Returns: * MOSQ_ERR_SUCCESS - always * * See Also: * , */ libmosq_EXPORT int mosquitto_lib_cleanup(void); /* * Function: mosquitto_new * * Create a new mosquitto client instance. * * Parameters: * id - String to use as the client id. If NULL, a random client id * will be generated. If id is NULL, clean_session must be true. * clean_session - set to true to instruct the broker to clean all messages * and subscriptions on disconnect, false to instruct it to * keep them. See the man page mqtt(7) for more details. * Note that a client will never discard its own outgoing * messages on disconnect. Calling or * will cause the messages to be resent. * Use to reset a client to its * original state. * Must be set to true if the id parameter is NULL. * obj - A user pointer that will be passed as an argument to any * callbacks that are specified. * * Returns: * Pointer to a struct mosquitto on success. * NULL on failure. Interrogate errno to determine the cause for the failure: * - ENOMEM on out of memory. * - EINVAL on invalid input parameters. * * See Also: * , , */ libmosq_EXPORT struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj); /* * Function: mosquitto_destroy * * Use to free memory associated with a mosquitto client instance. * * Parameters: * mosq - a struct mosquitto pointer to free. * * See Also: * , */ libmosq_EXPORT void mosquitto_destroy(struct mosquitto *mosq); /* * Function: mosquitto_reinitialise * * This function allows an existing mosquitto client to be reused. Call on a * mosquitto instance to close any open network connections, free memory * and reinitialise the client with the new parameters. The end result is the * same as the output of . * * Parameters: * mosq - a valid mosquitto instance. * id - string to use as the client id. If NULL, a random client id * will be generated. If id is NULL, clean_session must be true. * clean_session - set to true to instruct the broker to clean all messages * and subscriptions on disconnect, false to instruct it to * keep them. See the man page mqtt(7) for more details. * Must be set to true if the id parameter is NULL. * obj - A user pointer that will be passed as an argument to any * callbacks that are specified. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * See Also: * , */ libmosq_EXPORT int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *obj); /* * Function: mosquitto_will_set * * Configure will information for a mosquitto instance. By default, clients do * not have a will. This must be called before calling . * * Parameters: * mosq - a valid mosquitto instance. * topic - the topic on which to publish the will. * payloadlen - the size of the payload (bytes). Valid values are between 0 and * 268,435,455. * payload - pointer to the data to send. If payloadlen > 0 this must be a * valid memory location. * qos - integer value 0, 1 or 2 indicating the Quality of Service to be * used for the will. * retain - set to true to make the will a retained message. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. */ libmosq_EXPORT int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain); /* * Function: mosquitto_will_clear * * Remove a previously configured will. This must be called before calling * . * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. */ libmosq_EXPORT int mosquitto_will_clear(struct mosquitto *mosq); /* * Function: mosquitto_username_pw_set * * Configure username and password for a mosquitton instance. This is only * supported by brokers that implement the MQTT spec v3.1. By default, no * username or password will be sent. * If username is NULL, the password argument is ignored. * This must be called before calling mosquitto_connect(). * * This is must be called before calling . * * Parameters: * mosq - a valid mosquitto instance. * username - the username to send as a string, or NULL to disable * authentication. * password - the password to send as a string. Set to NULL when username is * valid in order to send just a username. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. */ libmosq_EXPORT int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password); /* * Function: mosquitto_connect * * Connect to an MQTT broker. * * Parameters: * mosq - a valid mosquitto instance. * host - the hostname or ip address of the broker to connect to. * port - the network port to connect to. Usually 1883. * keepalive - the number of seconds after which the broker should send a PING * message to the client if no other messages have been exchanged * in that time. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , , , */ libmosq_EXPORT int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive); /* * Function: mosquitto_connect_bind * * Connect to an MQTT broker. This extends the functionality of * by adding the bind_address parameter. Use this function * if you need to restrict network communication over a particular interface. * * Parameters: * mosq - a valid mosquitto instance. * host - the hostname or ip address of the broker to connect to. * port - the network port to connect to. Usually 1883. * keepalive - the number of seconds after which the broker should send a PING * message to the client if no other messages have been exchanged * in that time. * bind_address - the hostname or ip address of the local network interface to * bind to. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , */ libmosq_EXPORT int mosquitto_connect_bind(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); /* * Function: mosquitto_connect_async * * Connect to an MQTT broker. This is a non-blocking call. If you use * your client must use the threaded interface * . If you need to use , you must use * to connect the client. * * May be called before or after . * * Parameters: * mosq - a valid mosquitto instance. * host - the hostname or ip address of the broker to connect to. * port - the network port to connect to. Usually 1883. * keepalive - the number of seconds after which the broker should send a PING * message to the client if no other messages have been exchanged * in that time. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , , , */ libmosq_EXPORT int mosquitto_connect_async(struct mosquitto *mosq, const char *host, int port, int keepalive); /* * Function: mosquitto_connect_bind_async * * Connect to an MQTT broker. This is a non-blocking call. If you use * your client must use the threaded interface * . If you need to use , you must use * to connect the client. * * This extends the functionality of by adding the * bind_address parameter. Use this function if you need to restrict network * communication over a particular interface. * * May be called before or after . * * Parameters: * mosq - a valid mosquitto instance. * host - the hostname or ip address of the broker to connect to. * port - the network port to connect to. Usually 1883. * keepalive - the number of seconds after which the broker should send a PING * message to the client if no other messages have been exchanged * in that time. * bind_address - the hostname or ip address of the local network interface to * bind to. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , */ libmosq_EXPORT int mosquitto_connect_bind_async(struct mosquitto *mosq, const char *host, int port, int keepalive, const char *bind_address); /* * Function: mosquitto_connect_srv * * Connect to an MQTT broker. This is a non-blocking call. If you use * your client must use the threaded interface * . If you need to use , you must use * to connect the client. * * This extends the functionality of by adding the * bind_address parameter. Use this function if you need to restrict network * communication over a particular interface. * * May be called before or after . * * Parameters: * mosq - a valid mosquitto instance. * host - the hostname or ip address of the broker to connect to. * keepalive - the number of seconds after which the broker should send a PING * message to the client if no other messages have been exchanged * in that time. * bind_address - the hostname or ip address of the local network interface to * bind to. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , */ libmosq_EXPORT int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address); /* * Function: mosquitto_reconnect * * Reconnect to a broker. * * This function provides an easy way of reconnecting to a broker after a * connection has been lost. It uses the values that were provided in the * call. It must not be called before * . * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , */ libmosq_EXPORT int mosquitto_reconnect(struct mosquitto *mosq); /* * Function: mosquitto_reconnect_async * * Reconnect to a broker. Non blocking version of . * * This function provides an easy way of reconnecting to a broker after a * connection has been lost. It uses the values that were provided in the * or calls. It must not be * called before . * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , */ libmosq_EXPORT int mosquitto_reconnect_async(struct mosquitto *mosq); /* * Function: mosquitto_disconnect * * Disconnect from the broker. * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. */ libmosq_EXPORT int mosquitto_disconnect(struct mosquitto *mosq); /* * Function: mosquitto_publish * * Publish a message on a given topic. * * Parameters: * mosq - a valid mosquitto instance. * mid - pointer to an int. If not NULL, the function will set this * to the message id of this particular message. This can be then * used with the publish callback to determine when the message * has been sent. * Note that although the MQTT protocol doesn't use message ids * for messages with QoS=0, libmosquitto assigns them message ids * so they can be tracked with this parameter. * topic - null terminated string of the topic to publish to. * payloadlen - the size of the payload (bytes). Valid values are between 0 and * 268,435,455. * payload - pointer to the data to send. If payloadlen > 0 this must be a * valid memory location. * qos - integer value 0, 1 or 2 indicating the Quality of Service to be * used for the message. * retain - set to true to make the message retained. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the * broker. * MOSQ_ERR_PAYLOAD_SIZE - if payloadlen is too large. * * See Also: * */ libmosq_EXPORT int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain); /* * Function: mosquitto_subscribe * * Subscribe to a topic. * * Parameters: * mosq - a valid mosquitto instance. * mid - a pointer to an int. If not NULL, the function will set this to * the message id of this particular message. This can be then used * with the subscribe callback to determine when the message has been * sent. * sub - the subscription pattern. * qos - the requested Quality of Service for this subscription. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. */ libmosq_EXPORT int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos); /* * Function: mosquitto_unsubscribe * * Unsubscribe from a topic. * * Parameters: * mosq - a valid mosquitto instance. * mid - a pointer to an int. If not NULL, the function will set this to * the message id of this particular message. This can be then used * with the unsubscribe callback to determine when the message has been * sent. * sub - the unsubscription pattern. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. */ libmosq_EXPORT int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub); /* * Function: mosquitto_message_copy * * Copy the contents of a mosquitto message to another message. * Useful for preserving a message received in the on_message() callback. * * Parameters: * dst - a pointer to a valid mosquitto_message struct to copy to. * src - a pointer to a valid mosquitto_message struct to copy from. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * See Also: * */ libmosq_EXPORT int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src); /* * Function: mosquitto_message_free * * Completely free a mosquitto_message struct. * * Parameters: * message - pointer to a mosquitto_message pointer to free. * * See Also: * */ libmosq_EXPORT void mosquitto_message_free(struct mosquitto_message **message); /* * Function: mosquitto_loop * * The main network loop for the client. You must call this frequently in order * to keep communications between the client and broker working. If incoming * data is present it will then be processed. Outgoing commands, from e.g. * , are normally sent immediately that their function is * called, but this is not always possible. will also attempt * to send any remaining outgoing messages, which also includes commands that * are part of the flow for messages with QoS>0. * * An alternative approach is to use to run the client * loop in its own thread. * * This calls select() to monitor the client network socket. If you want to * integrate mosquitto client operation with your own select() call, use * , , and * . * * Threads: * * Parameters: * mosq - a valid mosquitto instance. * timeout - Maximum number of milliseconds to wait for network activity * in the select() call before timing out. Set to 0 for instant * return. Set negative to use the default of 1000ms. * max_packets - this parameter is currently unused and should be set to 1 for * future compatibility. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the * broker. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * See Also: * , , */ libmosq_EXPORT int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets); /* * Function: mosquitto_loop_forever * * This function call loop() for you in an infinite blocking loop. It is useful * for the case where you only want to run the MQTT client loop in your * program. * * It handles reconnecting in case server connection is lost. If you call * mosquitto_disconnect() in a callback it will return. * * Parameters: * mosq - a valid mosquitto instance. * timeout - Maximum number of milliseconds to wait for network activity * in the select() call before timing out. Set to 0 for instant * return. Set negative to use the default of 1000ms. * max_packets - this parameter is currently unused and should be set to 1 for * future compatibility. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the * broker. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , */ libmosq_EXPORT int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets); /* * Function: mosquitto_loop_start * * This is part of the threaded client interface. Call this once to start a new * thread to process network traffic. This provides an alternative to * repeatedly calling yourself. * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available. * * See Also: * , , , */ libmosq_EXPORT int mosquitto_loop_start(struct mosquitto *mosq); /* * Function: mosquitto_loop_stop * * This is part of the threaded client interface. Call this once to stop the * network thread previously created with . This call * will block until the network thread finishes. For the network thread to end, * you must have previously called or have set the force * parameter to true. * * Parameters: * mosq - a valid mosquitto instance. * force - set to true to force thread cancellation. If false, * must have already been called. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOT_SUPPORTED - if thread support is not available. * * See Also: * , */ libmosq_EXPORT int mosquitto_loop_stop(struct mosquitto *mosq, bool force); /* * Function: mosquitto_socket * * Return the socket handle for a mosquitto instance. Useful if you want to * include a mosquitto client in your own select() calls. * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * The socket for the mosquitto client or -1 on failure. */ libmosq_EXPORT int mosquitto_socket(struct mosquitto *mosq); /* * Function: mosquitto_loop_read * * Carry out network read operations. * This should only be used if you are not using mosquitto_loop() and are * monitoring the client network socket for activity yourself. * * Parameters: * mosq - a valid mosquitto instance. * max_packets - this parameter is currently unused and should be set to 1 for * future compatibility. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the * broker. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , */ libmosq_EXPORT int mosquitto_loop_read(struct mosquitto *mosq, int max_packets); /* * Function: mosquitto_loop_write * * Carry out network write operations. * This should only be used if you are not using mosquitto_loop() and are * monitoring the client network socket for activity yourself. * * Parameters: * mosq - a valid mosquitto instance. * max_packets - this parameter is currently unused and should be set to 1 for * future compatibility. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * MOSQ_ERR_CONN_LOST - if the connection to the broker was lost. * MOSQ_ERR_PROTOCOL - if there is a protocol error communicating with the * broker. * MOSQ_ERR_ERRNO - if a system call returned an error. The variable errno * contains the error code, even on Windows. * Use strerror_r() where available or FormatMessage() on * Windows. * * See Also: * , , , */ libmosq_EXPORT int mosquitto_loop_write(struct mosquitto *mosq, int max_packets); /* * Function: mosquitto_loop_misc * * Carry out miscellaneous operations required as part of the network loop. * This should only be used if you are not using mosquitto_loop() and are * monitoring the client network socket for activity yourself. * * This function deals with handling PINGs and checking whether messages need * to be retried, so should be called fairly frequently. * * Parameters: * mosq - a valid mosquitto instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NO_CONN - if the client isn't connected to a broker. * * See Also: * , , */ libmosq_EXPORT int mosquitto_loop_misc(struct mosquitto *mosq); /* * Function: mosquitto_want_write * * Returns true if there is data ready to be written on the socket. * * Parameters: * mosq - a valid mosquitto instance. * * See Also: * , , */ libmosq_EXPORT bool mosquitto_want_write(struct mosquitto *mosq); /* * Function: mosquitto_threaded_set * * Used to tell the library that your application is using threads, but not * using . The library operates slightly differently when * not in threaded mode in order to simplify its operation. If you are managing * your own threads and do not use this function you will experience crashes * due to race conditions. * * When using , this is set automatically. * * Parameters: * mosq - a valid mosquitto instance. * threaded - true if your application is using threads, false otherwise. */ libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded); /* * Function: mosquitto_opts_set * * Used to set options for the client. * * Parameters: * mosq - a valid mosquitto instance. * option - the option to set. * value - the option specific value. * * Options: * MOSQ_OPT_PROTOCOL_VERSION - value must be an int, set to either * MQTT_PROTOCOL_V31 or MQTT_PROTOCOL_V311. Must * be set before the client connects. Defaults to * MQTT_PROTOCOL_V31. */ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value); /* * Function: mosquitto_tls_set * * Configure the client for certificate based SSL/TLS support. Must be called * before . * * Cannot be used in conjunction with . * * Define the Certificate Authority certificates to be trusted (ie. the server * certificate must be signed with one of these certificates) using cafile. * * If the server you are connecting to requires clients to provide a * certificate, define certfile and keyfile with your client certificate and * private key. If your private key is encrypted, provide a password callback * function or you will have to enter the password at the command line. * * Parameters: * mosq - a valid mosquitto instance. * cafile - path to a file containing the PEM encoded trusted CA * certificate files. Either cafile or capath must not be NULL. * capath - path to a directory containing the PEM encoded trusted CA * certificate files. See mosquitto.conf for more details on * configuring this directory. Either cafile or capath must not * be NULL. * certfile - path to a file containing the PEM encoded certificate file * for this client. If NULL, keyfile must also be NULL and no * client certificate will be used. * keyfile - path to a file containing the PEM encoded private key for * this client. If NULL, certfile must also be NULL and no * client certificate will be used. * pw_callback - if keyfile is encrypted, set pw_callback to allow your client * to pass the correct password for decryption. If set to NULL, * the password must be entered on the command line. * Your callback must write the password into "buf", which is * "size" bytes long. The return value must be the length of the * password. "userdata" will be set to the calling mosquitto * instance. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * See Also: * , , */ libmosq_EXPORT int mosquitto_tls_set(struct mosquitto *mosq, const char *cafile, const char *capath, const char *certfile, const char *keyfile, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata)); /* * Function: mosquitto_tls_insecure_set * * Configure verification of the server hostname in the server certificate. If * value is set to true, it is impossible to guarantee that the host you are * connecting to is not impersonating your server. This can be useful in * initial server testing, but makes it possible for a malicious third party to * impersonate your server through DNS spoofing, for example. * Do not use this function in a real system. Setting value to true makes the * connection encryption pointless. * Must be called before . * * Parameters: * mosq - a valid mosquitto instance. * value - if set to false, the default, certificate hostname checking is * performed. If set to true, no hostname checking is performed and * the connection is insecure. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * * See Also: * */ libmosq_EXPORT int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value); /* * Function: mosquitto_tls_opts_set * * Set advanced SSL/TLS options. Must be called before . * * Parameters: * mosq - a valid mosquitto instance. * cert_reqs - an integer defining the verification requirements the client * will impose on the server. This can be one of: * * SSL_VERIFY_NONE (0): the server will not be verified in any way. * * SSL_VERIFY_PEER (1): the server certificate will be verified * and the connection aborted if the verification fails. * The default and recommended value is SSL_VERIFY_PEER. Using * SSL_VERIFY_NONE provides no security. * tls_version - the version of the SSL/TLS protocol to use as a string. If NULL, * the default value is used. The default value and the * available values depend on the version of openssl that the * library was compiled against. For openssl >= 1.0.1, the * available options are tlsv1.2, tlsv1.1 and tlsv1, with tlv1.2 * as the default. For openssl < 1.0.1, only tlsv1 is available. * ciphers - a string describing the ciphers available for use. See the * "openssl ciphers" tool for more information. If NULL, the * default ciphers will be used. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * See Also: * */ libmosq_EXPORT int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers); /* * Function: mosquitto_tls_psk_set * * Configure the client for pre-shared-key based TLS support. Must be called * before . * * Cannot be used in conjunction with . * * Parameters: * mosq - a valid mosquitto instance. * psk - the pre-shared-key in hex format with no leading "0x". * identity - the identity of this client. May be used as the username * depending on the server settings. * ciphers - a string describing the PSK ciphers available for use. See the * "openssl ciphers" tool for more information. If NULL, the * default ciphers will be used. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * See Also: * */ libmosq_EXPORT int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers); /* * Function: mosquitto_connect_callback_set * * Set the connect callback. This is called when the broker sends a CONNACK * message in response to a connection. * * Parameters: * mosq - a valid mosquitto instance. * on_connect - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj, int rc) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * rc - the return code of the connection response, one of: * * * 0 - success * * 1 - connection refused (unacceptable protocol version) * * 2 - connection refused (identifier rejected) * * 3 - connection refused (broker unavailable) * * 4-255 - reserved for future use */ libmosq_EXPORT void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int)); /* * Function: mosquitto_disconnect_callback_set * * Set the disconnect callback. This is called when the broker has received the * DISCONNECT command and has disconnected the client. * * Parameters: * mosq - a valid mosquitto instance. * on_disconnect - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * rc - integer value indicating the reason for the disconnect. A value of 0 * means the client has called . Any other value * indicates that the disconnect is unexpected. */ libmosq_EXPORT void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int)); /* * Function: mosquitto_publish_callback_set * * Set the publish callback. This is called when a message initiated with * has been sent to the broker successfully. * * Parameters: * mosq - a valid mosquitto instance. * on_publish - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj, int mid) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * mid - the message id of the sent message. */ libmosq_EXPORT void mosquitto_publish_callback_set(struct mosquitto *mosq, void (*on_publish)(struct mosquitto *, void *, int)); /* * Function: mosquitto_message_callback_set * * Set the message callback. This is called when a message is received from the * broker. * * Parameters: * mosq - a valid mosquitto instance. * on_message - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * message - the message data. This variable and associated memory will be * freed by the library after the callback completes. The client * should make copies of any of the data it requires. * * See Also: * */ libmosq_EXPORT void mosquitto_message_callback_set(struct mosquitto *mosq, void (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *)); /* * Function: mosquitto_subscribe_callback_set * * Set the subscribe callback. This is called when the broker responds to a * subscription request. * * Parameters: * mosq - a valid mosquitto instance. * on_subscribe - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * mid - the message id of the subscribe message. * qos_count - the number of granted subscriptions (size of granted_qos). * granted_qos - an array of integers indicating the granted QoS for each of * the subscriptions. */ libmosq_EXPORT void mosquitto_subscribe_callback_set(struct mosquitto *mosq, void (*on_subscribe)(struct mosquitto *, void *, int, int, const int *)); /* * Function: mosquitto_unsubscribe_callback_set * * Set the unsubscribe callback. This is called when the broker responds to a * unsubscription request. * * Parameters: * mosq - a valid mosquitto instance. * on_unsubscribe - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj, int mid) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * mid - the message id of the unsubscribe message. */ libmosq_EXPORT void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int)); /* * Function: mosquitto_log_callback_set * * Set the logging callback. This should be used if you want event logging * information from the client library. * * mosq - a valid mosquitto instance. * on_log - a callback function in the following form: * void callback(struct mosquitto *mosq, void *obj, int level, const char *str) * * Callback Parameters: * mosq - the mosquitto instance making the callback. * obj - the user data provided in * level - the log message level from the values: * MOSQ_LOG_INFO * MOSQ_LOG_NOTICE * MOSQ_LOG_WARNING * MOSQ_LOG_ERR * MOSQ_LOG_DEBUG * str - the message string. */ libmosq_EXPORT void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *)); /* * Function: mosquitto_reconnect_delay_set * * Control the behaviour of the client when it has unexpectedly disconnected in * or after . The default * behaviour if this function is not used is to repeatedly attempt to reconnect * with a delay of 1 second until the connection succeeds. * * Use reconnect_delay parameter to change the delay between successive * reconnection attempts. You may also enable exponential backoff of the time * between reconnections by setting reconnect_exponential_backoff to true and * set an upper bound on the delay with reconnect_delay_max. * * Example 1: * delay=2, delay_max=10, exponential_backoff=False * Delays would be: 2, 4, 6, 8, 10, 10, ... * * Example 2: * delay=3, delay_max=30, exponential_backoff=True * Delays would be: 3, 6, 12, 24, 30, 30, ... * * Parameters: * mosq - a valid mosquitto instance. * reconnect_delay - the number of seconds to wait between * reconnects. * reconnect_delay_max - the maximum number of seconds to wait * between reconnects. * reconnect_exponential_backoff - use exponential backoff between * reconnect attempts. Set to true to enable * exponential backoff. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. */ libmosq_EXPORT int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff); /* * Function: mosquitto_max_inflight_messages_set * * Set the number of QoS 1 and 2 messages that can be "in flight" at one time. * An in flight message is part way through its delivery flow. Attempts to send * further messages with will result in the messages being * queued until the number of in flight messages reduces. * * A higher number here results in greater message throughput, but if set * higher than the maximum in flight messages on the broker may lead to * delays in the messages being acknowledged. * * Set to 0 for no maximum. * * Parameters: * mosq - a valid mosquitto instance. * max_inflight_messages - the maximum number of inflight messages. Defaults * to 20. * * Returns: * MOSQ_ERR_SUCCESS - on success. * MOSQ_ERR_INVAL - if the input parameters were invalid. */ libmosq_EXPORT int mosquitto_max_inflight_messages_set(struct mosquitto *mosq, unsigned int max_inflight_messages); /* * Function: mosquitto_message_retry_set * * Set the number of seconds to wait before retrying messages. This applies to * publish messages with QoS>0. May be called at any time. * * Parameters: * mosq - a valid mosquitto instance. * message_retry - the number of seconds to wait for a response before * retrying. Defaults to 20. */ libmosq_EXPORT void mosquitto_message_retry_set(struct mosquitto *mosq, unsigned int message_retry); /* * Function: mosquitto_user_data_set * * When is called, the pointer given as the "obj" parameter * will be passed to the callbacks as user data. The * function allows this obj parameter to be updated at any time. This function * will not modify the memory pointed to by the current user data pointer. If * it is dynamically allocated memory you must free it yourself. * * Parameters: * mosq - a valid mosquitto instance. * obj - A user pointer that will be passed as an argument to any callbacks * that are specified. */ libmosq_EXPORT void mosquitto_user_data_set(struct mosquitto *mosq, void *obj); /* ============================================================================= * * Section: SOCKS5 proxy functions * * ============================================================================= */ /* * Function: mosquitto_socks5_set * * Configure the client to use a SOCKS5 proxy when connecting. Must be called * before connecting. "None" and "username/password" authentication is * supported. * * Parameters: * mosq - a valid mosquitto instance. * host - the SOCKS5 proxy host to connect to. * port - the SOCKS5 proxy port to use. * username - if not NULL, use this username when authenticating with the proxy. * password - if not NULL and username is not NULL, use this password when * authenticating with the proxy. */ libmosq_EXPORT int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password); /* ============================================================================= * * Section: Utility functions * * ============================================================================= */ /* * Function: mosquitto_strerror * * Call to obtain a const string description of a mosquitto error number. * * Parameters: * mosq_errno - a mosquitto error number. * * Returns: * A constant string describing the error. */ libmosq_EXPORT const char *mosquitto_strerror(int mosq_errno); /* * Function: mosquitto_connack_string * * Call to obtain a const string description of an MQTT connection result. * * Parameters: * connack_code - an MQTT connection result. * * Returns: * A constant string describing the result. */ libmosq_EXPORT const char *mosquitto_connack_string(int connack_code); /* * Function: mosquitto_sub_topic_tokenise * * Tokenise a topic or subscription string into an array of strings * representing the topic hierarchy. * * For example: * * subtopic: "a/deep/topic/hierarchy" * * Would result in: * * topics[0] = "a" * topics[1] = "deep" * topics[2] = "topic" * topics[3] = "hierarchy" * * and: * * subtopic: "/a/deep/topic/hierarchy/" * * Would result in: * * topics[0] = NULL * topics[1] = "a" * topics[2] = "deep" * topics[3] = "topic" * topics[4] = "hierarchy" * * Parameters: * subtopic - the subscription/topic to tokenise * topics - a pointer to store the array of strings * count - an int pointer to store the number of items in the topics array. * * Returns: * MOSQ_ERR_SUCCESS - on success * MOSQ_ERR_NOMEM - if an out of memory condition occurred. * * Example: * * > char **topics; * > int topic_count; * > int i; * > * > mosquitto_sub_topic_tokenise("$SYS/broker/uptime", &topics, &topic_count); * > * > for(i=0; i printf("%d: %s\n", i, topics[i]); * > } * * See Also: * */ libmosq_EXPORT int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count); /* * Function: mosquitto_sub_topic_tokens_free * * Free memory that was allocated in . * * Parameters: * topics - pointer to string array. * count - count of items in string array. * * Returns: * MOSQ_ERR_SUCCESS - on success * MOSQ_ERR_INVAL - if the input parameters were invalid. * * See Also: * */ libmosq_EXPORT int mosquitto_sub_topic_tokens_free(char ***topics, int count); /* * Function: mosquitto_topic_matches_sub * * Check whether a topic matches a subscription. * * For example: * * foo/bar would match the subscription foo/# or +/bar * non/matching would not match the subscription non/+/+ * * Parameters: * sub - subscription string to check topic against. * topic - topic to check. * result - bool pointer to hold result. Will be set to true if the topic * matches the subscription. * * Returns: * MOSQ_ERR_SUCCESS - on success * MOSQ_ERR_INVAL - if the input parameters were invalid. * MOSQ_ERR_NOMEM - if an out of memory condition occurred. */ libmosq_EXPORT int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result); /* * Function: mosquitto_pub_topic_check * * Check whether a topic to be used for publishing is valid. * * This searches for + or # in a topic and checks its length. * * This check is already carried out in and * , there is no need to call it directly before them. It * may be useful if you wish to check the validity of a topic in advance of * making a connection for example. * * Parameters: * topic - the topic to check * * Returns: * MOSQ_ERR_SUCCESS - for a valid topic * MOSQ_ERR_INVAL - if the topic contains a + or a #, or if it is too long. * * See Also: * */ libmosq_EXPORT int mosquitto_pub_topic_check(const char *topic); /* * Function: mosquitto_sub_topic_check * * Check whether a topic to be used for subscribing is valid. * * This searches for + or # in a topic and checks that they aren't in invalid * positions, such as with foo/#/bar, foo/+bar or foo/bar#, and checks its * length. * * This check is already carried out in and * , there is no need to call it directly before them. * It may be useful if you wish to check the validity of a topic in advance of * making a connection for example. * * Parameters: * topic - the topic to check * * Returns: * MOSQ_ERR_SUCCESS - for a valid topic * MOSQ_ERR_INVAL - if the topic contains a + or a # that is in an invalid * position, or if it is too long. * * See Also: * */ libmosq_EXPORT int mosquitto_sub_topic_check(const char *topic); #ifdef __cplusplus } #endif #endif mosquitto-1.4.15/lib/memory_mosq.h0000664000175000017500000000236513245550210016157 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 #include #if defined(WITH_MEMORY_TRACKING) && defined(WITH_BROKER) && !defined(WIN32) && !defined(__SYMBIAN32__) && !defined(__ANDROID__) && !defined(__UCLIBC__) && !defined(__OpenBSD__) #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 mosquitto-1.4.15/lib/will_mosq.c0000664000175000017500000000501713245550210015606 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 #include #include #include #include int _mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { int rc = MOSQ_ERR_SUCCESS; if(!mosq || !topic) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(payloadlen > 0 && !payload) return MOSQ_ERR_INVAL; if(mosquitto_pub_topic_check(topic)) return MOSQ_ERR_INVAL; if(mosq->will){ if(mosq->will->topic){ _mosquitto_free(mosq->will->topic); mosq->will->topic = NULL; } if(mosq->will->payload){ _mosquitto_free(mosq->will->payload); mosq->will->payload = NULL; } _mosquitto_free(mosq->will); mosq->will = NULL; } mosq->will = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!mosq->will) return MOSQ_ERR_NOMEM; mosq->will->topic = _mosquitto_strdup(topic); if(!mosq->will->topic){ rc = MOSQ_ERR_NOMEM; goto cleanup; } mosq->will->payloadlen = payloadlen; if(mosq->will->payloadlen > 0){ if(!payload){ rc = MOSQ_ERR_INVAL; goto cleanup; } mosq->will->payload = _mosquitto_malloc(sizeof(char)*mosq->will->payloadlen); if(!mosq->will->payload){ rc = MOSQ_ERR_NOMEM; goto cleanup; } memcpy(mosq->will->payload, payload, payloadlen); } mosq->will->qos = qos; mosq->will->retain = retain; return MOSQ_ERR_SUCCESS; cleanup: if(mosq->will){ if(mosq->will->topic) _mosquitto_free(mosq->will->topic); if(mosq->will->payload) _mosquitto_free(mosq->will->payload); } _mosquitto_free(mosq->will); mosq->will = NULL; return rc; } int _mosquitto_will_clear(struct mosquitto *mosq) { if(!mosq->will) return MOSQ_ERR_SUCCESS; if(mosq->will->topic){ _mosquitto_free(mosq->will->topic); mosq->will->topic = NULL; } if(mosq->will->payload){ _mosquitto_free(mosq->will->payload); mosq->will->payload = NULL; } _mosquitto_free(mosq->will); mosq->will = NULL; return MOSQ_ERR_SUCCESS; } mosquitto-1.4.15/lib/read_handle.c0000664000175000017500000001064213245550210016026 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include #include #include #include #include #include #include int _mosquitto_packet_handle(struct mosquitto *mosq) { assert(mosq); switch((mosq->in_packet.command)&0xF0){ case PINGREQ: return _mosquitto_handle_pingreq(mosq); case PINGRESP: return _mosquitto_handle_pingresp(mosq); case PUBACK: return _mosquitto_handle_pubackcomp(mosq, "PUBACK"); case PUBCOMP: return _mosquitto_handle_pubackcomp(mosq, "PUBCOMP"); case PUBLISH: return _mosquitto_handle_publish(mosq); case PUBREC: return _mosquitto_handle_pubrec(mosq); case PUBREL: return _mosquitto_handle_pubrel(NULL, mosq); case CONNACK: return _mosquitto_handle_connack(mosq); case SUBACK: return _mosquitto_handle_suback(mosq); case UNSUBACK: return _mosquitto_handle_unsuback(mosq); default: /* If we don't recognise the command, return an error straight away. */ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: Unrecognised command %d\n", (mosq->in_packet.command)&0xF0); return MOSQ_ERR_PROTOCOL; } } int _mosquitto_handle_publish(struct mosquitto *mosq) { uint8_t header; struct mosquitto_message_all *message; int rc = 0; uint16_t mid; assert(mosq); 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 = _mosquitto_read_string(&mosq->in_packet, &message->msg.topic); if(rc){ _mosquitto_message_cleanup(&message); return rc; } if(!strlen(message->msg.topic)){ _mosquitto_message_cleanup(&message); return MOSQ_ERR_PROTOCOL; } if(message->msg.qos > 0){ rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc){ _mosquitto_message_cleanup(&message); return rc; } message->msg.mid = (int)mid; } 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){ _mosquitto_message_cleanup(&message); return MOSQ_ERR_NOMEM; } rc = _mosquitto_read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen); if(rc){ _mosquitto_message_cleanup(&message); return rc; } } _mosquitto_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; } pthread_mutex_unlock(&mosq->callback_mutex); _mosquitto_message_cleanup(&message); return MOSQ_ERR_SUCCESS; case 1: rc = _mosquitto_send_puback(mosq, message->msg.mid); 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; } pthread_mutex_unlock(&mosq->callback_mutex); _mosquitto_message_cleanup(&message); return rc; case 2: rc = _mosquitto_send_pubrec(mosq, message->msg.mid); pthread_mutex_lock(&mosq->in_message_mutex); message->state = mosq_ms_wait_for_pubrel; _mosquitto_message_queue(mosq, message, mosq_md_in); pthread_mutex_unlock(&mosq->in_message_mutex); return rc; default: _mosquitto_message_cleanup(&message); return MOSQ_ERR_PROTOCOL; } } mosquitto-1.4.15/lib/send_mosq.c0000664000175000017500000002073713245550210015576 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #ifdef WITH_BROKER #include # ifdef WITH_SYS_TREE extern uint64_t g_pub_bytes_sent; # endif #endif #include #include #include #include #include #include #include #include #include int _mosquitto_send_pingreq(struct mosquitto *mosq) { int rc; assert(mosq); #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGREQ to %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGREQ", mosq->id); #endif rc = _mosquitto_send_simple_command(mosq, PINGREQ); if(rc == MOSQ_ERR_SUCCESS){ mosq->ping_t = mosquitto_time(); } return rc; } int _mosquitto_send_pingresp(struct mosquitto *mosq) { #ifdef WITH_BROKER if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGRESP to %s", mosq->id); #else if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGRESP", mosq->id); #endif return _mosquitto_send_simple_command(mosq, PINGRESP); } int _mosquitto_send_puback(struct mosquitto *mosq, uint16_t mid) { #ifdef WITH_BROKER if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBACK to %s (Mid: %d)", mosq->id, mid); #else if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBACK (Mid: %d)", mosq->id, mid); #endif return _mosquitto_send_command_with_mid(mosq, PUBACK, mid, false); } int _mosquitto_send_pubcomp(struct mosquitto *mosq, uint16_t mid) { #ifdef WITH_BROKER if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBCOMP to %s (Mid: %d)", mosq->id, mid); #else if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBCOMP (Mid: %d)", mosq->id, mid); #endif return _mosquitto_send_command_with_mid(mosq, PUBCOMP, mid, false); } int _mosquitto_send_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup) { #ifdef WITH_BROKER size_t len; #ifdef WITH_BRIDGE int i; struct _mqtt3_bridge_topic *cur_topic; bool match; int rc; char *mapped_topic = NULL; char *topic_temp = NULL; #endif #endif assert(mosq); assert(topic); #if defined(WITH_BROKER) && defined(WITH_WEBSOCKETS) if(mosq->sock == INVALID_SOCKET && !mosq->wsi) return MOSQ_ERR_NO_CONN; #else if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; #endif #ifdef WITH_BROKER if(mosq->listener && mosq->listener->mount_point){ len = strlen(mosq->listener->mount_point); if(len < strlen(topic)){ topic += len; }else{ /* Invalid topic string. Should never happen, but silently swallow the message anyway. */ return MOSQ_ERR_SUCCESS; } } #ifdef WITH_BRIDGE if(mosq->bridge && mosq->bridge->topics && mosq->bridge->topic_remapping){ for(i=0; ibridge->topic_count; i++){ cur_topic = &mosq->bridge->topics[i]; if((cur_topic->direction == bd_both || cur_topic->direction == bd_out) && (cur_topic->remote_prefix || cur_topic->local_prefix)){ /* Topic mapping required on this topic if the message matches */ rc = mosquitto_topic_matches_sub(cur_topic->local_topic, topic, &match); if(rc){ return rc; } if(match){ mapped_topic = _mosquitto_strdup(topic); if(!mapped_topic) return MOSQ_ERR_NOMEM; if(cur_topic->local_prefix){ /* This prefix needs removing. */ if(!strncmp(cur_topic->local_prefix, mapped_topic, strlen(cur_topic->local_prefix))){ topic_temp = _mosquitto_strdup(mapped_topic+strlen(cur_topic->local_prefix)); _mosquitto_free(mapped_topic); if(!topic_temp){ return MOSQ_ERR_NOMEM; } mapped_topic = topic_temp; } } if(cur_topic->remote_prefix){ /* This prefix needs adding. */ len = strlen(mapped_topic) + strlen(cur_topic->remote_prefix)+1; topic_temp = _mosquitto_malloc(len+1); if(!topic_temp){ _mosquitto_free(mapped_topic); return MOSQ_ERR_NOMEM; } snprintf(topic_temp, len, "%s%s", cur_topic->remote_prefix, mapped_topic); topic_temp[len] = '\0'; _mosquitto_free(mapped_topic); mapped_topic = topic_temp; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen); #ifdef WITH_SYS_TREE g_pub_bytes_sent += payloadlen; #endif rc = _mosquitto_send_real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup); _mosquitto_free(mapped_topic); return rc; } } } } #endif _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen); # ifdef WITH_SYS_TREE g_pub_bytes_sent += payloadlen; # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen); #endif return _mosquitto_send_real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup); } int _mosquitto_send_pubrec(struct mosquitto *mosq, uint16_t mid) { #ifdef WITH_BROKER if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREC to %s (Mid: %d)", mosq->id, mid); #else if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREC (Mid: %d)", mosq->id, mid); #endif return _mosquitto_send_command_with_mid(mosq, PUBREC, mid, false); } int _mosquitto_send_pubrel(struct mosquitto *mosq, uint16_t mid) { #ifdef WITH_BROKER if(mosq) _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBREL to %s (Mid: %d)", mosq->id, mid); #else if(mosq) _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBREL (Mid: %d)", mosq->id, mid); #endif return _mosquitto_send_command_with_mid(mosq, PUBREL|2, mid, false); } /* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ int _mosquitto_send_command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup) { struct _mosquitto_packet *packet = NULL; int rc; assert(mosq); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = command; if(dup){ packet->command |= 8; } packet->remaining_length = 2; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } packet->payload[packet->pos+0] = MOSQ_MSB(mid); packet->payload[packet->pos+1] = MOSQ_LSB(mid); return _mosquitto_packet_queue(mosq, packet); } /* For DISCONNECT, PINGREQ and PINGRESP */ int _mosquitto_send_simple_command(struct mosquitto *mosq, uint8_t command) { struct _mosquitto_packet *packet = NULL; int rc; assert(mosq); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = command; packet->remaining_length = 0; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } return _mosquitto_packet_queue(mosq, packet); } int _mosquitto_send_real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup) { struct _mosquitto_packet *packet = NULL; int packetlen; int rc; assert(mosq); assert(topic); packetlen = 2+strlen(topic) + payloadlen; if(qos > 0) packetlen += 2; /* For message id */ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->mid = mid; packet->command = PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain; packet->remaining_length = packetlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header (topic string) */ _mosquitto_write_string(packet, topic, strlen(topic)); if(qos > 0){ _mosquitto_write_uint16(packet, mid); } /* Payload */ if(payloadlen){ _mosquitto_write_bytes(packet, payload, payloadlen); } return _mosquitto_packet_queue(mosq, packet); } mosquitto-1.4.15/lib/Makefile0000664000175000017500000000555413245550210015102 0ustar rogerrogerinclude ../config.mk .PHONY : really clean install MOSQ_OBJS=mosquitto.o \ logging_mosq.o \ memory_mosq.o \ messages_mosq.o \ net_mosq.o \ read_handle.o \ read_handle_client.o \ read_handle_shared.o \ send_mosq.o \ send_client_mosq.o \ socks_mosq.o \ srv_mosq.o \ thread_mosq.o \ time_mosq.o \ tls_mosq.o \ util_mosq.o \ will_mosq.o all : libmosquitto.so.${SOVERSION} libmosquitto.a $(MAKE) -C cpp install : all $(INSTALL) -d ${DESTDIR}$(prefix)/lib${LIB_SUFFIX}/ $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so.${SOVERSION} ln -sf libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so $(INSTALL) -d ${DESTDIR}${prefix}/include/ $(INSTALL) mosquitto.h ${DESTDIR}${prefix}/include/mosquitto.h $(MAKE) -C cpp install uninstall : -rm -f ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so.${SOVERSION} -rm -f ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so -rm -f ${DESTDIR}${prefix}/include/mosquitto.h reallyclean : clean clean : -rm -f *.o libmosquitto.so.${SOVERSION} libmosquitto.so libmosquitto.a $(MAKE) -C cpp clean libmosquitto.so.${SOVERSION} : ${MOSQ_OBJS} ${CROSS_COMPILE}$(CC) -shared $(LIB_LDFLAGS) $^ -o $@ ${LIB_LIBS} libmosquitto.a : ${MOSQ_OBJS} ${CROSS_COMPILE}$(AR) cr $@ $^ mosquitto.o : mosquitto.c mosquitto.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ logging_mosq.o : logging_mosq.c logging_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ messages_mosq.o : messages_mosq.c messages_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ memory_mosq.o : memory_mosq.c memory_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ net_mosq.o : net_mosq.c net_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ read_handle.o : read_handle.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ read_handle_client.o : read_handle_client.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ read_handle_shared.o : read_handle_shared.c read_handle.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ send_mosq.o : send_mosq.c send_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ send_client_mosq.o : send_client_mosq.c send_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ socks_mosq.o : socks_mosq.c ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ srv_mosq.o : srv_mosq.c ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ thread_mosq.o : thread_mosq.c ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ time_mosq.o : time_mosq.c ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ tls_mosq.o : tls_mosq.c ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ util_mosq.o : util_mosq.c util_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ will_mosq.o : will_mosq.c will_mosq.h ${CROSS_COMPILE}$(CC) $(LIB_CFLAGS) -c $< -o $@ mosquitto-1.4.15/lib/logging_mosq.h0000664000175000017500000000130613245550210016267 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 int _mosquitto_log_printf(struct mosquitto *mosq, int priority, const char *fmt, ...); #endif mosquitto-1.4.15/lib/logging_mosq.c0000664000175000017500000000252513245550210016266 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include int _mosquitto_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; } mosquitto-1.4.15/lib/read_handle_client.c0000664000175000017500000000301613245550210017361 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include int _mosquitto_handle_connack(struct mosquitto *mosq) { uint8_t byte; uint8_t result; int rc; assert(mosq); _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK", mosq->id); rc = _mosquitto_read_byte(&mosq->in_packet, &byte); // Reserved byte, not used if(rc) return rc; rc = _mosquitto_read_byte(&mosq->in_packet, &result); if(rc) return rc; pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_connect){ mosq->in_callback = true; mosq->on_connect(mosq, mosq->userdata, result); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); switch(result){ case 0: if(mosq->state != mosq_cs_disconnecting){ mosq->state = mosq_cs_connected; } return MOSQ_ERR_SUCCESS; case 1: case 2: case 3: case 4: case 5: return MOSQ_ERR_CONN_REFUSED; default: return MOSQ_ERR_PROTOCOL; } } mosquitto-1.4.15/lib/will_mosq.h0000664000175000017500000000147413245550210015616 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 _WILL_MOSQ_H_ #define _WILL_MOSQ_H_ #include #include int _mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain); int _mosquitto_will_clear(struct mosquitto *mosq); #endif mosquitto-1.4.15/lib/linker.version0000664000175000017500000000334713245550210016333 0ustar rogerroger/* Linker version script - currently used here primarily to control which * symbols are exported. */ MOSQ_1.0 { global: mosquitto_lib_version; mosquitto_lib_init; mosquitto_lib_cleanup; mosquitto_new; mosquitto_destroy; mosquitto_reinitialise; mosquitto_will_set; mosquitto_will_clear; mosquitto_username_pw_set; mosquitto_connect; mosquitto_connect_async; mosquitto_reconnect; mosquitto_disconnect; mosquitto_publish; mosquitto_subscribe; mosquitto_unsubscribe; mosquitto_message_copy; mosquitto_message_free; mosquitto_loop; mosquitto_socket; mosquitto_loop_start; mosquitto_loop_stop; mosquitto_loop_read; mosquitto_loop_write; mosquitto_loop_misc; mosquitto_connect_callback_set; mosquitto_disconnect_callback_set; mosquitto_publish_callback_set; mosquitto_message_callback_set; mosquitto_subscribe_callback_set; mosquitto_unsubscribe_callback_set; mosquitto_log_callback_set; mosquitto_message_retry_set; mosquitto_want_write; mosquitto_user_data_set; mosquitto_strerror; mosquitto_connack_string; mosquitto_tls_set; mosquitto_tls_opts_set; mosquitto_tls_psk_set; mosquitto_sub_topic_tokenise; mosquitto_sub_topic_tokens_free; mosquitto_topic_matches_sub; local: *; }; MOSQ_1.1 { global: mosquitto_loop_forever; } MOSQ_1.0; MOSQ_1.2 { global: mosquitto_connect_bind; mosquitto_connect_bind_async; mosquitto_max_inflight_messages_set; mosquitto_reconnect_delay_set; mosquitto_reconnect_async; mosquitto_tls_insecure_set; } MOSQ_1.1; MOSQ_1.3 { global: mosquitto_connect_srv; } MOSQ_1.2; MOSQ_1.4 { global: mosquitto_threaded_set; mosquitto_opts_set; mosquitto_pub_topic_check; mosquitto_sub_topic_check; mosquitto_socks5_set; } MOSQ_1.3; mosquitto-1.4.15/lib/mosquitto_internal.h0000664000175000017500000001502113245550210017541 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 _MOSQUITTO_INTERNAL_H_ #define _MOSQUITTO_INTERNAL_H_ #include #ifdef WIN32 # include #endif #ifdef WITH_TLS # include #else # include #endif #include #if defined(WITH_THREADING) && !defined(WITH_BROKER) # include #else # include #endif #ifdef WITH_SRV # include #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 # endif #else # include #endif #include "mosquitto.h" #include "time_mosq.h" #ifdef WITH_BROKER # ifdef __linux__ # include # 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_connect_async = 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, }; enum _mosquitto_protocol { mosq_p_invalid = 0, mosq_p_mqtt31 = 1, mosq_p_mqtt311 = 2, mosq_p_mqtts = 3 }; 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_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; time_t timestamp; //enum mosquitto_msg_direction direction; enum mosquitto_msg_state state; bool dup; struct mosquitto_message msg; }; 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 *will; #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; #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 in_message_mutex; pthread_mutex_t out_message_mutex; pthread_mutex_t mid_mutex; pthread_t thread_id; #endif bool clean_session; #ifdef WITH_BROKER bool is_dropping; bool is_bridge; struct _mqtt3_bridge *bridge; struct mosquitto_client_msg *msgs; struct mosquitto_client_msg *last_msg; int msg_count; int msg_count12; struct _mosquitto_acl_user *acl_list; struct _mqtt3_listener *listener; time_t disconnect_t; struct _mosquitto_packet *out_packet_last; struct _mosquitto_subhier **subs; int 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; #else # ifdef WITH_SOCKS char *socks5_host; int socks5_port; char *socks5_username; char *socks5_password; # endif void *userdata; bool in_callback; unsigned int message_retry; time_t last_retry_check; struct mosquitto_message_all *in_messages; struct mosquitto_message_all *in_messages_last; struct mosquitto_message_all *out_messages; struct mosquitto_message_all *out_messages_last; void (*on_connect)(struct mosquitto *, void *userdata, int rc); void (*on_disconnect)(struct mosquitto *, void *userdata, int rc); void (*on_publish)(struct mosquitto *, void *userdata, int mid); void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message); void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos); void (*on_unsubscribe)(struct mosquitto *, void *userdata, int mid); void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str); //void (*on_error)(); char *host; int port; int in_queue_len; int out_queue_len; char *bind_address; unsigned int reconnect_delay; unsigned int reconnect_delay_max; bool reconnect_exponential_backoff; char threaded; struct _mosquitto_packet *out_packet_last; int inflight_messages; int max_inflight_messages; # ifdef WITH_SRV ares_channel achan; # endif #endif #ifdef WITH_BROKER UT_hash_handle hh_id; UT_hash_handle hh_sock; struct mosquitto *for_free_next; #endif }; #define STREMPTY(str) (str[0] == '\0') #endif mosquitto-1.4.15/lib/thread_mosq.c0000664000175000017500000000511013245550210016100 0ustar rogerroger/* Copyright (c) 2011-2018 Roger Light 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 #ifndef WIN32 #include #endif #include #include void *_mosquitto_thread_main(void *obj); int mosquitto_loop_start(struct mosquitto *mosq) { #ifdef WITH_THREADING if(!mosq || mosq->threaded != mosq_ts_none) return MOSQ_ERR_INVAL; mosq->threaded = mosq_ts_self; if(!pthread_create(&mosq->thread_id, NULL, _mosquitto_thread_main, mosq)){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_ERRNO; } #else return MOSQ_ERR_NOT_SUPPORTED; #endif } int mosquitto_loop_stop(struct mosquitto *mosq, bool force) { #ifdef WITH_THREADING # ifndef WITH_BROKER char sockpair_data = 0; # endif if(!mosq || mosq->threaded != mosq_ts_self) return MOSQ_ERR_INVAL; /* Write a single byte to sockpairW (connected to sockpairR) to break out * of select() if in threaded mode. */ if(mosq->sockpairW != INVALID_SOCKET){ #ifndef WIN32 if(write(mosq->sockpairW, &sockpair_data, 1)){ } #else send(mosq->sockpairW, &sockpair_data, 1, 0); #endif } if(force){ pthread_cancel(mosq->thread_id); } pthread_join(mosq->thread_id, NULL); mosq->thread_id = pthread_self(); mosq->threaded = mosq_ts_none; return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif } #ifdef WITH_THREADING void *_mosquitto_thread_main(void *obj) { struct mosquitto *mosq = obj; if(!mosq) return NULL; pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_connect_async){ pthread_mutex_unlock(&mosq->state_mutex); mosquitto_reconnect(mosq); }else{ pthread_mutex_unlock(&mosq->state_mutex); } if(!mosq->keepalive){ /* Sleep for a day if keepalive disabled. */ mosquitto_loop_forever(mosq, 1000*86400, 1); }else{ /* Sleep for our keepalive value. publish() etc. will wake us up. */ mosquitto_loop_forever(mosq, mosq->keepalive*1000, 1); } return obj; } #endif int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded) { if(!mosq) return MOSQ_ERR_INVAL; if(threaded){ mosq->threaded = mosq_ts_external; }else{ mosq->threaded = mosq_ts_none; } return MOSQ_ERR_SUCCESS; } mosquitto-1.4.15/lib/memory_mosq.c0000664000175000017500000000567313245550210016157 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #ifdef REAL_WITH_MEMORY_TRACKING # if defined(__APPLE__) # include # define malloc_usable_size malloc_size # elif defined(__FreeBSD__) # include # else # include # 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) { #ifdef LINUX struct rlimit r; r.rlim_cur = lim; r.rlim_max = lim; setrlimit(RLIMIT_CPU, &r); mem_limit = 0; #else mem_limit = lim; #endif } #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 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 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 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 memcount += malloc_usable_size(str); if(memcount > max_memcount){ max_memcount = memcount; } #endif return str; } mosquitto-1.4.15/lib/read_handle_shared.c0000664000175000017500000001553013245550210017355 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_BROKER #include #endif int _mosquitto_handle_pingreq(struct mosquitto *mosq) { assert(mosq); #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PINGREQ from %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGREQ", mosq->id); #endif return _mosquitto_send_pingresp(mosq); } int _mosquitto_handle_pingresp(struct mosquitto *mosq) { assert(mosq); mosq->ping_t = 0; /* No longer waiting for a PINGRESP. */ #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PINGRESP from %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PINGRESP", mosq->id); #endif return MOSQ_ERR_SUCCESS; } #ifdef WITH_BROKER int _mosquitto_handle_pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type) #else int _mosquitto_handle_pubackcomp(struct mosquitto *mosq, const char *type) #endif { uint16_t mid; int rc; assert(mosq); rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc) return rc; #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received %s from %s (Mid: %d)", type, mosq->id, mid); if(mid){ rc = mqtt3_db_message_delete(db, mosq, mid, mosq_md_out); if(rc == MOSQ_ERR_NOT_FOUND){ _mosquitto_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 _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received %s (Mid: %d)", mosq->id, type, mid); if(!_mosquitto_message_delete(mosq, mid, mosq_md_out)){ /* 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; } pthread_mutex_unlock(&mosq->callback_mutex); } #endif return MOSQ_ERR_SUCCESS; } int _mosquitto_handle_pubrec(struct mosquitto *mosq) { uint16_t mid; int rc; assert(mosq); rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc) return rc; #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREC from %s (Mid: %d)", mosq->id, mid); rc = mqtt3_db_message_update(mosq, mid, mosq_md_out, mosq_ms_wait_for_pubcomp); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREC (Mid: %d)", mosq->id, mid); rc = _mosquitto_message_out_update(mosq, mid, mosq_ms_wait_for_pubcomp); #endif if(rc == MOSQ_ERR_NOT_FOUND){ _mosquitto_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 = _mosquitto_send_pubrel(mosq, mid); if(rc) return rc; return MOSQ_ERR_SUCCESS; } int _mosquitto_handle_pubrel(struct mosquitto_db *db, struct mosquitto *mosq) { uint16_t mid; #ifndef WITH_BROKER struct mosquitto_message_all *message = NULL; #endif int rc; assert(mosq); if(mosq->protocol == mosq_p_mqtt311){ if((mosq->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } } rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc) return rc; #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received PUBREL from %s (Mid: %d)", mosq->id, mid); if(mqtt3_db_message_release(db, mosq, mid, mosq_md_in)){ /* Message not found. Still send a PUBCOMP anyway because this could be * due to a repeated PUBREL after a client has reconnected. */ _mosquitto_log_printf(mosq, MOSQ_LOG_WARNING, "Warning: Received PUBREL from %s for an unknown packet identifier %d.", mosq->id, mid); } #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBREL (Mid: %d)", mosq->id, mid); if(!_mosquitto_message_remove(mosq, mid, mosq_md_in, &message)){ /* 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; } pthread_mutex_unlock(&mosq->callback_mutex); _mosquitto_message_cleanup(&message); } #endif rc = _mosquitto_send_pubcomp(mosq, mid); if(rc) return rc; return MOSQ_ERR_SUCCESS; } int _mosquitto_handle_suback(struct mosquitto *mosq) { uint16_t mid; uint8_t qos; int *granted_qos; int qos_count; int i = 0; int rc; assert(mosq); #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK", mosq->id); #endif rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); 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 = _mosquitto_read_byte(&mosq->in_packet, &qos); if(rc){ _mosquitto_free(granted_qos); return rc; } granted_qos[i] = (int)qos; i++; } #ifndef WITH_BROKER 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; } pthread_mutex_unlock(&mosq->callback_mutex); #endif _mosquitto_free(granted_qos); return MOSQ_ERR_SUCCESS; } int _mosquitto_handle_unsuback(struct mosquitto *mosq) { uint16_t mid; int rc; assert(mosq); #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBACK from %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received UNSUBACK", mosq->id); #endif rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc) return rc; #ifndef WITH_BROKER 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; } pthread_mutex_unlock(&mosq->callback_mutex); #endif return MOSQ_ERR_SUCCESS; } mosquitto-1.4.15/lib/util_mosq.h0000664000175000017500000000232013245550210015613 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 _UTIL_MOSQ_H_ #define _UTIL_MOSQ_H_ #include #include "tls_mosq.h" #include "mosquitto.h" #include "mosquitto_internal.h" #ifdef WITH_BROKER # include "mosquitto_broker.h" #endif int _mosquitto_packet_alloc(struct _mosquitto_packet *packet); #ifdef WITH_BROKER void _mosquitto_check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq); #else void _mosquitto_check_keepalive(struct mosquitto *mosq); #endif uint16_t _mosquitto_mid_generate(struct mosquitto *mosq); FILE *_mosquitto_fopen(const char *path, const char *mode, bool restrict_read); #ifdef REAL_WITH_TLS_PSK int _mosquitto_hex2bin(const char *hex, unsigned char *bin, int bin_max_len); #endif #endif mosquitto-1.4.15/lib/read_handle.h0000664000175000017500000000253213245550210016032 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 _READ_HANDLE_H_ #define _READ_HANDLE_H_ #include struct mosquitto_db; int _mosquitto_packet_handle(struct mosquitto *mosq); int _mosquitto_handle_connack(struct mosquitto *mosq); int _mosquitto_handle_pingreq(struct mosquitto *mosq); int _mosquitto_handle_pingresp(struct mosquitto *mosq); #ifdef WITH_BROKER int _mosquitto_handle_pubackcomp(struct mosquitto_db *db, struct mosquitto *mosq, const char *type); #else int _mosquitto_handle_pubackcomp(struct mosquitto *mosq, const char *type); #endif int _mosquitto_handle_publish(struct mosquitto *mosq); int _mosquitto_handle_pubrec(struct mosquitto *mosq); int _mosquitto_handle_pubrel(struct mosquitto_db *db, struct mosquitto *mosq); int _mosquitto_handle_suback(struct mosquitto *mosq); int _mosquitto_handle_unsuback(struct mosquitto *mosq); #endif mosquitto-1.4.15/lib/tls_mosq.h0000664000175000017500000000213513245550210015444 0ustar rogerroger/* Copyright (c) 2013-2018 Roger Light 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 _TLS_MOSQ_H_ #define _TLS_MOSQ_H_ #ifdef WITH_TLS # define SSL_DATA_PENDING(A) ((A)->ssl && SSL_pending((A)->ssl)) #else # define SSL_DATA_PENDING(A) 0 #endif #ifdef WITH_TLS #include #ifdef WITH_TLS_PSK # if OPENSSL_VERSION_NUMBER >= 0x10000000 # define REAL_WITH_TLS_PSK # else # warning "TLS-PSK not supported, openssl too old." # endif #endif int _mosquitto_server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx); int _mosquitto_verify_certificate_hostname(X509 *cert, const char *hostname); #endif /* WITH_TLS */ #endif mosquitto-1.4.15/lib/dummypthread.h0000664000175000017500000000042613245550210016307 0ustar rogerroger#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 mosquitto-1.4.15/lib/mqtt3_protocol.h0000664000175000017500000000255413245550210016601 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 _MQTT3_PROTOCOL_H_ #define _MQTT3_PROTOCOL_H_ /* For version 3 of the MQTT protocol */ #define PROTOCOL_NAME_v31 "MQIsdp" #define PROTOCOL_VERSION_v31 3 #define PROTOCOL_NAME_v311 "MQTT" #define PROTOCOL_VERSION_v311 4 /* Message types */ #define CONNECT 0x10 #define CONNACK 0x20 #define PUBLISH 0x30 #define PUBACK 0x40 #define PUBREC 0x50 #define PUBREL 0x60 #define PUBCOMP 0x70 #define SUBSCRIBE 0x80 #define SUBACK 0x90 #define UNSUBSCRIBE 0xA0 #define UNSUBACK 0xB0 #define PINGREQ 0xC0 #define PINGRESP 0xD0 #define DISCONNECT 0xE0 #define CONNACK_ACCEPTED 0 #define CONNACK_REFUSED_PROTOCOL_VERSION 1 #define CONNACK_REFUSED_IDENTIFIER_REJECTED 2 #define CONNACK_REFUSED_SERVER_UNAVAILABLE 3 #define CONNACK_REFUSED_BAD_USERNAME_PASSWORD 4 #define CONNACK_REFUSED_NOT_AUTHORIZED 5 #define MQTT_MAX_PAYLOAD 268435455 #endif mosquitto-1.4.15/lib/messages_mosq.h0000664000175000017500000000256413245550210016457 0ustar rogerroger/* Copyright (c) 2010-2018 Roger Light 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 #include void _mosquitto_message_cleanup_all(struct mosquitto *mosq); void _mosquitto_message_cleanup(struct mosquitto_message_all **message); int _mosquitto_message_delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir); int _mosquitto_message_queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir); void _mosquitto_messages_reconnect_reset(struct mosquitto *mosq); int _mosquitto_message_remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message); void _mosquitto_message_retry_check(struct mosquitto *mosq); int _mosquitto_message_out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state); #endif mosquitto-1.4.15/lib/srv_mosq.c0000664000175000017500000000512613245550210015452 0ustar rogerroger/* Copyright (c) 2013-2018 Roger Light 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. */ #ifdef WITH_SRV # include # include # include # include #endif #include "logging_mosq.h" #include "memory_mosq.h" #include "mosquitto_internal.h" #include "mosquitto.h" #ifdef WITH_SRV static void srv_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { struct mosquitto *mosq = arg; struct ares_srv_reply *reply = NULL; if(status == ARES_SUCCESS){ status = ares_parse_srv_reply(abuf, alen, &reply); if(status == ARES_SUCCESS){ // FIXME - choose which answer to use based on rfc2782 page 3. */ mosquitto_connect(mosq, reply->host, reply->port, mosq->keepalive); } }else{ _mosquitto_log_printf(mosq, MOSQ_LOG_ERR, "Error: SRV lookup failed (%d).", status); /* FIXME - calling on_disconnect here isn't correct. */ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_disconnect){ mosq->in_callback = true; mosq->on_disconnect(mosq, mosq->userdata, 2); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); } } #endif int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address) { #ifdef WITH_SRV char *h; int rc; if(!mosq) return MOSQ_ERR_INVAL; rc = ares_init(&mosq->achan); if(rc != ARES_SUCCESS){ return MOSQ_ERR_UNKNOWN; } if(!host){ // get local domain }else{ #ifdef WITH_TLS if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){ h = _mosquitto_malloc(strlen(host) + strlen("_secure-mqtt._tcp.") + 1); if(!h) return MOSQ_ERR_NOMEM; sprintf(h, "_secure-mqtt._tcp.%s", host); }else{ #endif h = _mosquitto_malloc(strlen(host) + strlen("_mqtt._tcp.") + 1); if(!h) return MOSQ_ERR_NOMEM; sprintf(h, "_mqtt._tcp.%s", host); #ifdef WITH_TLS } #endif ares_search(mosq->achan, h, ns_c_in, ns_t_srv, srv_callback, mosq); _mosquitto_free(h); } pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_connect_srv; pthread_mutex_unlock(&mosq->state_mutex); mosq->keepalive = keepalive; return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif } mosquitto-1.4.15/lib/util_mosq.c0000664000175000017500000002471313245550210015620 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #ifdef WIN32 # include # include # include # include #else # include #endif #include #include #include #include #include #include #include #ifdef WITH_BROKER #include #endif #ifdef WITH_WEBSOCKETS #include #endif int _mosquitto_packet_alloc(struct _mosquitto_packet *packet) { uint8_t remaining_bytes[5], byte; uint32_t remaining_length; int i; assert(packet); remaining_length = packet->remaining_length; packet->payload = NULL; packet->remaining_count = 0; do{ byte = remaining_length % 128; remaining_length = remaining_length / 128; /* If there are more digits to encode, set the top bit of this digit */ if(remaining_length > 0){ byte = byte | 0x80; } remaining_bytes[packet->remaining_count] = byte; packet->remaining_count++; }while(remaining_length > 0 && packet->remaining_count < 5); if(packet->remaining_count == 5) return MOSQ_ERR_PAYLOAD_SIZE; packet->packet_length = packet->remaining_length + 1 + packet->remaining_count; #ifdef WITH_WEBSOCKETS packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING); #else packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); #endif if(!packet->payload) return MOSQ_ERR_NOMEM; packet->payload[0] = packet->command; for(i=0; iremaining_count; i++){ packet->payload[i+1] = remaining_bytes[i]; } packet->pos = 1 + packet->remaining_count; return MOSQ_ERR_SUCCESS; } #ifdef WITH_BROKER void _mosquitto_check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq) #else void _mosquitto_check_keepalive(struct mosquitto *mosq) #endif { time_t next_msg_out; time_t last_msg_in; time_t now = mosquitto_time(); #ifndef WITH_BROKER int rc; #endif assert(mosq); #if defined(WITH_BROKER) && defined(WITH_BRIDGE) /* Check if a lazy bridge should be timed out due to idle. */ if(mosq->bridge && mosq->bridge->start_type == bst_lazy && mosq->sock != INVALID_SOCKET && now - mosq->next_msg_out - mosq->keepalive >= mosq->bridge->idle_timeout){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id); _mosquitto_socket_close(db, mosq); return; } #endif pthread_mutex_lock(&mosq->msgtime_mutex); next_msg_out = mosq->next_msg_out; last_msg_in = mosq->last_msg_in; pthread_mutex_unlock(&mosq->msgtime_mutex); if(mosq->keepalive && mosq->sock != INVALID_SOCKET && (now >= next_msg_out || now - last_msg_in >= mosq->keepalive)){ if(mosq->state == mosq_cs_connected && mosq->ping_t == 0){ _mosquitto_send_pingreq(mosq); /* Reset last msg times to give the server time to send a pingresp */ pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = now; mosq->next_msg_out = now + mosq->keepalive; pthread_mutex_unlock(&mosq->msgtime_mutex); }else{ #ifdef WITH_BROKER if(mosq->listener){ mosq->listener->client_count--; assert(mosq->listener->client_count >= 0); } mosq->listener = NULL; _mosquitto_socket_close(db, mosq); #else _mosquitto_socket_close(mosq); pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ rc = MOSQ_ERR_SUCCESS; }else{ rc = 1; } pthread_mutex_unlock(&mosq->state_mutex); 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; } pthread_mutex_unlock(&mosq->callback_mutex); #endif } } } uint16_t _mosquitto_mid_generate(struct mosquitto *mosq) { /* FIXME - this would be better with atomic increment, but this is safer * for now for a bug fix release. * * If this is changed to use atomic increment, callers of this function * will have to be aware that they may receive a 0 result, which may not be * used as a mid. */ uint16_t mid; assert(mosq); pthread_mutex_lock(&mosq->mid_mutex); mosq->last_mid++; if(mosq->last_mid == 0) mosq->last_mid++; mid = mosq->last_mid; pthread_mutex_unlock(&mosq->mid_mutex); return mid; } /* Check that a topic used for publishing is valid. * Search for + or # in a topic. Return MOSQ_ERR_INVAL if found. * Also returns MOSQ_ERR_INVAL if the topic string is too long. * Returns MOSQ_ERR_SUCCESS if everything is fine. */ int mosquitto_pub_topic_check(const char *str) { int len = 0; while(str && str[0]){ if(str[0] == '+' || str[0] == '#'){ return MOSQ_ERR_INVAL; } len++; str = &str[1]; } if(len > 65535) return MOSQ_ERR_INVAL; return MOSQ_ERR_SUCCESS; } /* Check that a topic used for subscriptions is valid. * Search for + or # in a topic, check they aren't in invalid positions such as * foo/#/bar, foo/+bar or foo/bar#. * Return MOSQ_ERR_INVAL if invalid position found. * Also returns MOSQ_ERR_INVAL if the topic string is too long. * Returns MOSQ_ERR_SUCCESS if everything is fine. */ int mosquitto_sub_topic_check(const char *str) { char c = '\0'; int len = 0; while(str && str[0]){ if(str[0] == '+'){ if((c != '\0' && c != '/') || (str[1] != '\0' && str[1] != '/')){ return MOSQ_ERR_INVAL; } }else if(str[0] == '#'){ if((c != '\0' && c != '/') || str[1] != '\0'){ return MOSQ_ERR_INVAL; } } len++; c = str[0]; str = &str[1]; } if(len > 65535) return MOSQ_ERR_INVAL; return MOSQ_ERR_SUCCESS; } /* Does a topic match a subscription? */ int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result) { int slen, tlen; int spos, tpos; bool multilevel_wildcard = false; if(!result) return MOSQ_ERR_INVAL; *result = false; if(!sub || !topic){ return MOSQ_ERR_INVAL; } slen = strlen(sub); tlen = strlen(topic); if(!slen || !tlen){ return MOSQ_ERR_INVAL; } if(slen && tlen){ if((sub[0] == '$' && topic[0] != '$') || (topic[0] == '$' && sub[0] != '$')){ return MOSQ_ERR_SUCCESS; } } spos = 0; tpos = 0; while(spos < slen && tpos <= tlen){ if(sub[spos] == topic[tpos]){ if(tpos == tlen-1){ /* Check for e.g. foo matching foo/# */ if(spos == slen-3 && sub[spos+1] == '/' && sub[spos+2] == '#'){ *result = true; multilevel_wildcard = true; return MOSQ_ERR_SUCCESS; } } spos++; tpos++; if(spos == slen && tpos == tlen){ *result = true; return MOSQ_ERR_SUCCESS; }else if(tpos == tlen && spos == slen-1 && sub[spos] == '+'){ if(spos > 0 && sub[spos-1] != '/'){ return MOSQ_ERR_INVAL; } spos++; *result = true; return MOSQ_ERR_SUCCESS; } }else{ if(sub[spos] == '+'){ /* Check for bad "+foo" or "a/+foo" subscription */ if(spos > 0 && sub[spos-1] != '/'){ return MOSQ_ERR_INVAL; } /* Check for bad "foo+" or "foo+/a" subscription */ if(spos < slen-1 && sub[spos+1] != '/'){ return MOSQ_ERR_INVAL; } spos++; while(tpos < tlen && topic[tpos] != '/'){ tpos++; } if(tpos == tlen && spos == slen){ *result = true; return MOSQ_ERR_SUCCESS; } }else if(sub[spos] == '#'){ if(spos > 0 && sub[spos-1] != '/'){ return MOSQ_ERR_INVAL; } multilevel_wildcard = true; if(spos+1 != slen){ return MOSQ_ERR_INVAL; }else{ *result = true; return MOSQ_ERR_SUCCESS; } }else{ /* Check for e.g. foo/bar matching foo/+/# */ if(spos > 0 && spos+2 == slen && tpos == tlen && sub[spos-1] == '+' && sub[spos] == '/' && sub[spos+1] == '#') { *result = true; multilevel_wildcard = true; return MOSQ_ERR_SUCCESS; } return MOSQ_ERR_SUCCESS; } } } if(multilevel_wildcard == false && (tpos < tlen || spos < slen)){ *result = false; } return MOSQ_ERR_SUCCESS; } #ifdef REAL_WITH_TLS_PSK int _mosquitto_hex2bin(const char *hex, unsigned char *bin, int bin_max_len) { BIGNUM *bn = NULL; int len; int leading_zero = 0; int start = 0; int i = 0; /* Count the number of leading zero */ for(i=0; i bin_max_len){ BN_free(bn); return 0; } len = BN_bn2bin(bn, bin + leading_zero); BN_free(bn); return len + leading_zero; } #endif FILE *_mosquitto_fopen(const char *path, const char *mode, bool restrict_read) { #ifdef WIN32 char buf[4096]; int rc; rc = ExpandEnvironmentStrings(path, buf, 4096); if(rc == 0 || rc > 4096){ return NULL; }else{ if (restrict_read) { HANDLE hfile; SECURITY_ATTRIBUTES sec; EXPLICIT_ACCESS ea; PACL pacl = NULL; char username[UNLEN + 1]; int ulen = UNLEN; SECURITY_DESCRIPTOR sd; GetUserName(username, &ulen); if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { return NULL; } BuildExplicitAccessWithName(&ea, username, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE); if (SetEntriesInAcl(1, &ea, NULL, &pacl) != ERROR_SUCCESS) { return NULL; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) { LocalFree(pacl); return NULL; } sec.nLength = sizeof(SECURITY_ATTRIBUTES); sec.bInheritHandle = FALSE; sec.lpSecurityDescriptor = &sd; hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, &sec, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); LocalFree(pacl); int fd = _open_osfhandle((intptr_t)hfile, 0); if (fd < 0) { return NULL; } FILE *fptr = _fdopen(fd, mode); if (!fptr) { _close(fd); return NULL; } return fptr; }else { return fopen(buf, mode); } } #else if (restrict_read) { FILE *fptr; mode_t old_mask; old_mask = umask(0077); fptr = fopen(path, mode); umask(old_mask); return fptr; }else{ return fopen(path, mode); } #endif } mosquitto-1.4.15/lib/socks_mosq.h0000664000175000017500000000126613245550210015770 0ustar rogerroger/* Copyright (c) 2014-2018 Roger Light 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 SOCKS_MOSQ_H #define SOCKS_MOSQ_H int mosquitto__socks5_send(struct mosquitto *mosq); int mosquitto__socks5_read(struct mosquitto *mosq); #endif mosquitto-1.4.15/lib/tls_mosq.c0000664000175000017500000001037113245550210015440 0ustar rogerroger/* Copyright (c) 2013-2018 Roger Light 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. */ #ifdef WITH_TLS #ifdef WIN32 # include # include #else # include # include #endif #include #include #include #include #ifdef WITH_BROKER # include "mosquitto_broker.h" #endif #include "mosquitto_internal.h" #include "tls_mosq.h" extern int tls_ex_index_mosq; int _mosquitto_server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx) { /* Preverify should have already checked expiry, revocation. * We need to verify the hostname. */ struct mosquitto *mosq; SSL *ssl; X509 *cert; /* Always reject if preverify_ok has failed. */ if(!preverify_ok) return 0; ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq); if(!mosq) return 0; if(mosq->tls_insecure == false){ if(X509_STORE_CTX_get_error_depth(ctx) == 0){ /* FIXME - use X509_check_host() etc. for sufficiently new openssl (>=1.1.x) */ cert = X509_STORE_CTX_get_current_cert(ctx); /* This is the peer certificate, all others are upwards in the chain. */ #if defined(WITH_BROKER) return _mosquitto_verify_certificate_hostname(cert, mosq->bridge->addresses[mosq->bridge->cur_address].address); #else return _mosquitto_verify_certificate_hostname(cert, mosq->host); #endif }else{ return preverify_ok; } }else{ return preverify_ok; } } int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname) { int i; int len; if(!certname || !hostname){ return 1; } if(certname[0] == '*'){ if(certname[1] != '.'){ return 1; } certname += 2; len = strlen(hostname); for(i=0; itype == GEN_DNS){ data = ASN1_STRING_data(nval->d.dNSName); if(data && !mosquitto__cmp_hostname_wildcard((char *)data, hostname)){ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free); return 1; } have_san_dns = true; }else if(nval->type == GEN_IPADD){ data = ASN1_STRING_data(nval->d.iPAddress); if(nval->d.iPAddress->length == 4 && ipv4_ok){ if(!memcmp(ipv4_addr, data, 4)){ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free); return 1; } }else if(nval->d.iPAddress->length == 16 && ipv6_ok){ if(!memcmp(ipv6_addr, data, 16)){ sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free); return 1; } } } } sk_GENERAL_NAME_pop_free(san, GENERAL_NAME_free); if(have_san_dns){ /* Only check CN if subjectAltName DNS entry does not exist. */ return 0; } } subj = X509_get_subject_name(cert); if(X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0){ name[sizeof(name) - 1] = '\0'; if (!mosquitto__cmp_hostname_wildcard(name, hostname)) return 1; } return 0; } #endif mosquitto-1.4.15/lib/socks_mosq.c0000664000175000017500000002666213245550210015772 0ustar rogerroger/* Copyright (c) 2014-2018 Roger Light 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 #include #include "mosquitto_internal.h" #include "memory_mosq.h" #include "net_mosq.h" #include "send_mosq.h" #define SOCKS_AUTH_NONE 0x00 #define SOCKS_AUTH_GSS 0x01 #define SOCKS_AUTH_USERPASS 0x02 #define SOCKS_AUTH_NO_ACCEPTABLE 0xFF #define SOCKS_ATYPE_IP_V4 1 /* four bytes */ #define SOCKS_ATYPE_DOMAINNAME 3 /* one byte length, followed by fqdn no null, 256 max chars */ #define SOCKS_ATYPE_IP_V6 4 /* 16 bytes */ #define SOCKS_REPLY_SUCCEEDED 0x00 #define SOCKS_REPLY_GENERAL_FAILURE 0x01 #define SOCKS_REPLY_CONNECTION_NOT_ALLOWED 0x02 #define SOCKS_REPLY_NETWORK_UNREACHABLE 0x03 #define SOCKS_REPLY_HOST_UNREACHABLE 0x04 #define SOCKS_REPLY_CONNECTION_REFUSED 0x05 #define SOCKS_REPLY_TTL_EXPIRED 0x06 #define SOCKS_REPLY_COMMAND_NOT_SUPPORTED 0x07 #define SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED 0x08 int mosquitto_socks5_set(struct mosquitto *mosq, const char *host, int port, const char *username, const char *password) { #ifdef WITH_SOCKS if(!mosq) return MOSQ_ERR_INVAL; if(!host || strlen(host) > 256) return MOSQ_ERR_INVAL; if(port < 1 || port > 65535) return MOSQ_ERR_INVAL; if(mosq->socks5_host){ _mosquitto_free(mosq->socks5_host); } mosq->socks5_host = _mosquitto_strdup(host); if(!mosq->socks5_host){ return MOSQ_ERR_NOMEM; } mosq->socks5_port = port; if(mosq->socks5_username){ _mosquitto_free(mosq->socks5_username); } if(mosq->socks5_password){ _mosquitto_free(mosq->socks5_password); } if(username){ mosq->socks5_username = _mosquitto_strdup(username); if(!mosq->socks5_username){ return MOSQ_ERR_NOMEM; } if(password){ mosq->socks5_password = _mosquitto_strdup(password); if(!mosq->socks5_password){ _mosquitto_free(mosq->socks5_username); return MOSQ_ERR_NOMEM; } } } return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif } #ifdef WITH_SOCKS int mosquitto__socks5_send(struct mosquitto *mosq) { struct _mosquitto_packet *packet; int slen; int ulen, plen; if(mosq->state == mosq_cs_socks5_new){ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; if(mosq->socks5_username){ packet->packet_length = 4; }else{ packet->packet_length = 3; } packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); packet->payload[0] = 0x05; if(mosq->socks5_username){ packet->payload[1] = 2; packet->payload[2] = SOCKS_AUTH_NONE; packet->payload[3] = SOCKS_AUTH_USERPASS; }else{ packet->payload[1] = 1; packet->payload[2] = SOCKS_AUTH_NONE; } pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_socks5_start; pthread_mutex_unlock(&mosq->state_mutex); mosq->in_packet.pos = 0; mosq->in_packet.packet_length = 2; mosq->in_packet.to_process = 2; mosq->in_packet.payload = _mosquitto_malloc(sizeof(uint8_t)*2); if(!mosq->in_packet.payload){ _mosquitto_free(packet->payload); _mosquitto_free(packet); return MOSQ_ERR_NOMEM; } return _mosquitto_packet_queue(mosq, packet); }else if(mosq->state == mosq_cs_socks5_auth_ok){ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->packet_length = 7+strlen(mosq->host); packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); slen = strlen(mosq->host); packet->payload[0] = 0x05; packet->payload[1] = 1; packet->payload[2] = 0; packet->payload[3] = SOCKS_ATYPE_DOMAINNAME; packet->payload[4] = slen; memcpy(&(packet->payload[5]), mosq->host, slen); packet->payload[5+slen] = MOSQ_MSB(mosq->port); packet->payload[6+slen] = MOSQ_LSB(mosq->port); pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_socks5_request; pthread_mutex_unlock(&mosq->state_mutex); mosq->in_packet.pos = 0; mosq->in_packet.packet_length = 5; mosq->in_packet.to_process = 5; mosq->in_packet.payload = _mosquitto_malloc(sizeof(uint8_t)*5); if(!mosq->in_packet.payload){ _mosquitto_free(packet->payload); _mosquitto_free(packet); return MOSQ_ERR_NOMEM; } return _mosquitto_packet_queue(mosq, packet); }else if(mosq->state == mosq_cs_socks5_send_userpass){ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; ulen = strlen(mosq->socks5_username); plen = strlen(mosq->socks5_password); packet->packet_length = 3 + ulen + plen; packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); packet->payload[0] = 0x01; packet->payload[1] = ulen; memcpy(&(packet->payload[2]), mosq->socks5_username, ulen); packet->payload[2+ulen] = plen; memcpy(&(packet->payload[3+ulen]), mosq->socks5_password, plen); pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_socks5_userpass_reply; pthread_mutex_unlock(&mosq->state_mutex); mosq->in_packet.pos = 0; mosq->in_packet.packet_length = 2; mosq->in_packet.to_process = 2; mosq->in_packet.payload = _mosquitto_malloc(sizeof(uint8_t)*2); if(!mosq->in_packet.payload){ _mosquitto_free(packet->payload); _mosquitto_free(packet); return MOSQ_ERR_NOMEM; } return _mosquitto_packet_queue(mosq, packet); } return MOSQ_ERR_SUCCESS; } int mosquitto__socks5_read(struct mosquitto *mosq) { ssize_t len; uint8_t *payload; uint8_t i; if(mosq->state == mosq_cs_socks5_start){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.payload[0] != 5){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } switch(mosq->in_packet.payload[1]){ case SOCKS_AUTH_NONE: _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_auth_ok; return mosquitto__socks5_send(mosq); case SOCKS_AUTH_USERPASS: _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_send_userpass; return mosquitto__socks5_send(mosq); default: _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_AUTH; } }else if(mosq->state == mosq_cs_socks5_userpass_reply){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.payload[0] != 1){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } if(mosq->in_packet.payload[1] == 0){ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_auth_ok; return mosquitto__socks5_send(mosq); }else{ i = mosq->in_packet.payload[1]; _mosquitto_packet_cleanup(&mosq->in_packet); switch(i){ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED: return MOSQ_ERR_AUTH; case SOCKS_REPLY_NETWORK_UNREACHABLE: case SOCKS_REPLY_HOST_UNREACHABLE: case SOCKS_REPLY_CONNECTION_REFUSED: return MOSQ_ERR_NO_CONN; case SOCKS_REPLY_GENERAL_FAILURE: case SOCKS_REPLY_TTL_EXPIRED: case SOCKS_REPLY_COMMAND_NOT_SUPPORTED: case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: return MOSQ_ERR_PROXY; default: return MOSQ_ERR_INVAL; } return MOSQ_ERR_PROXY; } }else if(mosq->state == mosq_cs_socks5_request){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.packet_length == 5){ /* First part of the packet has been received, we now know what else to expect. */ if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V4){ mosq->in_packet.to_process += 4+2-1; /* 4 bytes IPv4, 2 bytes port, -1 byte because we've already read the first byte */ mosq->in_packet.packet_length += 4+2-1; }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V6){ mosq->in_packet.to_process += 16+2-1; /* 16 bytes IPv6, 2 bytes port, -1 byte because we've already read the first byte */ mosq->in_packet.packet_length += 16+2-1; }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_DOMAINNAME){ if(mosq->in_packet.payload[4] > 0 && mosq->in_packet.payload[4] <= 255){ mosq->in_packet.to_process += mosq->in_packet.payload[4]; mosq->in_packet.packet_length += mosq->in_packet.payload[4]; } }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROTOCOL; } payload = _mosquitto_realloc(mosq->in_packet.payload, mosq->in_packet.packet_length); if(payload){ mosq->in_packet.payload = payload; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_NOMEM; } return MOSQ_ERR_SUCCESS; } /* Entire packet is now read. */ if(mosq->in_packet.payload[0] != 5){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } if(mosq->in_packet.payload[1] == 0){ /* Auth passed */ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_new; return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session); }else{ i = mosq->in_packet.payload[1]; _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_new; switch(i){ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED: return MOSQ_ERR_AUTH; case SOCKS_REPLY_NETWORK_UNREACHABLE: case SOCKS_REPLY_HOST_UNREACHABLE: case SOCKS_REPLY_CONNECTION_REFUSED: return MOSQ_ERR_NO_CONN; case SOCKS_REPLY_GENERAL_FAILURE: case SOCKS_REPLY_TTL_EXPIRED: case SOCKS_REPLY_COMMAND_NOT_SUPPORTED: case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: return MOSQ_ERR_PROXY; default: return MOSQ_ERR_INVAL; } } }else{ return _mosquitto_packet_read(mosq); } return MOSQ_ERR_SUCCESS; } #endif mosquitto-1.4.15/lib/time_mosq.h0000664000175000017500000000115713245550210015603 0ustar rogerroger/* Copyright (c) 2013-2018 Roger Light 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 _TIME_MOSQ_H_ #define _TIME_MOSQ_H_ time_t mosquitto_time(void); #endif mosquitto-1.4.15/client/0000775000175000017500000000000013245550210014141 5ustar rogerrogermosquitto-1.4.15/client/pub_client.c0000664000175000017500000003246013245550210016436 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #ifndef WIN32 #include #else #include #include #define snprintf sprintf_s #endif #include #include "client_shared.h" #define STATUS_CONNECTING 0 #define STATUS_CONNACK_RECVD 1 #define STATUS_WAITING 2 #define STATUS_DISCONNECTING 3 /* Global variables for use in callbacks. See sub_client.c for an example of * using a struct to hold variables for use in callbacks. */ static char *topic = NULL; static char *message = NULL; static long msglen = 0; static int qos = 0; static int retain = 0; static int mode = MSGMODE_NONE; static int status = STATUS_CONNECTING; static int mid_sent = 0; static int last_mid = -1; static int last_mid_sent = -1; static bool connected = true; static char *username = NULL; static char *password = NULL; static bool disconnect_sent = false; static bool quiet = false; void my_connect_callback(struct mosquitto *mosq, void *obj, int result) { int rc = MOSQ_ERR_SUCCESS; if(!result){ switch(mode){ case MSGMODE_CMD: case MSGMODE_FILE: case MSGMODE_STDIN_FILE: rc = mosquitto_publish(mosq, &mid_sent, topic, msglen, message, qos, retain); break; case MSGMODE_NULL: rc = mosquitto_publish(mosq, &mid_sent, topic, 0, NULL, qos, retain); break; case MSGMODE_STDIN_LINE: status = STATUS_CONNACK_RECVD; break; } if(rc){ if(!quiet){ switch(rc){ case MOSQ_ERR_INVAL: fprintf(stderr, "Error: Invalid input. Does your topic contain '+' or '#'?\n"); break; case MOSQ_ERR_NOMEM: fprintf(stderr, "Error: Out of memory when trying to publish message.\n"); break; case MOSQ_ERR_NO_CONN: fprintf(stderr, "Error: Client not connected when trying to publish.\n"); break; case MOSQ_ERR_PROTOCOL: fprintf(stderr, "Error: Protocol error when communicating with broker.\n"); break; case MOSQ_ERR_PAYLOAD_SIZE: fprintf(stderr, "Error: Message payload is too large.\n"); break; } } mosquitto_disconnect(mosq); } }else{ if(result && !quiet){ fprintf(stderr, "%s\n", mosquitto_connack_string(result)); } } } void my_disconnect_callback(struct mosquitto *mosq, void *obj, int rc) { connected = false; } void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) { last_mid_sent = mid; if(mode == MSGMODE_STDIN_LINE){ if(mid == last_mid){ mosquitto_disconnect(mosq); disconnect_sent = true; } }else if(disconnect_sent == false){ mosquitto_disconnect(mosq); disconnect_sent = true; } } void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) { printf("%s\n", str); } int load_stdin(void) { long pos = 0, rlen; char buf[1024]; char *aux_message = NULL; mode = MSGMODE_STDIN_FILE; while(!feof(stdin)){ rlen = fread(buf, 1, 1024, stdin); aux_message = realloc(message, pos+rlen); if(!aux_message){ if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); free(message); return 1; } else { message = aux_message; } memcpy(&(message[pos]), buf, rlen); pos += rlen; } msglen = pos; if(!msglen){ if(!quiet) fprintf(stderr, "Error: Zero length input.\n"); return 1; } return 0; } int load_file(const char *filename) { long pos, rlen; FILE *fptr = NULL; fptr = fopen(filename, "rb"); if(!fptr){ if(!quiet) fprintf(stderr, "Error: Unable to open file \"%s\".\n", filename); return 1; } mode = MSGMODE_FILE; fseek(fptr, 0, SEEK_END); msglen = ftell(fptr); if(msglen > 268435455){ fclose(fptr); if(!quiet) fprintf(stderr, "Error: File \"%s\" is too large (>268,435,455 bytes).\n", filename); return 1; }else if(msglen == 0){ fclose(fptr); if(!quiet) fprintf(stderr, "Error: File \"%s\" is empty.\n", filename); return 1; }else if(msglen < 0){ fclose(fptr); if(!quiet) fprintf(stderr, "Error: Unable to determine size of file \"%s\".\n", filename); return 1; } fseek(fptr, 0, SEEK_SET); message = malloc(msglen); if(!message){ fclose(fptr); if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); return 1; } pos = 0; while(pos < msglen){ rlen = fread(&(message[pos]), sizeof(char), msglen-pos, fptr); pos += rlen; } fclose(fptr); return 0; } void print_usage(void) { int major, minor, revision; mosquitto_lib_version(&major, &minor, &revision); printf("mosquitto_pub is a simple mqtt client that will publish a message on a single topic and exit.\n"); printf("mosquitto_pub version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); printf("Usage: mosquitto_pub [-h host] [-k keepalive] [-p port] [-q qos] [-r] {-f file | -l | -n | -m message} -t topic\n"); #ifdef WITH_SRV printf(" [-A bind_address] [-S]\n"); #else printf(" [-A bind_address]\n"); #endif printf(" [-i id] [-I id_prefix]\n"); printf(" [-d] [--quiet]\n"); printf(" [-M max_inflight]\n"); printf(" [-u username [-P password]]\n"); printf(" [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n"); #ifdef WITH_TLS printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); printf(" [--ciphers ciphers] [--insecure]]\n"); #ifdef WITH_TLS_PSK printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); #endif #endif #ifdef WITH_SOCKS printf(" [--proxy socks-url]\n"); #endif printf(" mosquitto_pub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); printf(" -d : enable debug messages.\n"); printf(" -f : send the contents of a file as the message.\n"); printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); printf(" -i : id to use for this client. Defaults to mosquitto_pub_ appended with the process id.\n"); printf(" -I : define the client id as id_prefix appended with the process id. Useful for when the\n"); printf(" broker is using the clientid_prefixes option.\n"); printf(" -k : keep alive in seconds for this client. Defaults to 60.\n"); printf(" -l : read messages from stdin, sending a separate message for each line.\n"); printf(" -m : message payload to send.\n"); printf(" -M : the maximum inflight messages for QoS 1/2..\n"); printf(" -n : send a null (zero length) message.\n"); printf(" -p : network port to connect to. Defaults to 1883.\n"); printf(" -P : provide a password (requires MQTT 3.1 broker)\n"); printf(" -q : quality of service level to use for all messages. Defaults to 0.\n"); printf(" -r : message should be retained.\n"); printf(" -s : read message from stdin, sending the entire input as a message.\n"); #ifdef WITH_SRV printf(" -S : use SRV lookups to determine which host to connect to.\n"); #endif printf(" -t : mqtt topic to publish to.\n"); printf(" -u : provide a username (requires MQTT 3.1 broker)\n"); printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); printf(" Can be mqttv31 or mqttv311. Defaults to mqttv31.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); printf(" unexpected disconnection. If not given and will-topic is set, a zero\n"); printf(" length message will be sent.\n"); printf(" --will-qos : QoS level for the client Will.\n"); printf(" --will-retain : if given, make the client Will retained.\n"); printf(" --will-topic : the topic on which to publish the client Will.\n"); #ifdef WITH_TLS printf(" --cafile : path to a file containing trusted CA certificates to enable encrypted\n"); printf(" communication.\n"); printf(" --capath : path to a directory containing trusted CA certificates to enable encrypted\n"); printf(" communication.\n"); printf(" --cert : client certificate for authentication, if required by server.\n"); printf(" --key : client private key for authentication, if required by server.\n"); printf(" --ciphers : openssl compatible list of TLS ciphers to support.\n"); printf(" --tls-version : TLS protocol version, can be one of tlsv1.2 tlsv1.1 or tlsv1.\n"); printf(" Defaults to tlsv1.2 if available.\n"); printf(" --insecure : do not check that the server certificate hostname matches the remote\n"); printf(" hostname. Using this option means that you cannot be sure that the\n"); printf(" remote host is the server you wish to connect to and so is insecure.\n"); printf(" Do not use this option in a production environment.\n"); # ifdef WITH_TLS_PSK printf(" --psk : pre-shared-key in hexadecimal (no leading 0x) to enable TLS-PSK mode.\n"); printf(" --psk-identity : client identity string for TLS-PSK mode.\n"); # endif #endif #ifdef WITH_SOCKS printf(" --proxy : SOCKS5 proxy URL of the form:\n"); printf(" socks5h://[username[:password]@]hostname[:port]\n"); printf(" Only \"none\" and \"username\" authentication is supported.\n"); #endif printf("\nSee http://mosquitto.org/ for more information.\n\n"); } int main(int argc, char *argv[]) { struct mosq_config cfg; struct mosquitto *mosq = NULL; int rc; int rc2; char *buf; int buf_len = 1024; int buf_len_actual; int read_len; int pos; buf = malloc(buf_len); if(!buf){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } memset(&cfg, 0, sizeof(struct mosq_config)); rc = client_config_load(&cfg, CLIENT_PUB, argc, argv); if(rc){ client_config_cleanup(&cfg); if(rc == 2){ /* --help */ print_usage(); }else{ fprintf(stderr, "\nUse 'mosquitto_pub --help' to see usage.\n"); } return 1; } topic = cfg.topic; message = cfg.message; msglen = cfg.msglen; qos = cfg.qos; retain = cfg.retain; mode = cfg.pub_mode; username = cfg.username; password = cfg.password; quiet = cfg.quiet; if(cfg.pub_mode == MSGMODE_STDIN_FILE){ if(load_stdin()){ fprintf(stderr, "Error loading input from stdin.\n"); return 1; } }else if(cfg.file_input){ if(load_file(cfg.file_input)){ fprintf(stderr, "Error loading input file \"%s\".\n", cfg.file_input); return 1; } } if(!topic || mode == MSGMODE_NONE){ fprintf(stderr, "Error: Both topic and message must be supplied.\n"); print_usage(); return 1; } mosquitto_lib_init(); if(client_id_generate(&cfg, "mosqpub")){ return 1; } mosq = mosquitto_new(cfg.id, true, NULL); if(!mosq){ switch(errno){ case ENOMEM: if(!quiet) fprintf(stderr, "Error: Out of memory.\n"); break; case EINVAL: if(!quiet) fprintf(stderr, "Error: Invalid id.\n"); break; } mosquitto_lib_cleanup(); return 1; } if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); } mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); mosquitto_publish_callback_set(mosq, my_publish_callback); if(client_opts_set(mosq, &cfg)){ return 1; } rc = client_connect(mosq, &cfg); if(rc) return rc; if(mode == MSGMODE_STDIN_LINE){ mosquitto_loop_start(mosq); } do{ if(mode == MSGMODE_STDIN_LINE){ if(status == STATUS_CONNACK_RECVD){ pos = 0; read_len = buf_len; while(fgets(&buf[pos], read_len, stdin)){ buf_len_actual = strlen(buf); if(buf[buf_len_actual-1] == '\n'){ buf[buf_len_actual-1] = '\0'; rc2 = mosquitto_publish(mosq, &mid_sent, topic, buf_len_actual-1, buf, qos, retain); if(rc2){ if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2); mosquitto_disconnect(mosq); } break; }else{ buf_len += 1024; pos += 1023; read_len = 1024; buf = realloc(buf, buf_len); if(!buf){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } } } if(feof(stdin)){ if(last_mid == -1){ /* Empty file */ mosquitto_disconnect(mosq); disconnect_sent = true; status = STATUS_DISCONNECTING; }else{ last_mid = mid_sent; status = STATUS_WAITING; } } }else if(status == STATUS_WAITING){ if(last_mid_sent == last_mid && disconnect_sent == false){ mosquitto_disconnect(mosq); disconnect_sent = true; } #ifdef WIN32 Sleep(100); #else usleep(100000); #endif } rc = MOSQ_ERR_SUCCESS; }else{ rc = mosquitto_loop(mosq, -1, 1); } }while(rc == MOSQ_ERR_SUCCESS && connected); if(mode == MSGMODE_STDIN_LINE){ mosquitto_loop_stop(mosq, false); } if(message && mode == MSGMODE_FILE){ free(message); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); if(rc){ fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); } return rc; } mosquitto-1.4.15/client/CMakeLists.txt0000664000175000017500000000125213245550210016701 0ustar rogerrogerinclude_directories(${mosquitto_SOURCE_DIR}/lib ${STDBOOL_H_PATH} ${STDINT_H_PATH}) link_directories(${mosquitto_BINARY_DIR}/lib) set(shared_src client_shared.c client_shared.h) if (${WITH_SRV} STREQUAL ON) add_definitions("-DWITH_SRV") endif (${WITH_SRV} STREQUAL ON) add_executable(mosquitto_pub pub_client.c ${shared_src}) add_executable(mosquitto_sub sub_client.c ${shared_src}) target_link_libraries(mosquitto_pub libmosquitto) target_link_libraries(mosquitto_sub libmosquitto) install(TARGETS mosquitto_pub RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") install(TARGETS mosquitto_sub RUNTIME DESTINATION "${BINDIR}" LIBRARY DESTINATION "${LIBDIR}") mosquitto-1.4.15/client/Makefile0000664000175000017500000000216213245550210015602 0ustar rogerrogerinclude ../config.mk .PHONY: all install uninstall reallyclean clean all : mosquitto_pub mosquitto_sub mosquitto_pub : pub_client.o client_shared.o ${CROSS_COMPILE}${CC} $^ -o $@ ${CLIENT_LDFLAGS} mosquitto_sub : sub_client.o client_shared.o ${CROSS_COMPILE}${CC} $^ -o $@ ${CLIENT_LDFLAGS} pub_client.o : pub_client.c ../lib/libmosquitto.so.${SOVERSION} ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} sub_client.o : sub_client.c ../lib/libmosquitto.so.${SOVERSION} ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} client_shared.o : client_shared.c client_shared.h ${CROSS_COMPILE}${CC} -c $< -o $@ ${CLIENT_CFLAGS} ../lib/libmosquitto.so.${SOVERSION} : $(MAKE) -C ../lib install : all $(INSTALL) -d ${DESTDIR}$(prefix)/bin $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} mosquitto_pub ${DESTDIR}${prefix}/bin/mosquitto_pub $(INSTALL) -s --strip-program=${CROSS_COMPILE}${STRIP} mosquitto_sub ${DESTDIR}${prefix}/bin/mosquitto_sub uninstall : -rm -f ${DESTDIR}${prefix}/bin/mosquitto_pub -rm -f ${DESTDIR}${prefix}/bin/mosquitto_sub reallyclean : clean clean : -rm -f *.o mosquitto_pub mosquitto_sub mosquitto-1.4.15/client/client_shared.h0000664000175000017500000000433213245550210017120 0ustar rogerroger/* Copyright (c) 2014-2018 Roger Light 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 _CLIENT_CONFIG_H #define _CLIENT_CONFIG_H #include /* pub_client.c modes */ #define MSGMODE_NONE 0 #define MSGMODE_CMD 1 #define MSGMODE_STDIN_LINE 2 #define MSGMODE_STDIN_FILE 3 #define MSGMODE_FILE 4 #define MSGMODE_NULL 5 #define CLIENT_PUB 1 #define CLIENT_SUB 2 struct mosq_config { char *id; char *id_prefix; int protocol_version; int keepalive; char *host; int port; int qos; bool retain; int pub_mode; /* pub */ char *file_input; /* pub */ char *message; /* pub */ long msglen; /* pub */ char *topic; /* pub */ char *bind_address; #ifdef WITH_SRV bool use_srv; #endif bool debug; bool quiet; unsigned int max_inflight; char *username; char *password; char *will_topic; char *will_payload; long will_payloadlen; int will_qos; bool will_retain; #ifdef WITH_TLS char *cafile; char *capath; char *certfile; char *keyfile; char *ciphers; bool insecure; char *tls_version; # ifdef WITH_TLS_PSK char *psk; char *psk_identity; # endif #endif bool clean_session; /* sub */ char **topics; /* sub */ int topic_count; /* sub */ bool no_retain; /* sub */ char **filter_outs; /* sub */ int filter_out_count; /* sub */ bool verbose; /* sub */ bool eol; /* sub */ int msg_count; /* sub */ #ifdef WITH_SOCKS char *socks5_host; int socks5_port; char *socks5_username; char *socks5_password; #endif }; int client_config_load(struct mosq_config *config, int pub_or_sub, int argc, char *argv[]); void client_config_cleanup(struct mosq_config *cfg); int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg); int client_id_generate(struct mosq_config *cfg, const char *id_base); int client_connect(struct mosquitto *mosq, struct mosq_config *cfg); #endif mosquitto-1.4.15/client/client_shared.c0000664000175000017500000006273113245550210017122 0ustar rogerroger/* Copyright (c) 2014-2018 Roger Light 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 #include #include #include #include #ifndef WIN32 #include #else #include #include #define snprintf sprintf_s #endif #include #include "client_shared.h" static int mosquitto__parse_socks_url(struct mosq_config *cfg, char *url); static int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]); void init_config(struct mosq_config *cfg) { memset(cfg, 0, sizeof(*cfg)); cfg->port = 1883; cfg->max_inflight = 20; cfg->keepalive = 60; cfg->clean_session = true; cfg->eol = true; cfg->protocol_version = MQTT_PROTOCOL_V31; } void client_config_cleanup(struct mosq_config *cfg) { int i; free(cfg->id); free(cfg->id_prefix); free(cfg->host); free(cfg->file_input); free(cfg->message); free(cfg->topic); free(cfg->bind_address); free(cfg->username); free(cfg->password); free(cfg->will_topic); free(cfg->will_payload); #ifdef WITH_TLS free(cfg->cafile); free(cfg->capath); free(cfg->certfile); free(cfg->keyfile); free(cfg->ciphers); free(cfg->tls_version); # ifdef WITH_TLS_PSK free(cfg->psk); free(cfg->psk_identity); # endif #endif if(cfg->topics){ for(i=0; itopic_count; i++){ free(cfg->topics[i]); } free(cfg->topics); } if(cfg->filter_outs){ for(i=0; ifilter_out_count; i++){ free(cfg->filter_outs[i]); } free(cfg->filter_outs); } #ifdef WITH_SOCKS free(cfg->socks5_host); free(cfg->socks5_username); free(cfg->socks5_password); #endif } int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) { int rc; FILE *fptr; char line[1024]; int count; char *loc = NULL; int len; char *args[3]; #ifndef WIN32 char *env; #else char env[1024]; #endif args[0] = NULL; init_config(cfg); /* Default config file */ #ifndef WIN32 env = getenv("XDG_CONFIG_HOME"); if(env){ len = strlen(env) + strlen("/mosquitto_pub") + 1; loc = malloc(len); if(!loc){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } if(pub_or_sub == CLIENT_PUB){ snprintf(loc, len, "%s/mosquitto_pub", env); }else{ snprintf(loc, len, "%s/mosquitto_sub", env); } loc[len-1] = '\0'; }else{ env = getenv("HOME"); if(env){ len = strlen(env) + strlen("/.config/mosquitto_pub") + 1; loc = malloc(len); if(!loc){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } if(pub_or_sub == CLIENT_PUB){ snprintf(loc, len, "%s/.config/mosquitto_pub", env); }else{ snprintf(loc, len, "%s/.config/mosquitto_sub", env); } loc[len-1] = '\0'; }else{ fprintf(stderr, "Warning: Unable to locate configuration directory, default config not loaded.\n"); } } #else rc = GetEnvironmentVariable("USERPROFILE", env, 1024); if(rc > 0 && rc < 1024){ len = strlen(env) + strlen("\\mosquitto_pub.conf") + 1; loc = malloc(len); if(!loc){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } if(pub_or_sub == CLIENT_PUB){ snprintf(loc, len, "%s\\mosquitto_pub.conf", env); }else{ snprintf(loc, len, "%s\\mosquitto_sub.conf", env); } loc[len-1] = '\0'; }else{ fprintf(stderr, "Warning: Unable to locate configuration directory, default config not loaded.\n"); } #endif if(loc){ fptr = fopen(loc, "rt"); if(fptr){ while(fgets(line, 1024, fptr)){ if(line[0] == '#') continue; /* Comments */ while(line[strlen(line)-1] == 10 || line[strlen(line)-1] == 13){ line[strlen(line)-1] = 0; } /* All offset by one "args" here, because real argc/argv has * program name as the first entry. */ args[1] = strtok(line, " "); if(args[1]){ args[2] = strtok(NULL, " "); if(args[2]){ count = 3; }else{ count = 2; } rc = client_config_line_proc(cfg, pub_or_sub, count, args); if(rc){ fclose(fptr); free(loc); return rc; } } } fclose(fptr); } free(loc); } /* Deal with real argc/argv */ rc = client_config_line_proc(cfg, pub_or_sub, argc, argv); if(rc) return rc; if(cfg->will_payload && !cfg->will_topic){ fprintf(stderr, "Error: Will payload given, but no will topic given.\n"); return 1; } if(cfg->will_retain && !cfg->will_topic){ fprintf(stderr, "Error: Will retain given, but no will topic given.\n"); return 1; } if(cfg->password && !cfg->username){ if(!cfg->quiet) fprintf(stderr, "Warning: Not using password since username not set.\n"); } #ifdef WITH_TLS if((cfg->certfile && !cfg->keyfile) || (cfg->keyfile && !cfg->certfile)){ fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is.\n"); return 1; } #endif #ifdef WITH_TLS_PSK if((cfg->cafile || cfg->capath) && cfg->psk){ if(!cfg->quiet) fprintf(stderr, "Error: Only one of --psk or --cafile/--capath may be used at once.\n"); return 1; } if(cfg->psk && !cfg->psk_identity){ if(!cfg->quiet) fprintf(stderr, "Error: --psk-identity required if --psk used.\n"); return 1; } #endif if(pub_or_sub == CLIENT_SUB){ if(cfg->clean_session == false && (cfg->id_prefix || !cfg->id)){ if(!cfg->quiet) fprintf(stderr, "Error: You must provide a client id if you are using the -c option.\n"); return 1; } if(cfg->topic_count == 0){ if(!cfg->quiet) fprintf(stderr, "Error: You must specify a topic to subscribe to.\n"); return 1; } } if(!cfg->host){ cfg->host = "localhost"; } return MOSQ_ERR_SUCCESS; } /* Process a tokenised single line from a file or set of real argc/argv */ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, char *argv[]) { int i; for(i=1; iport = atoi(argv[i+1]); if(cfg->port<1 || cfg->port>65535){ fprintf(stderr, "Error: Invalid port given: %d\n", cfg->port); return 1; } } i++; }else if(!strcmp(argv[i], "-A")){ if(i==argc-1){ fprintf(stderr, "Error: -A argument given but no address specified.\n\n"); return 1; }else{ cfg->bind_address = strdup(argv[i+1]); } i++; #ifdef WITH_TLS }else if(!strcmp(argv[i], "--cafile")){ if(i==argc-1){ fprintf(stderr, "Error: --cafile argument given but no file specified.\n\n"); return 1; }else{ cfg->cafile = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "--capath")){ if(i==argc-1){ fprintf(stderr, "Error: --capath argument given but no directory specified.\n\n"); return 1; }else{ cfg->capath = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "--cert")){ if(i==argc-1){ fprintf(stderr, "Error: --cert argument given but no file specified.\n\n"); return 1; }else{ cfg->certfile = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "--ciphers")){ if(i==argc-1){ fprintf(stderr, "Error: --ciphers argument given but no ciphers specified.\n\n"); return 1; }else{ cfg->ciphers = strdup(argv[i+1]); } i++; #endif }else if(!strcmp(argv[i], "-C")){ if(pub_or_sub == CLIENT_PUB){ goto unknown_option; }else{ if(i==argc-1){ fprintf(stderr, "Error: -C argument given but no count specified.\n\n"); return 1; }else{ cfg->msg_count = atoi(argv[i+1]); if(cfg->msg_count < 1){ fprintf(stderr, "Error: Invalid message count \"%d\".\n\n", cfg->msg_count); return 1; } } i++; } }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){ cfg->debug = true; }else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; } if(cfg->pub_mode != MSGMODE_NONE){ fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); return 1; }else if(i==argc-1){ fprintf(stderr, "Error: -f argument given but no file specified.\n\n"); return 1; }else{ cfg->pub_mode = MSGMODE_FILE; cfg->file_input = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "--help")){ return 2; }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")){ if(i==argc-1){ fprintf(stderr, "Error: -h argument given but no host specified.\n\n"); return 1; }else{ cfg->host = strdup(argv[i+1]); } i++; #ifdef WITH_TLS }else if(!strcmp(argv[i], "--insecure")){ cfg->insecure = true; #endif }else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--id")){ if(cfg->id_prefix){ fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); return 1; } if(i==argc-1){ fprintf(stderr, "Error: -i argument given but no id specified.\n\n"); return 1; }else{ cfg->id = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "-I") || !strcmp(argv[i], "--id-prefix")){ if(cfg->id){ fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n"); return 1; } if(i==argc-1){ fprintf(stderr, "Error: -I argument given but no id prefix specified.\n\n"); return 1; }else{ cfg->id_prefix = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "-k") || !strcmp(argv[i], "--keepalive")){ if(i==argc-1){ fprintf(stderr, "Error: -k argument given but no keepalive specified.\n\n"); return 1; }else{ cfg->keepalive = atoi(argv[i+1]); if(cfg->keepalive>65535){ fprintf(stderr, "Error: Invalid keepalive given: %d\n", cfg->keepalive); return 1; } } i++; #ifdef WITH_TLS }else if(!strcmp(argv[i], "--key")){ if(i==argc-1){ fprintf(stderr, "Error: --key argument given but no file specified.\n\n"); return 1; }else{ cfg->keyfile = strdup(argv[i+1]); } i++; #endif }else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--stdin-line")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; } if(cfg->pub_mode != MSGMODE_NONE){ fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); return 1; }else{ cfg->pub_mode = MSGMODE_STDIN_LINE; } }else if(!strcmp(argv[i], "-m") || !strcmp(argv[i], "--message")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; } if(cfg->pub_mode != MSGMODE_NONE){ fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); return 1; }else if(i==argc-1){ fprintf(stderr, "Error: -m argument given but no message specified.\n\n"); return 1; }else{ cfg->message = strdup(argv[i+1]); cfg->msglen = strlen(cfg->message); cfg->pub_mode = MSGMODE_CMD; } i++; }else if(!strcmp(argv[i], "-M")){ if(i==argc-1){ fprintf(stderr, "Error: -M argument given but max_inflight not specified.\n\n"); return 1; }else{ cfg->max_inflight = atoi(argv[i+1]); } i++; }else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--null-message")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; } if(cfg->pub_mode != MSGMODE_NONE){ fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); return 1; }else{ cfg->pub_mode = MSGMODE_NULL; } }else if(!strcmp(argv[i], "-V") || !strcmp(argv[i], "--protocol-version")){ if(i==argc-1){ fprintf(stderr, "Error: --protocol-version argument given but no version specified.\n\n"); return 1; }else{ if(!strcmp(argv[i+1], "mqttv31")){ cfg->protocol_version = MQTT_PROTOCOL_V31; }else if(!strcmp(argv[i+1], "mqttv311")){ cfg->protocol_version = MQTT_PROTOCOL_V311; }else{ fprintf(stderr, "Error: Invalid protocol version argument given.\n\n"); return 1; } i++; } #ifdef WITH_SOCKS }else if(!strcmp(argv[i], "--proxy")){ if(i==argc-1){ fprintf(stderr, "Error: --proxy argument given but no proxy url specified.\n\n"); return 1; }else{ if(mosquitto__parse_socks_url(cfg, argv[i+1])){ return 1; } i++; } #endif #ifdef WITH_TLS_PSK }else if(!strcmp(argv[i], "--psk")){ if(i==argc-1){ fprintf(stderr, "Error: --psk argument given but no key specified.\n\n"); return 1; }else{ cfg->psk = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "--psk-identity")){ if(i==argc-1){ fprintf(stderr, "Error: --psk-identity argument given but no identity specified.\n\n"); return 1; }else{ cfg->psk_identity = strdup(argv[i+1]); } i++; #endif }else if(!strcmp(argv[i], "-q") || !strcmp(argv[i], "--qos")){ if(i==argc-1){ fprintf(stderr, "Error: -q argument given but no QoS specified.\n\n"); return 1; }else{ cfg->qos = atoi(argv[i+1]); if(cfg->qos<0 || cfg->qos>2){ fprintf(stderr, "Error: Invalid QoS given: %d\n", cfg->qos); return 1; } } i++; }else if(!strcmp(argv[i], "--quiet")){ cfg->quiet = true; }else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--retain")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; } cfg->retain = 1; }else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stdin-file")){ if(pub_or_sub == CLIENT_SUB){ goto unknown_option; } if(cfg->pub_mode != MSGMODE_NONE){ fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n"); return 1; }else{ cfg->pub_mode = MSGMODE_STDIN_FILE; } #ifdef WITH_SRV }else if(!strcmp(argv[i], "-S")){ cfg->use_srv = true; #endif }else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--topic")){ if(i==argc-1){ fprintf(stderr, "Error: -t argument given but no topic specified.\n\n"); return 1; }else{ if(pub_or_sub == CLIENT_PUB){ if(mosquitto_pub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ fprintf(stderr, "Error: Invalid publish topic '%s', does it contain '+' or '#'?\n", argv[i+1]); return 1; } cfg->topic = strdup(argv[i+1]); }else{ if(mosquitto_sub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ fprintf(stderr, "Error: Invalid subscription topic '%s', are all '+' and '#' wildcards correct?\n", argv[i+1]); return 1; } cfg->topic_count++; cfg->topics = realloc(cfg->topics, cfg->topic_count*sizeof(char *)); cfg->topics[cfg->topic_count-1] = strdup(argv[i+1]); } i++; } }else if(!strcmp(argv[i], "-T") || !strcmp(argv[i], "--filter-out")){ if(pub_or_sub == CLIENT_PUB){ goto unknown_option; } if(i==argc-1){ fprintf(stderr, "Error: -T argument given but no topic filter specified.\n\n"); return 1; }else{ if(mosquitto_sub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ fprintf(stderr, "Error: Invalid filter topic '%s', are all '+' and '#' wildcards correct?\n", argv[i+1]); return 1; } cfg->filter_out_count++; cfg->filter_outs = realloc(cfg->filter_outs, cfg->filter_out_count*sizeof(char *)); cfg->filter_outs[cfg->filter_out_count-1] = strdup(argv[i+1]); } i++; #ifdef WITH_TLS }else if(!strcmp(argv[i], "--tls-version")){ if(i==argc-1){ fprintf(stderr, "Error: --tls-version argument given but no version specified.\n\n"); return 1; }else{ cfg->tls_version = strdup(argv[i+1]); } i++; #endif }else if(!strcmp(argv[i], "-u") || !strcmp(argv[i], "--username")){ if(i==argc-1){ fprintf(stderr, "Error: -u argument given but no username specified.\n\n"); return 1; }else{ cfg->username = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "-P") || !strcmp(argv[i], "--pw")){ if(i==argc-1){ fprintf(stderr, "Error: -P argument given but no password specified.\n\n"); return 1; }else{ cfg->password = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "--will-payload")){ if(i==argc-1){ fprintf(stderr, "Error: --will-payload argument given but no will payload specified.\n\n"); return 1; }else{ cfg->will_payload = strdup(argv[i+1]); cfg->will_payloadlen = strlen(cfg->will_payload); } i++; }else if(!strcmp(argv[i], "--will-qos")){ if(i==argc-1){ fprintf(stderr, "Error: --will-qos argument given but no will QoS specified.\n\n"); return 1; }else{ cfg->will_qos = atoi(argv[i+1]); if(cfg->will_qos < 0 || cfg->will_qos > 2){ fprintf(stderr, "Error: Invalid will QoS %d.\n\n", cfg->will_qos); return 1; } } i++; }else if(!strcmp(argv[i], "--will-retain")){ cfg->will_retain = true; }else if(!strcmp(argv[i], "--will-topic")){ if(i==argc-1){ fprintf(stderr, "Error: --will-topic argument given but no will topic specified.\n\n"); return 1; }else{ if(mosquitto_pub_topic_check(argv[i+1]) == MOSQ_ERR_INVAL){ fprintf(stderr, "Error: Invalid will topic '%s', does it contain '+' or '#'?\n", argv[i+1]); return 1; } cfg->will_topic = strdup(argv[i+1]); } i++; }else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--disable-clean-session")){ if(pub_or_sub == CLIENT_PUB){ goto unknown_option; } cfg->clean_session = false; }else if(!strcmp(argv[i], "-N")){ if(pub_or_sub == CLIENT_PUB){ goto unknown_option; } cfg->eol = false; }else if(!strcmp(argv[i], "-R")){ if(pub_or_sub == CLIENT_PUB){ goto unknown_option; } cfg->no_retain = true; }else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")){ if(pub_or_sub == CLIENT_PUB){ goto unknown_option; } cfg->verbose = 1; }else{ goto unknown_option; } } return MOSQ_ERR_SUCCESS; unknown_option: fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]); return 1; } int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) { int rc; if(cfg->will_topic && mosquitto_will_set(mosq, cfg->will_topic, cfg->will_payloadlen, cfg->will_payload, cfg->will_qos, cfg->will_retain)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting will.\n"); mosquitto_lib_cleanup(); return 1; } if(cfg->username && mosquitto_username_pw_set(mosq, cfg->username, cfg->password)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting username and password.\n"); mosquitto_lib_cleanup(); return 1; } #ifdef WITH_TLS if((cfg->cafile || cfg->capath) && mosquitto_tls_set(mosq, cfg->cafile, cfg->capath, cfg->certfile, cfg->keyfile, NULL)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); mosquitto_lib_cleanup(); return 1; } if(cfg->insecure && mosquitto_tls_insecure_set(mosq, true)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS insecure option.\n"); mosquitto_lib_cleanup(); return 1; } # ifdef WITH_TLS_PSK if(cfg->psk && mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); mosquitto_lib_cleanup(); return 1; } # endif if((cfg->tls_version || cfg->ciphers) && mosquitto_tls_opts_set(mosq, 1, cfg->tls_version, cfg->ciphers)){ if(!cfg->quiet) fprintf(stderr, "Error: Problem setting TLS options.\n"); mosquitto_lib_cleanup(); return 1; } #endif mosquitto_max_inflight_messages_set(mosq, cfg->max_inflight); #ifdef WITH_SOCKS if(cfg->socks5_host){ rc = mosquitto_socks5_set(mosq, cfg->socks5_host, cfg->socks5_port, cfg->socks5_username, cfg->socks5_password); if(rc){ mosquitto_lib_cleanup(); return rc; } } #endif mosquitto_opts_set(mosq, MOSQ_OPT_PROTOCOL_VERSION, &(cfg->protocol_version)); return MOSQ_ERR_SUCCESS; } int client_id_generate(struct mosq_config *cfg, const char *id_base) { int len; char hostname[256]; if(cfg->id_prefix){ cfg->id = malloc(strlen(cfg->id_prefix)+10); if(!cfg->id){ if(!cfg->quiet) fprintf(stderr, "Error: Out of memory.\n"); mosquitto_lib_cleanup(); return 1; } snprintf(cfg->id, strlen(cfg->id_prefix)+10, "%s%d", cfg->id_prefix, getpid()); }else if(!cfg->id){ hostname[0] = '\0'; gethostname(hostname, 256); hostname[255] = '\0'; len = strlen(id_base) + strlen("|-") + 6 + strlen(hostname); cfg->id = malloc(len); if(!cfg->id){ if(!cfg->quiet) fprintf(stderr, "Error: Out of memory.\n"); mosquitto_lib_cleanup(); return 1; } snprintf(cfg->id, len, "%s|%d-%s", id_base, getpid(), hostname); if(strlen(cfg->id) > MOSQ_MQTT_ID_MAX_LENGTH){ /* Enforce maximum client id length of 23 characters */ cfg->id[MOSQ_MQTT_ID_MAX_LENGTH] = '\0'; } } return MOSQ_ERR_SUCCESS; } int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) { char err[1024]; int rc; #ifdef WITH_SRV if(cfg->use_srv){ rc = mosquitto_connect_srv(mosq, cfg->host, cfg->keepalive, cfg->bind_address); }else{ rc = mosquitto_connect_bind(mosq, cfg->host, cfg->port, cfg->keepalive, cfg->bind_address); } #else rc = mosquitto_connect_bind(mosq, cfg->host, cfg->port, cfg->keepalive, cfg->bind_address); #endif if(rc>0){ if(!cfg->quiet){ if(rc == MOSQ_ERR_ERRNO){ #ifndef WIN32 strerror_r(errno, err, 1024); #else FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL); #endif fprintf(stderr, "Error: %s\n", err); }else{ fprintf(stderr, "Unable to connect (%s).\n", mosquitto_strerror(rc)); } } mosquitto_lib_cleanup(); return rc; } return MOSQ_ERR_SUCCESS; } #ifdef WITH_SOCKS /* Convert %25 -> %, %3a, %3A -> :, %40 -> @ */ static int mosquitto__urldecode(char *str) { int i, j; int len; if(!str) return 0; if(!strchr(str, '%')) return 0; len = strlen(str); for(i=0; i= len){ return 1; } if(str[i+1] == '2' && str[i+2] == '5'){ str[i] = '%'; len -= 2; for(j=i+1; j start){ len = i-start; if(host){ /* Have already seen a @ , so this must be of form * socks5h://username[:password]@host:port */ port = malloc(len + 1); memcpy(port, &(str[start]), len); port[len] = '\0'; }else if(username_or_host){ /* Haven't seen a @ before, so must be of form * socks5h://host:port */ host = username_or_host; username_or_host = NULL; port = malloc(len + 1); memcpy(port, &(str[start]), len); port[len] = '\0'; }else{ host = malloc(len + 1); if(!host){ fprintf(stderr, "Error: Out of memory.\n"); goto cleanup; } memcpy(host, &(str[start]), len); host[len] = '\0'; } } if(!host){ fprintf(stderr, "Error: Invalid proxy.\n"); goto cleanup; } if(mosquitto__urldecode(username)){ goto cleanup; } if(mosquitto__urldecode(password)){ goto cleanup; } if(port){ port_int = atoi(port); if(port_int < 1 || port_int > 65535){ fprintf(stderr, "Error: Invalid proxy port %d\n", port_int); goto cleanup; } free(port); }else{ port_int = 1080; } cfg->socks5_username = username; cfg->socks5_password = password; cfg->socks5_host = host; cfg->socks5_port = port_int; return 0; cleanup: if(username_or_host) free(username_or_host); if(username) free(username); if(password) free(password); if(host) free(host); if(port) free(port); return 1; } #endif mosquitto-1.4.15/client/sub_client.c0000664000175000017500000002224413245550210016440 0ustar rogerroger/* Copyright (c) 2009-2018 Roger Light 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 #include #include #include #include #ifndef WIN32 #include #else #include #include #define snprintf sprintf_s #endif #include #include "client_shared.h" bool process_messages = true; int msg_count = 0; void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message) { struct mosq_config *cfg; int i; bool res; if(process_messages == false) return; assert(obj); cfg = (struct mosq_config *)obj; if(message->retain && cfg->no_retain) return; if(cfg->filter_outs){ for(i=0; ifilter_out_count; i++){ mosquitto_topic_matches_sub(cfg->filter_outs[i], message->topic, &res); if(res) return; } } if(cfg->verbose){ if(message->payloadlen){ printf("%s ", message->topic); fwrite(message->payload, 1, message->payloadlen, stdout); if(cfg->eol){ printf("\n"); } }else{ if(cfg->eol){ printf("%s (null)\n", message->topic); } } fflush(stdout); }else{ if(message->payloadlen){ fwrite(message->payload, 1, message->payloadlen, stdout); if(cfg->eol){ printf("\n"); } fflush(stdout); } } if(cfg->msg_count>0){ msg_count++; if(cfg->msg_count == msg_count){ process_messages = false; mosquitto_disconnect(mosq); } } } void my_connect_callback(struct mosquitto *mosq, void *obj, int result) { int i; struct mosq_config *cfg; assert(obj); cfg = (struct mosq_config *)obj; if(!result){ for(i=0; itopic_count; i++){ mosquitto_subscribe(mosq, NULL, cfg->topics[i], cfg->qos); } }else{ if(result && !cfg->quiet){ fprintf(stderr, "%s\n", mosquitto_connack_string(result)); } } } void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { int i; struct mosq_config *cfg; assert(obj); cfg = (struct mosq_config *)obj; if(!cfg->quiet) printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); for(i=1; iquiet) printf(", %d", granted_qos[i]); } if(!cfg->quiet) printf("\n"); } void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) { printf("%s\n", str); } void print_usage(void) { int major, minor, revision; mosquitto_lib_version(&major, &minor, &revision); printf("mosquitto_sub is a simple mqtt client that will subscribe to a single topic and print all messages it receives.\n"); printf("mosquitto_sub version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); printf("Usage: mosquitto_sub [-c] [-h host] [-k keepalive] [-p port] [-q qos] [-R] -t topic ...\n"); printf(" [-C msg_count] [-T filter_out]\n"); #ifdef WITH_SRV printf(" [-A bind_address] [-S]\n"); #else printf(" [-A bind_address]\n"); #endif printf(" [-i id] [-I id_prefix]\n"); printf(" [-d] [-N] [--quiet] [-v]\n"); printf(" [-u username [-P password]]\n"); printf(" [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n"); #ifdef WITH_TLS printf(" [{--cafile file | --capath dir} [--cert file] [--key file]\n"); printf(" [--ciphers ciphers] [--insecure]]\n"); #ifdef WITH_TLS_PSK printf(" [--psk hex-key --psk-identity identity [--ciphers ciphers]]\n"); #endif #endif #ifdef WITH_SOCKS printf(" [--proxy socks-url]\n"); #endif printf(" mosquitto_sub --help\n\n"); printf(" -A : bind the outgoing socket to this host/ip address. Use to control which interface\n"); printf(" the client communicates over.\n"); printf(" -c : disable 'clean session' (store subscription and pending messages when client disconnects).\n"); printf(" -C : disconnect and exit after receiving the 'msg_count' messages.\n"); printf(" -d : enable debug messages.\n"); printf(" -h : mqtt host to connect to. Defaults to localhost.\n"); printf(" -i : id to use for this client. Defaults to mosquitto_sub_ appended with the process id.\n"); printf(" -I : define the client id as id_prefix appended with the process id. Useful for when the\n"); printf(" broker is using the clientid_prefixes option.\n"); printf(" -k : keep alive in seconds for this client. Defaults to 60.\n"); printf(" -N : do not add an end of line character when printing the payload.\n"); printf(" -p : network port to connect to. Defaults to 1883.\n"); printf(" -P : provide a password (requires MQTT 3.1 broker)\n"); printf(" -q : quality of service level to use for the subscription. Defaults to 0.\n"); printf(" -R : do not print stale messages (those with retain set).\n"); #ifdef WITH_SRV printf(" -S : use SRV lookups to determine which host to connect to.\n"); #endif printf(" -t : mqtt topic to subscribe to. May be repeated multiple times.\n"); printf(" -T : topic string to filter out of results. May be repeated.\n"); printf(" -u : provide a username (requires MQTT 3.1 broker)\n"); printf(" -v : print published messages verbosely.\n"); printf(" -V : specify the version of the MQTT protocol to use when connecting.\n"); printf(" Can be mqttv31 or mqttv311. Defaults to mqttv31.\n"); printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); printf(" unexpected disconnection. If not given and will-topic is set, a zero\n"); printf(" length message will be sent.\n"); printf(" --will-qos : QoS level for the client Will.\n"); printf(" --will-retain : if given, make the client Will retained.\n"); printf(" --will-topic : the topic on which to publish the client Will.\n"); #ifdef WITH_TLS printf(" --cafile : path to a file containing trusted CA certificates to enable encrypted\n"); printf(" certificate based communication.\n"); printf(" --capath : path to a directory containing trusted CA certificates to enable encrypted\n"); printf(" communication.\n"); printf(" --cert : client certificate for authentication, if required by server.\n"); printf(" --key : client private key for authentication, if required by server.\n"); printf(" --ciphers : openssl compatible list of TLS ciphers to support.\n"); printf(" --tls-version : TLS protocol version, can be one of tlsv1.2 tlsv1.1 or tlsv1.\n"); printf(" Defaults to tlsv1.2 if available.\n"); printf(" --insecure : do not check that the server certificate hostname matches the remote\n"); printf(" hostname. Using this option means that you cannot be sure that the\n"); printf(" remote host is the server you wish to connect to and so is insecure.\n"); printf(" Do not use this option in a production environment.\n"); #ifdef WITH_TLS_PSK printf(" --psk : pre-shared-key in hexadecimal (no leading 0x) to enable TLS-PSK mode.\n"); printf(" --psk-identity : client identity string for TLS-PSK mode.\n"); #endif #endif #ifdef WITH_SOCKS printf(" --proxy : SOCKS5 proxy URL of the form:\n"); printf(" socks5h://[username[:password]@]hostname[:port]\n"); printf(" Only \"none\" and \"username\" authentication is supported.\n"); #endif printf("\nSee http://mosquitto.org/ for more information.\n\n"); } int main(int argc, char *argv[]) { struct mosq_config cfg; struct mosquitto *mosq = NULL; int rc; rc = client_config_load(&cfg, CLIENT_SUB, argc, argv); if(rc){ client_config_cleanup(&cfg); if(rc == 2){ /* --help */ print_usage(); }else{ fprintf(stderr, "\nUse 'mosquitto_sub --help' to see usage.\n"); } return 1; } mosquitto_lib_init(); if(client_id_generate(&cfg, "mosqsub")){ return 1; } mosq = mosquitto_new(cfg.id, cfg.clean_session, &cfg); if(!mosq){ switch(errno){ case ENOMEM: if(!cfg.quiet) fprintf(stderr, "Error: Out of memory.\n"); break; case EINVAL: if(!cfg.quiet) fprintf(stderr, "Error: Invalid id and/or clean_session.\n"); break; } mosquitto_lib_cleanup(); return 1; } if(client_opts_set(mosq, &cfg)){ return 1; } if(cfg.debug){ mosquitto_log_callback_set(mosq, my_log_callback); mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); } mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_message_callback_set(mosq, my_message_callback); rc = client_connect(mosq, &cfg); if(rc) return rc; rc = mosquitto_loop_forever(mosq, -1, 1); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); if(cfg.msg_count>0 && rc == MOSQ_ERR_NO_CONN){ rc = 0; } if(rc){ fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc)); } return rc; } mosquitto-1.4.15/aclfile.example0000664000175000017500000000034613245550210015642 0ustar rogerroger# This affects access control for clients with no username. topic read $SYS/# # This only affects clients with username "roger". user roger topic foo/bar # This affects all clients. pattern write $SYS/broker/connection/%c/state mosquitto-1.4.15/readme.md0000664000175000017500000000614013245550210014443 0ustar rogerrogerEclipse Mosquitto ================= Mosquitto is an open source implementation of a server for version 3.1 and 3.1.1 of the MQTT protocol. It also includes a C and C++ client library, and the `mosquitto_pub` and `mosquitto_sub` utilities for publishing and subscribing. ## Links See the following links for more information on MQTT: - Community page: - MQTT v3.1.1 standard: Mosquitto project information is available at the following locations: - Main homepage: - Find existing bugs or submit a new bug: - Source code repository: There is also a public test server available at ## Installing See for details on installing binaries for various platforms. ## Quick start If you have installed a binary package the broker should have been started automatically. If not, it can be started with a basic configuration: mosquitto Then use `mosquitto_sub` to subscribe to a topic: mosquitto_sub -t 'test/topic' -v And to publish a message: mosquitto_pub -t 'test/topic' -m 'hello world' ## Documentation Documentation for the broker, clients and client library API can be found in the man pages, which are available online at . There are also pages with an introduction to the features of MQTT, the `mosquitto_passwd` utility for dealing with username/passwords, and a description of the configuration file options available for the broker. Detailed client library API documentation can be found at ## Building from source To build from source the recommended route for end users is to download the archive from . On Windows and Mac, use `cmake` to build. On other platforms, just run `make` to build. For Windows, see also `readme-windows.md`. If you are building from the git repository then the documentation will not already be built. Use `make binary` to skip building the man pages, or install `docbook-xsl` on Debian/Ubuntu systems. ### Build Dependencies * c-ares (libc-ares-dev on Debian based systems) - disable with `make WITH_SRV=no` * libuuid (uuid-dev) - disable with `make WITH_UUID=no` * libwebsockets (libwebsockets-dev) - enable with `make WITH_WEBSOCKETS=yes` * openssl (libssl-dev on Debian based systems) - disable with `make WITH_TLS=no` * xsltproc (xsltproc and docbook-xsl on Debian based systems) - only needed when building from git sources - disable with `make WITH_DOCS=no` ## Credits Mosquitto was written by Roger Light Master: [![Travis Build Status (master)](https://travis-ci.org/eclipse/mosquitto.svg?branch=master)](https://travis-ci.org/eclipse/mosquitto) Develop: [![Travis Build Status (develop)](https://travis-ci.org/eclipse/mosquitto.svg?branch=develop)](https://travis-ci.org/eclipse/mosquitto) Fixes: [![Travis Build Status (fixes)](https://travis-ci.org/eclipse/mosquitto.svg?branch=fixes)](https://travis-ci.org/eclipse/mosquitto) mosquitto-1.4.15/about.html0000664000175000017500000000375213245550210014672 0ustar rogerroger About

About This Content

May 8, 2014

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html and a copy of the EDL is available at http://www.eclipse.org/org/documents/edl-v10.php. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

Third Party Content

The Content includes items that have been sourced from third parties as set out below. If you did not receive this Content directly from the Eclipse Foundation, the following is provided for informational purposes only, and you should look to the Redistributor's license for terms and conditions of use.

None



mosquitto-1.4.15/mosquitto.conf0000664000175000017500000011154213245550210015602 0ustar rogerroger# Config file for mosquitto # # See mosquitto.conf(5) for more information. # # Default values are shown, uncomment to change. # # Use the # character to indicate a comment, but only if it is the # very first character on the line. # ================================================================= # General configuration # ================================================================= # Time in seconds to wait before resending an outgoing QoS=1 or # QoS=2 message. #retry_interval 20 # Time in seconds between updates of the $SYS tree. # Set to 0 to disable the publishing of the $SYS tree. #sys_interval 10 # Time in seconds between cleaning the internal message store of # unreferenced messages. Lower values will result in lower memory # usage but more processor time, higher values will have the # opposite effect. # Setting a value of 0 means the unreferenced messages will be # disposed of as quickly as possible. #store_clean_interval 10 # Write process id to a file. Default is a blank string which means # a pid file shouldn't be written. # This should be set to /var/run/mosquitto.pid if mosquitto is # being run automatically on boot with an init script and # start-stop-daemon or similar. #pid_file # When run as root, drop privileges to this user and its primary # group. # Leave blank to stay as root, but this is not recommended. # If run as a non-root user, this setting has no effect. # Note that on Windows this has no effect and so mosquitto should # be started by the user you wish it to run as. #user mosquitto # The maximum number of QoS 1 and 2 messages currently inflight per # client. # This includes messages that are partway through handshakes and # those that are being retried. Defaults to 20. Set to 0 for no # maximum. Setting to 1 will guarantee in-order delivery of QoS 1 # and 2 messages. #max_inflight_messages 20 # The maximum number of QoS 1 and 2 messages to hold in a queue # above those that are currently in-flight. Defaults to 100. Set # to 0 for no maximum (not recommended). # See also queue_qos0_messages. #max_queued_messages 100 # Set to true to queue messages with QoS 0 when a persistent client is # disconnected. These messages are included in the limit imposed by # max_queued_messages. # Defaults to false. # This is a non-standard option for the MQTT v3.1 spec but is allowed in # v3.1.1. #queue_qos0_messages false # This option sets the maximum publish payload size that the broker will allow. # Received messages that exceed this size will not be accepted by the broker. # The default value is 0, which means that all valid MQTT messages are # accepted. MQTT imposes a maximum payload size of 268435455 bytes. #message_size_limit 0 # This option controls whether a client is allowed to connect with a zero # length client id or not. This option only affects clients using MQTT v3.1.1 # and later. If set to false, clients connecting with a zero length client id # are disconnected. If set to true, clients will be allocated a client id by # the broker. This means it is only useful for clients with clean session set # to true. #allow_zero_length_clientid true # If allow_zero_length_clientid is true, this option allows you to set a prefix # to automatically generated client ids to aid visibility in logs. #auto_id_prefix # This option allows persistent clients (those with clean session set to false) # to be removed if they do not reconnect within a certain time frame. # # This is a non-standard option in MQTT V3.1 but allowed in MQTT v3.1.1. # # Badly designed clients may set clean session to false whilst using a randomly # generated client id. This leads to persistent clients that will never # reconnect. This option allows these clients to be removed. # # The expiration period should be an integer followed by one of h d w m y for # hour, day, week, month and year respectively. For example # # persistent_client_expiration 2m # persistent_client_expiration 14d # persistent_client_expiration 1y # # The default if not set is to never expire persistent clients. #persistent_client_expiration # If a client is subscribed to multiple subscriptions that overlap, e.g. foo/# # and foo/+/baz , then MQTT expects that when the broker receives a message on # a topic that matches both subscriptions, such as foo/bar/baz, then the client # should only receive the message once. # Mosquitto keeps track of which clients a message has been sent to in order to # meet this requirement. The allow_duplicate_messages option allows this # behaviour to be disabled, which may be useful if you have a large number of # clients subscribed to the same set of topics and are very concerned about # minimising memory usage. # It can be safely set to true if you know in advance that your clients will # never have overlapping subscriptions, otherwise your clients must be able to # correctly deal with duplicate messages even when then have QoS=2. #allow_duplicate_messages false # The MQTT specification requires that the QoS of a message delivered to a # subscriber is never upgraded to match the QoS of the subscription. Enabling # this option changes this behaviour. If upgrade_outgoing_qos is set true, # messages sent to a subscriber will always match the QoS of its subscription. # This is a non-standard option explicitly disallowed by the spec. #upgrade_outgoing_qos false # ================================================================= # Default listener # ================================================================= # IP address/hostname to bind the default listener to. If not # given, the default listener will not be bound to a specific # address and so will be accessible to all network interfaces. # bind_address ip-address/host name #bind_address # Port to use for the default listener. #port 1883 # The maximum number of client connections to allow. This is # a per listener setting. # Default is -1, which means unlimited connections. # Note that other process limits mean that unlimited connections # are not really possible. Typically the default maximum number of # connections possible is around 1024. #max_connections -1 # Choose the protocol to use when listening. # This can be either mqtt or websockets. # Websockets support is currently disabled by default at compile time. # Certificate based TLS may be used with websockets, except that # only the cafile, certfile, keyfile and ciphers options are supported. #protocol mqtt # When a listener is using the websockets protocol, it is possible to serve # http data as well. Set http_dir to a directory which contains the files you # wish to serve. If this option is not specified, then no normal http # connections will be possible. #http_dir # Set use_username_as_clientid to true to replace the clientid that a client # connected with with its username. This allows authentication to be tied to # the clientid, which means that it is possible to prevent one client # disconnecting another by using the same clientid. # If a client connects with no username it will be disconnected as not # authorised when this option is set to true. # Do not use in conjunction with clientid_prefixes. # See also use_identity_as_username. #use_username_as_clientid # ----------------------------------------------------------------- # Certificate based SSL/TLS support # ----------------------------------------------------------------- # The following options can be used to enable SSL/TLS support for # this listener. Note that the recommended port for MQTT over TLS # is 8883, but this must be set manually. # # See also the mosquitto-tls man page. # At least one of cafile or capath must be defined. They both # define methods of accessing the PEM encoded Certificate # Authority certificates that have signed your server certificate # and that you wish to trust. # cafile defines the path to a file containing the CA certificates. # capath defines a directory that will be searched for files # containing the CA certificates. For capath to work correctly, the # certificate files must have ".crt" as the file ending and you must run # "c_rehash " each time you add/remove a certificate. #cafile #capath # Path to the PEM encoded server certificate. #certfile # Path to the PEM encoded keyfile. #keyfile # This option defines the version of the TLS protocol to use for this listener. # The default value allows v1.2, v1.1 and v1.0, if they are all supported by # the version of openssl that the broker was compiled against. For openssl >= # 1.0.1 the valid values are tlsv1.2 tlsv1.1 and tlsv1. For openssl < 1.0.1 the # valid values are tlsv1. #tls_version # By default a TLS enabled listener will operate in a similar fashion to a # https enabled web server, in that the server has a certificate signed by a CA # and the client will verify that it is a trusted certificate. The overall aim # is encryption of the network traffic. By setting require_certificate to true, # the client must provide a valid certificate in order for the network # connection to proceed. This allows access to the broker to be controlled # outside of the mechanisms provided by MQTT. #require_certificate false # If require_certificate is true, you may set use_identity_as_username to true # to use the CN value from the client certificate as a username. If this is # true, the password_file option will not be used for this listener. #use_identity_as_username false # If you have require_certificate set to true, you can create a certificate # revocation list file to revoke access to particular client certificates. If # you have done this, use crlfile to point to the PEM encoded revocation file. #crlfile # If you wish to control which encryption ciphers are used, use the ciphers # option. The list of available ciphers can be obtained using the "openssl # ciphers" command and should be provided in the same format as the output of # that command. # If unset defaults to DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH #ciphers DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH # ----------------------------------------------------------------- # Pre-shared-key based SSL/TLS support # ----------------------------------------------------------------- # The following options can be used to enable PSK based SSL/TLS support for # this listener. Note that the recommended port for MQTT over TLS is 8883, but # this must be set manually. # # See also the mosquitto-tls man page and the "Certificate based SSL/TLS # support" section. Only one of certificate or PSK encryption support can be # enabled for any listener. # The psk_hint option enables pre-shared-key support for this listener and also # acts as an identifier for this listener. The hint is sent to clients and may # be used locally to aid authentication. The hint is a free form string that # doesn't have much meaning in itself, so feel free to be creative. # If this option is provided, see psk_file to define the pre-shared keys to be # used or create a security plugin to handle them. #psk_hint # Set use_identity_as_username to have the psk identity sent by the client used # as its username. Authentication will be carried out using the PSK rather than # the MQTT username/password and so password_file will not be used for this # listener. #use_identity_as_username false # When using PSK, the encryption ciphers used will be chosen from the list of # available PSK ciphers. If you want to control which ciphers are available, # use the "ciphers" option. The list of available ciphers can be obtained # using the "openssl ciphers" command and should be provided in the same format # as the output of that command. #ciphers # ================================================================= # Extra listeners # ================================================================= # Listen on a port/ip address combination. By using this variable # multiple times, mosquitto can listen on more than one port. If # this variable is used and neither bind_address nor port given, # then the default listener will not be started. # The port number to listen on must be given. Optionally, an ip # address or host name may be supplied as a second argument. In # this case, mosquitto will attempt to bind the listener to that # address and so restrict access to the associated network and # interface. By default, mosquitto will listen on all interfaces. # Note that for a websockets listener it is not possible to bind to a host # name. # listener port-number [ip address/host name] #listener # The maximum number of client connections to allow. This is # a per listener setting. # Default is -1, which means unlimited connections. # Note that other process limits mean that unlimited connections # are not really possible. Typically the default maximum number of # connections possible is around 1024. #max_connections -1 # The listener can be restricted to operating within a topic hierarchy using # the mount_point option. This is achieved be prefixing the mount_point string # to all topics for any clients connected to this listener. This prefixing only # happens internally to the broker; the client will not see the prefix. #mount_point # Choose the protocol to use when listening. # This can be either mqtt or websockets. # Certificate based TLS may be used with websockets, except that only the # cafile, certfile, keyfile and ciphers options are supported. #protocol mqtt # When a listener is using the websockets protocol, it is possible to serve # http data as well. Set http_dir to a directory which contains the files you # wish to serve. If this option is not specified, then no normal http # connections will be possible. #http_dir # Set use_username_as_clientid to true to replace the clientid that a client # connected with with its username. This allows authentication to be tied to # the clientid, which means that it is possible to prevent one client # disconnecting another by using the same clientid. # If a client connects with no username it will be disconnected as not # authorised when this option is set to true. # Do not use in conjunction with clientid_prefixes. # See also use_identity_as_username. #use_username_as_clientid # ----------------------------------------------------------------- # Certificate based SSL/TLS support # ----------------------------------------------------------------- # The following options can be used to enable certificate based SSL/TLS support # for this listener. Note that the recommended port for MQTT over TLS is 8883, # but this must be set manually. # # See also the mosquitto-tls man page and the "Pre-shared-key based SSL/TLS # support" section. Only one of certificate or PSK encryption support can be # enabled for any listener. # At least one of cafile or capath must be defined to enable certificate based # TLS encryption. They both define methods of accessing the PEM encoded # Certificate Authority certificates that have signed your server certificate # and that you wish to trust. # cafile defines the path to a file containing the CA certificates. # capath defines a directory that will be searched for files # containing the CA certificates. For capath to work correctly, the # certificate files must have ".crt" as the file ending and you must run # "c_rehash " each time you add/remove a certificate. #cafile #capath # Path to the PEM encoded server certificate. #certfile # Path to the PEM encoded keyfile. #keyfile # By default an TLS enabled listener will operate in a similar fashion to a # https enabled web server, in that the server has a certificate signed by a CA # and the client will verify that it is a trusted certificate. The overall aim # is encryption of the network traffic. By setting require_certificate to true, # the client must provide a valid certificate in order for the network # connection to proceed. This allows access to the broker to be controlled # outside of the mechanisms provided by MQTT. #require_certificate false # If require_certificate is true, you may set use_identity_as_username to true # to use the CN value from the client certificate as a username. If this is # true, the password_file option will not be used for this listener. #use_identity_as_username false # If you have require_certificate set to true, you can create a certificate # revocation list file to revoke access to particular client certificates. If # you have done this, use crlfile to point to the PEM encoded revocation file. #crlfile # If you wish to control which encryption ciphers are used, use the ciphers # option. The list of available ciphers can be optained using the "openssl # ciphers" command and should be provided in the same format as the output of # that command. #ciphers # ----------------------------------------------------------------- # Pre-shared-key based SSL/TLS support # ----------------------------------------------------------------- # The following options can be used to enable PSK based SSL/TLS support for # this listener. Note that the recommended port for MQTT over TLS is 8883, but # this must be set manually. # # See also the mosquitto-tls man page and the "Certificate based SSL/TLS # support" section. Only one of certificate or PSK encryption support can be # enabled for any listener. # The psk_hint option enables pre-shared-key support for this listener and also # acts as an identifier for this listener. The hint is sent to clients and may # be used locally to aid authentication. The hint is a free form string that # doesn't have much meaning in itself, so feel free to be creative. # If this option is provided, see psk_file to define the pre-shared keys to be # used or create a security plugin to handle them. #psk_hint # Set use_identity_as_username to have the psk identity sent by the client used # as its username. Authentication will be carried out using the PSK rather than # the MQTT username/password and so password_file will not be used for this # listener. #use_identity_as_username false # When using PSK, the encryption ciphers used will be chosen from the list of # available PSK ciphers. If you want to control which ciphers are available, # use the "ciphers" option. The list of available ciphers can be optained # using the "openssl ciphers" command and should be provided in the same format # as the output of that command. #ciphers # ================================================================= # Persistence # ================================================================= # If persistence is enabled, save the in-memory database to disk # every autosave_interval seconds. If set to 0, the persistence # database will only be written when mosquitto exits. See also # autosave_on_changes. # Note that writing of the persistence database can be forced by # sending mosquitto a SIGUSR1 signal. #autosave_interval 1800 # If true, mosquitto will count the number of subscription changes, retained # messages received and queued messages and if the total exceeds # autosave_interval then the in-memory database will be saved to disk. # If false, mosquitto will save the in-memory database to disk by treating # autosave_interval as a time in seconds. #autosave_on_changes false # Save persistent message data to disk (true/false). # This saves information about all messages, including # subscriptions, currently in-flight messages and retained # messages. # retained_persistence is a synonym for this option. #persistence false # The filename to use for the persistent database, not including # the path. #persistence_file mosquitto.db # Location for persistent database. Must include trailing / # Default is an empty string (current directory). # Set to e.g. /var/lib/mosquitto/ if running as a proper service on Linux or # similar. #persistence_location # ================================================================= # Logging # ================================================================= # Places to log to. Use multiple log_dest lines for multiple # logging destinations. # Possible destinations are: stdout stderr syslog topic file # # stdout and stderr log to the console on the named output. # # syslog uses the userspace syslog facility which usually ends up # in /var/log/messages or similar. # # topic logs to the broker topic '$SYS/broker/log/', # where severity is one of D, E, W, N, I, M which are debug, error, # warning, notice, information and message. Message type severity is used by # the subscribe/unsubscribe log_types and publishes log messages to # $SYS/broker/log/M/susbcribe or $SYS/broker/log/M/unsubscribe. # # The file destination requires an additional parameter which is the file to be # logged to, e.g. "log_dest file /var/log/mosquitto.log". The file will be # closed and reopened when the broker receives a HUP signal. Only a single file # destination may be configured. # # Note that if the broker is running as a Windows service it will default to # "log_dest none" and neither stdout nor stderr logging is available. # Use "log_dest none" if you wish to disable logging. #log_dest stderr # If using syslog logging (not on Windows), messages will be logged to the # "daemon" facility by default. Use the log_facility option to choose which of # local0 to local7 to log to instead. The option value should be an integer # value, e.g. "log_facility 5" to use local5. #log_facility # Types of messages to log. Use multiple log_type lines for logging # multiple types of messages. # Possible types are: debug, error, warning, notice, information, # none, subscribe, unsubscribe, websockets, all. # Note that debug type messages are for decoding the incoming/outgoing # network packets. They are not logged in "topics". #log_type error #log_type warning #log_type notice #log_type information # Change the websockets logging level. This is a global option, it is not # possible to set per listener. This is an integer that is interpreted by # libwebsockets as a bit mask for its lws_log_levels enum. See the # libwebsockets documentation for more details. "log_type websockets" must also # be enabled. #websockets_log_level 0 # If set to true, client connection and disconnection messages will be included # in the log. #connection_messages true # If set to true, add a timestamp value to each log message. #log_timestamp true # ================================================================= # Security # ================================================================= # If set, only clients that have a matching prefix on their # clientid will be allowed to connect to the broker. By default, # all clients may connect. # For example, setting "secure-" here would mean a client "secure- # client" could connect but another with clientid "mqtt" couldn't. #clientid_prefixes # Boolean value that determines whether clients that connect # without providing a username are allowed to connect. If set to # false then a password file should be created (see the # password_file option) to control authenticated client access. # Defaults to true. #allow_anonymous true # In addition to the clientid_prefixes, allow_anonymous and TLS # authentication options, username based authentication is also # possible. The default support is described in "Default # authentication and topic access control" below. The auth_plugin # allows another authentication method to be used. # Specify the path to the loadable plugin and see the # "Authentication and topic access plugin options" section below. #auth_plugin # If auth_plugin_deny_special_chars is true, the default, then before an ACL # check is made, the username/client id of the client needing the check is # searched for the presence of either a '+' or '#' character. If either of # these characters is found in either the username or client id, then the ACL # check is denied before it is sent to the plugin.o # # This check prevents the case where a malicious user could circumvent an ACL # check by using one of these characters as their username or client id. This # is the same issue as was reported with mosquitto itself as CVE-2017-7650. # # If you are entirely sure that the plugin you are using is not vulnerable to # this attack (i.e. if you never use usernames or client ids in topics) then # you can disable this extra check and have all ACL checks delivered to your # plugin by setting auth_plugin_deny_special_chars to false. #auth_plugin_deny_special_chars true # ----------------------------------------------------------------- # Default authentication and topic access control # ----------------------------------------------------------------- # Control access to the broker using a password file. This file can be # generated using the mosquitto_passwd utility. If TLS support is not compiled # into mosquitto (it is recommended that TLS support should be included) then # plain text passwords are used, in which case the file should be a text file # with lines in the format: # username:password # The password (and colon) may be omitted if desired, although this # offers very little in the way of security. # # See the TLS client require_certificate and use_identity_as_username options # for alternative authentication options. #password_file # Access may also be controlled using a pre-shared-key file. This requires # TLS-PSK support and a listener configured to use it. The file should be text # lines in the format: # identity:key # The key should be in hexadecimal format without a leading "0x". #psk_file # Control access to topics on the broker using an access control list # file. If this parameter is defined then only the topics listed will # have access. # If the first character of a line of the ACL file is a # it is treated as a # comment. # Topic access is added with lines of the format: # # topic [read|write|readwrite] # # The access type is controlled using "read", "write" or "readwrite". This # parameter is optional (unless contains a space character) - if not # given then the access is read/write. can contain the + or # # wildcards as in subscriptions. # # The first set of topics are applied to anonymous clients, assuming # allow_anonymous is true. User specific topic ACLs are added after a # user line as follows: # # user # # The username referred to here is the same as in password_file. It is # not the clientid. # # # If is also possible to define ACLs based on pattern substitution within the # topic. The patterns available for substition are: # # %c to match the client id of the client # %u to match the username of the client # # The substitution pattern must be the only text for that level of hierarchy. # # The form is the same as for the topic keyword, but using pattern as the # keyword. # Pattern ACLs apply to all users even if the "user" keyword has previously # been given. # # If using bridges with usernames and ACLs, connection messages can be allowed # with the following pattern: # pattern write $SYS/broker/connection/%c/state # # pattern [read|write|readwrite] # # Example: # # pattern write sensor/%u/data # #acl_file # ----------------------------------------------------------------- # Authentication and topic access plugin options # ----------------------------------------------------------------- # If the auth_plugin option above is used, define options to pass to the # plugin here as described by the plugin instructions. All options named # using the format auth_opt_* will be passed to the plugin, for example: # # auth_opt_db_host # auth_opt_db_port # auth_opt_db_username # auth_opt_db_password # ================================================================= # Bridges # ================================================================= # A bridge is a way of connecting multiple MQTT brokers together. # Create a new bridge using the "connection" option as described below. Set # options for the bridges using the remaining parameters. You must specify the # address and at least one topic to subscribe to. # Each connection must have a unique name. # The address line may have multiple host address and ports specified. See # below in the round_robin description for more details on bridge behaviour if # multiple addresses are used. # The direction that the topic will be shared can be chosen by # specifying out, in or both, where the default value is out. # The QoS level of the bridged communication can be specified with the next # topic option. The default QoS level is 0, to change the QoS the topic # direction must also be given. # The local and remote prefix options allow a topic to be remapped when it is # bridged to/from the remote broker. This provides the ability to place a topic # tree in an appropriate location. # For more details see the mosquitto.conf man page. # Multiple topics can be specified per connection, but be careful # not to create any loops. # If you are using bridges with cleansession set to false (the default), then # you may get unexpected behaviour from incoming topics if you change what # topics you are subscribing to. This is because the remote broker keeps the # subscription for the old topic. If you have this problem, connect your bridge # with cleansession set to true, then reconnect with cleansession set to false # as normal. #connection #address [:] [[:]] #topic [[[out | in | both] qos-level] local-prefix remote-prefix] # Set the version of the MQTT protocol to use with for this bridge. Can be one # of mqttv31 or mqttv311. Defaults to mqttv31. #bridge_protocol_version mqttv31 # If a bridge has topics that have "out" direction, the default behaviour is to # send an unsubscribe request to the remote broker on that topic. This means # that changing a topic direction from "in" to "out" will not keep receiving # incoming messages. Sending these unsubscribe requests is not always # desirable, setting bridge_attempt_unsubscribe to false will disable sending # the unsubscribe request. #bridge_attempt_unsubscribe true # If the bridge has more than one address given in the address/addresses # configuration, the round_robin option defines the behaviour of the bridge on # a failure of the bridge connection. If round_robin is false, the default # value, then the first address is treated as the main bridge connection. If # the connection fails, the other secondary addresses will be attempted in # turn. Whilst connected to a secondary bridge, the bridge will periodically # attempt to reconnect to the main bridge until successful. # If round_robin is true, then all addresses are treated as equals. If a # connection fails, the next address will be tried and if successful will # remain connected until it fails #round_robin false # Set the client id to use on the remote end of this bridge connection. If not # defined, this defaults to 'name.hostname' where name is the connection name # and hostname is the hostname of this computer. # This replaces the old "clientid" option to avoid confusion. "clientid" # remains valid for the time being. #remote_clientid # Set the clientid to use on the local broker. If not defined, this defaults to # 'local.'. If you are bridging a broker to itself, it is important # that local_clientid and clientid do not match. #local_clientid # Set the clean session variable for this bridge. # When set to true, when the bridge disconnects for any reason, all # messages and subscriptions will be cleaned up on the remote # broker. Note that with cleansession set to true, there may be a # significant amount of retained messages sent when the bridge # reconnects after losing its connection. # When set to false, the subscriptions and messages are kept on the # remote broker, and delivered when the bridge reconnects. #cleansession false # If set to true, publish notification messages to the local and remote brokers # giving information about the state of the bridge connection. Retained # messages are published to the topic $SYS/broker/connection//state # unless the notification_topic option is used. # If the message is 1 then the connection is active, or 0 if the connection has # failed. #notifications true # Choose the topic on which notification messages for this bridge are # published. If not set, messages are published on the topic # $SYS/broker/connection//state #notification_topic # Set the keepalive interval for this bridge connection, in # seconds. #keepalive_interval 60 # Set the start type of the bridge. This controls how the bridge starts and # can be one of three types: automatic, lazy and once. Note that RSMB provides # a fourth start type "manual" which isn't currently supported by mosquitto. # # "automatic" is the default start type and means that the bridge connection # will be started automatically when the broker starts and also restarted # after a short delay (30 seconds) if the connection fails. # # Bridges using the "lazy" start type will be started automatically when the # number of queued messages exceeds the number set with the "threshold" # parameter. It will be stopped automatically after the time set by the # "idle_timeout" parameter. Use this start type if you wish the connection to # only be active when it is needed. # # A bridge using the "once" start type will be started automatically when the # broker starts but will not be restarted if the connection fails. #start_type automatic # Set the amount of time a bridge using the automatic start type will wait # until attempting to reconnect. Defaults to 30 seconds. #restart_timeout 30 # Set the amount of time a bridge using the lazy start type must be idle before # it will be stopped. Defaults to 60 seconds. #idle_timeout 60 # Set the number of messages that need to be queued for a bridge with lazy # start type to be restarted. Defaults to 10 messages. # Must be less than max_queued_messages. #threshold 10 # If try_private is set to true, the bridge will attempt to indicate to the # remote broker that it is a bridge not an ordinary client. If successful, this # means that loop detection will be more effective and that retained messages # will be propagated correctly. Not all brokers support this feature so it may # be necessary to set try_private to false if your bridge does not connect # properly. #try_private true # Set the username to use when connecting to a broker that requires # authentication. # This replaces the old "username" option to avoid confusion. "username" # remains valid for the time being. #remote_username # Set the password to use when connecting to a broker that requires # authentication. This option is only used if remote_username is also set. # This replaces the old "password" option to avoid confusion. "password" # remains valid for the time being. #remote_password # ----------------------------------------------------------------- # Certificate based SSL/TLS support # ----------------------------------------------------------------- # Either bridge_cafile or bridge_capath must be defined to enable TLS support # for this bridge. # bridge_cafile defines the path to a file containing the # Certificate Authority certificates that have signed the remote broker # certificate. # bridge_capath defines a directory that will be searched for files containing # the CA certificates. For bridge_capath to work correctly, the certificate # files must have ".crt" as the file ending and you must run "c_rehash " each time you add/remove a certificate. #bridge_cafile #bridge_capath # Path to the PEM encoded client certificate, if required by the remote broker. #bridge_certfile # Path to the PEM encoded client private key, if required by the remote broker. #bridge_keyfile # When using certificate based encryption, bridge_insecure disables # verification of the server hostname in the server certificate. This can be # useful when testing initial server configurations, but makes it possible for # a malicious third party to impersonate your server through DNS spoofing, for # example. Use this option in testing only. If you need to resort to using this # option in a production environment, your setup is at fault and there is no # point using encryption. #bridge_insecure false # ----------------------------------------------------------------- # PSK based SSL/TLS support # ----------------------------------------------------------------- # Pre-shared-key encryption provides an alternative to certificate based # encryption. A bridge can be configured to use PSK with the bridge_identity # and bridge_psk options. These are the client PSK identity, and pre-shared-key # in hexadecimal format with no "0x". Only one of certificate and PSK based # encryption can be used on one # bridge at once. #bridge_identity #bridge_psk # ================================================================= # External config files # ================================================================= # External configuration files may be included by using the # include_dir option. This defines a directory that will be searched # for config files. All files that end in '.conf' will be loaded as # a configuration file. It is best to have this as the last option # in the main file. This option will only be processed from the main # configuration file. The directory specified must not contain the # main configuration file. #include_dir # ================================================================= # rsmb options - unlikely to ever be supported # ================================================================= #ffdc_output #max_log_entries #trace_level #trace_output mosquitto-1.4.15/notice.html0000664000175000017500000002201613245550210015033 0ustar rogerroger Eclipse Foundation Software User Agreement

Eclipse Foundation Software User Agreement

February 1, 2011

Usage Of Content

THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.

Applicable Licenses

Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html. For purposes of the EPL, "Program" will mean the Content.

Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").

  • Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
  • Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
  • A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins and/or Fragments associated with that Feature.
  • Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.

The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:

  • The top-level (root) directory
  • Plug-in and Fragment directories
  • Inside Plug-ins and Fragments packaged as JARs
  • Sub-directories of the directory named "src" of certain Plug-ins
  • Feature directories

Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature. Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.

Use of Provisioning Technology

The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").

You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:

  1. A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based product.
  2. During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be accessed and copied to the Target Machine.
  3. Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.

Cryptography

Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.

Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.

mosquitto-1.4.15/compiling.txt0000664000175000017500000000155113245550210015407 0ustar rogerrogerThe following packages are required for mosquitto: * tcp-wrappers (optional, package name libwrap0-dev) * openssl (version 1.0.0 or greater if TLS-PSK support is needed, can be disabled) * c-ares (for DNS-SRV support, can be disabled) * libuuid (from e2fsprogs, can be disabled) * On Windows, the Redhat pthreads library is required if threading support is to be included. To compile, run "make", but also see the file config.mk for more details on the various options that can be compiled in. Where possible use the Makefiles to compile. This is particularly relevant for the client libraries as symbol information will be included. Use cmake to compile on Windows or Mac. If you have any questions, problems or suggestions (particularly related to installing on a more unusual device like a plug-computer) then please get in touch using the details in readme.txt. mosquitto-1.4.15/service/0000775000175000017500000000000013245550210014323 5ustar rogerrogermosquitto-1.4.15/service/upstart/0000775000175000017500000000000013245550210016025 5ustar rogerrogermosquitto-1.4.15/service/upstart/mosquitto.conf0000664000175000017500000000026213245550210020740 0ustar rogerrogerdescription "Mosquitto MQTTv3.1 broker" author "Roger Light " start on net-device-up respawn exec /usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf mosquitto-1.4.15/service/svscan/0000775000175000017500000000000013245550210015620 5ustar rogerrogermosquitto-1.4.15/service/svscan/run0000775000175000017500000000010013245550210016341 0ustar rogerroger#!/bin/sh /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf mosquitto-1.4.15/service/monit/0000775000175000017500000000000013245550210015451 5ustar rogerrogermosquitto-1.4.15/service/monit/mosquitto.monit0000664000175000017500000000021113245550210020557 0ustar rogerrogercheck process mosquitto with pidfile /var/run/mosquitto.pid start = "/etc/init.d/mosquitto start" stop = "/etc/init.d/mosquitto stop" mosquitto-1.4.15/test/0000775000175000017500000000000013245550210013642 5ustar rogerrogermosquitto-1.4.15/test/packet-gen.c0000664000175000017500000000256013245550210016027 0ustar rogerroger/* Fudge a file description into a client instead of a socket connection so * that we can write out packets to a file. * See http://answers.launchpad.net/mosquitto/+question/123594 * also http://answers.launchpad.net/mosquitto/+question/136821 */ #include #include #include #include #include #include int main(int argc, char *argv[]) { struct mosquitto *mosq; int fd; bool clean_session = true; int keepalive = 60; mosq = mosquitto_new("packetgen", NULL); if(!mosq){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } /* CONNECT */ fd = open("mqtt.connect", O_CREAT|O_WRONLY, 00644); if(fd<0){ fprintf(stderr, "Error: Unable to open mqtt.connect for writing.\n"); return 1; } mosq->core.sock = fd; printf("_mosquitto_send_connect(): %d\n", _mosquitto_send_connect(mosq, keepalive, clean_session)); printf("loop: %d\n", mosquitto_loop_write(mosq)); close(fd); /* SUBSCRIBE */ fd = open("mqtt.subscribe", O_CREAT|O_WRONLY, 00644); if(fd<0){ fprintf(stderr, "Error: Unable to open mqtt.subscribe for writing.\n"); return 1; } mosq->core.sock = fd; printf("_mosquitto_send_subscribe(): %d\n", _mosquitto_send_subscribe(mosq, NULL, false, "subscribe/topic", 2)); printf("loop: %d\n", mosquitto_loop_write(mosq)); close(fd); mosquitto_destroy(mosq); return 0; } mosquitto-1.4.15/test/mosq_test.py0000664000175000017500000003277113245550210016244 0ustar rogerrogerimport errno import os import socket import subprocess import struct import time def start_broker(filename, cmd=None, port=1888): delay = 0.1 if cmd is None: cmd = ['../../src/mosquitto', '-v', '-c', filename.replace('.py', '.conf')] if os.environ.get('MOSQ_USE_VALGRIND') is not None: cmd = ['valgrind', '--trace-children=yes', '-v', '--log-file='+filename+'.vglog'] + cmd delay = 1 broker = subprocess.Popen(cmd, stderr=subprocess.PIPE) for i in range(0, 20): time.sleep(delay) c = None try: c = socket.create_connection(("localhost", port)) except socket.error as err: if err.errno != errno.ECONNREFUSED: raise if c is not None: c.close() time.sleep(delay) return broker raise IOError def start_client(filename, cmd, env): if cmd is None: raise ValueError if os.environ.get('MOSQ_USE_VALGRIND') is not None: cmd = ['valgrind', '-q', '--log-file='+filename+'.vglog'] + cmd return subprocess.Popen(cmd, env=env) def expect_packet(sock, name, expected): if len(expected) > 0: rlen = len(expected) else: rlen = 1 packet_recvd = sock.recv(rlen) return packet_matches(name, packet_recvd, expected) def packet_matches(name, recvd, expected): if recvd != expected: print("FAIL: Received incorrect "+name+".") try: print("Received: "+to_string(recvd)) except struct.error: print("Received (not decoded): "+recvd) try: print("Expected: "+to_string(expected)) except struct.error: print("Expected (not decoded): "+expected) return 0 else: return 1 def do_client_connect(connect_packet, connack_packet, hostname="localhost", port=1888, timeout=60, connack_error="connack"): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) sock.connect((hostname, port)) sock.send(connect_packet) if expect_packet(sock, connack_error, connack_packet): return sock else: sock.close() raise ValueError def remaining_length(packet): l = min(5, len(packet)) all_bytes = struct.unpack("!"+"B"*l, packet[:l]) mult = 1 rl = 0 for i in range(1,l-1): byte = all_bytes[i] rl += (byte & 127) * mult mult *= 128 if byte & 128 == 0: packet = packet[i+1:] break return (packet, rl) def to_hex_string(packet): if len(packet) == 0: return "" s = "" while len(packet) > 0: packet0 = struct.unpack("!B", packet[0]) s = s+hex(packet0[0]) + " " packet = packet[1:] return s def to_string(packet): if len(packet) == 0: return "" packet0 = struct.unpack("!B", packet[0]) packet0 = packet0[0] cmd = packet0 & 0xF0 if cmd == 0x00: # Reserved return "0x00" elif cmd == 0x10: # CONNECT (packet, rl) = remaining_length(packet) pack_format = "!H" + str(len(packet)-2) + 's' (slen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(slen)+'sBBH' + str(len(packet)-slen-4) + 's' (protocol, proto_ver, flags, keepalive, packet) = struct.unpack(pack_format, packet) s = "CONNECT, proto="+protocol+str(proto_ver)+", keepalive="+str(keepalive) if flags&2: s = s+", clean-session" else: s = s+", durable" pack_format = "!H" + str(len(packet)-2) + 's' (slen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(slen)+'s' + str(len(packet)-slen) + 's' (client_id, packet) = struct.unpack(pack_format, packet) s = s+", id="+client_id if flags&4: pack_format = "!H" + str(len(packet)-2) + 's' (slen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(slen)+'s' + str(len(packet)-slen) + 's' (will_topic, packet) = struct.unpack(pack_format, packet) s = s+", will-topic="+will_topic pack_format = "!H" + str(len(packet)-2) + 's' (slen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(slen)+'s' + str(len(packet)-slen) + 's' (will_message, packet) = struct.unpack(pack_format, packet) s = s+", will-message="+will_message s = s+", will-qos="+str((flags&24)>>3) s = s+", will-retain="+str((flags&32)>>5) if flags&128: pack_format = "!H" + str(len(packet)-2) + 's' (slen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(slen)+'s' + str(len(packet)-slen) + 's' (username, packet) = struct.unpack(pack_format, packet) s = s+", username="+username if flags&64: pack_format = "!H" + str(len(packet)-2) + 's' (slen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(slen)+'s' + str(len(packet)-slen) + 's' (password, packet) = struct.unpack(pack_format, packet) s = s+", password="+password if flags&1: s = s+", reserved=1" return s elif cmd == 0x20: # CONNACK (cmd, rl, resv, rc) = struct.unpack('!BBBB', packet) return "CONNACK, rl="+str(rl)+", res="+str(resv)+", rc="+str(rc) elif cmd == 0x30: # PUBLISH dup = (packet0 & 0x08)>>3 qos = (packet0 & 0x06)>>1 retain = (packet0 & 0x01) (packet, rl) = remaining_length(packet) pack_format = "!H" + str(len(packet)-2) + 's' (tlen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(tlen)+'s' + str(len(packet)-tlen) + 's' (topic, packet) = struct.unpack(pack_format, packet) s = "PUBLISH, rl="+str(rl)+", topic="+topic+", qos="+str(qos)+", retain="+str(retain)+", dup="+str(dup) if qos > 0: pack_format = "!H" + str(len(packet)-2) + 's' (mid, packet) = struct.unpack(pack_format, packet) s = s + ", mid="+str(mid) s = s + ", payload="+packet return s elif cmd == 0x40: # PUBACK (cmd, rl, mid) = struct.unpack('!BBH', packet) return "PUBACK, rl="+str(rl)+", mid="+str(mid) elif cmd == 0x50: # PUBREC (cmd, rl, mid) = struct.unpack('!BBH', packet) return "PUBREC, rl="+str(rl)+", mid="+str(mid) elif cmd == 0x60: # PUBREL dup = (packet0 & 0x08)>>3 (cmd, rl, mid) = struct.unpack('!BBH', packet) return "PUBREL, rl="+str(rl)+", mid="+str(mid)+", dup="+str(dup) elif cmd == 0x70: # PUBCOMP (cmd, rl, mid) = struct.unpack('!BBH', packet) return "PUBCOMP, rl="+str(rl)+", mid="+str(mid) elif cmd == 0x80: # SUBSCRIBE (packet, rl) = remaining_length(packet) pack_format = "!H" + str(len(packet)-2) + 's' (mid, packet) = struct.unpack(pack_format, packet) s = "SUBSCRIBE, rl="+str(rl)+", mid="+str(mid) topic_index = 0 while len(packet) > 0: pack_format = "!H" + str(len(packet)-2) + 's' (tlen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(tlen)+'sB' + str(len(packet)-tlen-1) + 's' (topic, qos, packet) = struct.unpack(pack_format, packet) s = s + ", topic"+str(topic_index)+"="+topic+","+str(qos) return s elif cmd == 0x90: # SUBACK (packet, rl) = remaining_length(packet) pack_format = "!H" + str(len(packet)-2) + 's' (mid, packet) = struct.unpack(pack_format, packet) pack_format = "!" + "B"*len(packet) granted_qos = struct.unpack(pack_format, packet) s = "SUBACK, rl="+str(rl)+", mid="+str(mid)+", granted_qos="+str(granted_qos[0]) for i in range(1, len(granted_qos)-1): s = s+", "+str(granted_qos[i]) return s elif cmd == 0xA0: # UNSUBSCRIBE (packet, rl) = remaining_length(packet) pack_format = "!H" + str(len(packet)-2) + 's' (mid, packet) = struct.unpack(pack_format, packet) s = "UNSUBSCRIBE, rl="+str(rl)+", mid="+str(mid) topic_index = 0 while len(packet) > 0: pack_format = "!H" + str(len(packet)-2) + 's' (tlen, packet) = struct.unpack(pack_format, packet) pack_format = "!" + str(tlen)+'s' + str(len(packet)-tlen) + 's' (topic, packet) = struct.unpack(pack_format, packet) s = s + ", topic"+str(topic_index)+"="+topic return s elif cmd == 0xB0: # UNSUBACK (cmd, rl, mid) = struct.unpack('!BBH', packet) return "UNSUBACK, rl="+str(rl)+", mid="+str(mid) elif cmd == 0xC0: # PINGREQ (cmd, rl) = struct.unpack('!BB', packet) return "PINGREQ, rl="+str(rl) elif cmd == 0xD0: # PINGRESP (cmd, rl) = struct.unpack('!BB', packet) return "PINGRESP, rl="+str(rl) elif cmd == 0xE0: # DISCONNECT (cmd, rl) = struct.unpack('!BB', packet) return "DISCONNECT, rl="+str(rl) elif cmd == 0xF0: # Reserved return "0xF0" def gen_connect(client_id, clean_session=True, keepalive=60, username=None, password=None, will_topic=None, will_qos=0, will_retain=False, will_payload="", proto_ver=3, connect_reserved=False): if (proto_ver&0x7F) == 3 or proto_ver == 0: remaining_length = 12 elif (proto_ver&0x7F) == 4: remaining_length = 10 else: raise ValueError if client_id != None: remaining_length = remaining_length + 2+len(client_id) connect_flags = 0 if connect_reserved: connect_flags = connect_flags | 0x01 if clean_session: connect_flags = connect_flags | 0x02 if will_topic != None: remaining_length = remaining_length + 2+len(will_topic) + 2+len(will_payload) connect_flags = connect_flags | 0x04 | ((will_qos&0x03) << 3) if will_retain: connect_flags = connect_flags | 32 if username != None: remaining_length = remaining_length + 2+len(username) connect_flags = connect_flags | 0x80 if password != None: connect_flags = connect_flags | 0x40 remaining_length = remaining_length + 2+len(password) rl = pack_remaining_length(remaining_length) packet = struct.pack("!B"+str(len(rl))+"s", 0x10, rl) if (proto_ver&0x7F) == 3 or proto_ver == 0: packet = packet + struct.pack("!H6sBBH", len("MQIsdp"), "MQIsdp", proto_ver, connect_flags, keepalive) elif (proto_ver&0x7F) == 4: packet = packet + struct.pack("!H4sBBH", len("MQTT"), "MQTT", proto_ver, connect_flags, keepalive) if client_id != None: packet = packet + struct.pack("!H"+str(len(client_id))+"s", len(client_id), client_id) if will_topic != None: packet = packet + struct.pack("!H"+str(len(will_topic))+"s", len(will_topic), will_topic) if len(will_payload) > 0: packet = packet + struct.pack("!H"+str(len(will_payload))+"s", len(will_payload), will_payload) else: packet = packet + struct.pack("!H", 0) if username != None: packet = packet + struct.pack("!H"+str(len(username))+"s", len(username), username) if password != None: packet = packet + struct.pack("!H"+str(len(password))+"s", len(password), password) return packet def gen_connack(resv=0, rc=0): return struct.pack('!BBBB', 32, 2, resv, rc); def gen_publish(topic, qos, payload=None, retain=False, dup=False, mid=0): rl = 2+len(topic) pack_format = "!BBH"+str(len(topic))+"s" if qos > 0: rl = rl + 2 pack_format = pack_format + "H" if payload != None: rl = rl + len(payload) pack_format = pack_format + str(len(payload))+"s" else: payload = "" pack_format = pack_format + "0s" cmd = 48 | (qos<<1) if retain: cmd = cmd + 1 if dup: cmd = cmd + 8 if qos > 0: return struct.pack(pack_format, cmd, rl, len(topic), topic, mid, payload) else: return struct.pack(pack_format, cmd, rl, len(topic), topic, payload) def gen_puback(mid): return struct.pack('!BBH', 64, 2, mid) def gen_pubrec(mid): return struct.pack('!BBH', 80, 2, mid) def gen_pubrel(mid, dup=False): if dup: cmd = 96+8+2 else: cmd = 96+2 return struct.pack('!BBH', cmd, 2, mid) def gen_pubcomp(mid): return struct.pack('!BBH', 112, 2, mid) def gen_subscribe(mid, topic, qos): pack_format = "!BBHH"+str(len(topic))+"sB" return struct.pack(pack_format, 130, 2+2+len(topic)+1, mid, len(topic), topic, qos) def gen_suback(mid, qos): return struct.pack('!BBHB', 144, 2+1, mid, qos) def gen_unsubscribe(mid, topic): pack_format = "!BBHH"+str(len(topic))+"s" return struct.pack(pack_format, 162, 2+2+len(topic), mid, len(topic), topic) def gen_unsuback(mid): return struct.pack('!BBH', 176, 2, mid) def gen_pingreq(): return struct.pack('!BB', 192, 0) def gen_pingresp(): return struct.pack('!BB', 208, 0) def gen_disconnect(): return struct.pack('!BB', 224, 0) def pack_remaining_length(remaining_length): s = "" while True: byte = remaining_length % 128 remaining_length = remaining_length // 128 # If there are more digits to encode, set the top bit of this digit if remaining_length > 0: byte = byte | 0x80 s = s + struct.pack("!B", byte) if remaining_length == 0: return s mosquitto-1.4.15/test/msgsps_sub.c0000664000175000017500000000403613245550210016176 0ustar rogerroger/* This provides a crude manner of testing the performance of a broker in messages/s. */ #include #include #include #include #include #include #include static bool run = true; static int message_count = 0; static struct timeval start, stop; FILE *fptr = NULL; void my_connect_callback(struct mosquitto *mosq, void *obj, int rc) { printf("rc: %d\n", rc); } void my_disconnect_callback(struct mosquitto *mosq, void *obj, int result) { run = false; } void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) { if(message_count == 0){ gettimeofday(&start, NULL); } fwrite(msg->payload, sizeof(uint8_t), msg->payloadlen, fptr); message_count++; if(message_count == MESSAGE_COUNT){ gettimeofday(&stop, NULL); mosquitto_disconnect((struct mosquitto *)obj); } } int main(int argc, char *argv[]) { struct mosquitto *mosq; double dstart, dstop, diff; int mid = 0; char id[50]; int rc; start.tv_sec = 0; start.tv_usec = 0; stop.tv_sec = 0; stop.tv_usec = 0; fptr = fopen("msgsps_sub.dat", "wb"); if(!fptr){ printf("Error: Unable to write to msgsps_sub.dat.\n"); return 1; } mosquitto_lib_init(); snprintf(id, 50, "msgps_sub_%d", getpid()); mosq = mosquitto_new(id, true, NULL); mosquitto_connect_callback_set(mosq, my_connect_callback); mosquitto_disconnect_callback_set(mosq, my_disconnect_callback); mosquitto_message_callback_set(mosq, my_message_callback); mosquitto_connect(mosq, "127.0.0.1", 1884, 600); mosquitto_subscribe(mosq, &mid, "perf/test", 0); do{ rc = mosquitto_loop(mosq, 1, 10); }while(rc == MOSQ_ERR_SUCCESS && run); printf("rc: %d\n", rc); dstart = (double)start.tv_sec*1.0e6 + (double)start.tv_usec; dstop = (double)stop.tv_sec*1.0e6 + (double)stop.tv_usec; diff = (dstop-dstart)/1.0e6; printf("Start: %g\nStop: %g\nDiff: %g\nMessages/s: %g\n", dstart, dstop, diff, (double)MESSAGE_COUNT/diff); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); fclose(fptr); return 0; } mosquitto-1.4.15/test/Makefile0000664000175000017500000000422013245550210015300 0ustar rogerrogerinclude ../config.mk CC=cc CFLAGS=-I../src -I../lib -I. -I.. -Wall -ggdb -DDEBUG -DWITH_CLIENT LDFLAGS= OBJS=context.o database.o logging.o memory.o net.o raw_send.o raw_send_client.o read_handle.o read_handle_client.o util.o SOVERSION=1 .PHONY: all test clean reallyclean all : fake_user msgsps_pub msgsps_sub #packet-gen qos test : $(MAKE) -C broker test $(MAKE) -C lib test fake_user : fake_user.o ${CC} $^ -o $@ ../lib/libmosquitto.so.${SOVERSION} #${CC} $^ -o $@ -lmosquitto fake_user.o : fake_user.c ${CC} $(CFLAGS) -c $< -o $@ msgsps_pub : msgsps_pub.o ${CC} $^ -o $@ ../lib/libmosquitto.so.${SOVERSION} msgsps_pub.o : msgsps_pub.c msgsps_common.h ${CC} $(CFLAGS) -c $< -o $@ msgsps_sub : msgsps_sub.o ${CC} $^ -o $@ ../lib/libmosquitto.so.${SOVERSION} msgsps_sub.o : msgsps_sub.c msgsps_common.h ${CC} $(CFLAGS) -c $< -o $@ packet-gen : packet-gen.o ${CC} $^ -o $@ ../lib/libmosquitto.so.${SOVERSION} packet-gen.o : packet-gen.c ${CC} $(CFLAGS) -c $< -o $@ qos : qos.o ${CC} $^ -o $@ ../lib/libmosquitto.so.${SOVERSION} qos.o : qos.c ${CC} $(CFLAGS) -c $< -o $@ random_client : random_client.o ${OBJS} ${CC} $^ -o $@ ${LDFLAGS} random_client.o : random_client.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ context.o : ../src/context.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ database.o : ../src/database.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ logging.o : ../src/logging.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ memory.o : ../src/memory.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ net.o : ../src/net.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ raw_send.o : ../src/raw_send.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ raw_send_client.o : ../src/raw_send_client.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ read_handle.o : ../src/read_handle.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ read_handle_client.o : ../src/read_handle_client.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ util.o : ../src/util.c ../src/mqtt3.h ${CC} $(CFLAGS) -c $< -o $@ reallyclean : clean -rm -f *.orig clean : -rm -f *.o random_client qos msgsps_pub msgsps_sub fake_user test_client *.pyc $(MAKE) -C lib clean $(MAKE) -C broker clean mosquitto-1.4.15/test/to-test0000664000175000017500000000021213245550210015157 0ustar rogerrogermessage delivery 0, 1, 2 retained message delivery queued message delivery for 1, 2 wills bridge connections password authentication ACLs mosquitto-1.4.15/test/ssl/0000775000175000017500000000000013245550210014443 5ustar rogerrogermosquitto-1.4.15/test/ssl/test-alt-ca.key0000664000175000017500000000156713245550210017304 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDUBOZpE1wtVsUOEPNbNLjw2wBP5MTjLaQyC9arU6GoMenoPW/7 jdT3Ca1UXEezJ0rI0ZUeQyrJS7bCgYpLhFbyiEO5U1ri+JFrLyYeh2Jz68FFnnqX P/jb0r/WRCCnhPsR6+nLg190OaeVhUwPB8ABUAH/NLQsj1DY7mHNNUAsBQIDAQAB AoGACeLwm5W7hqG1LqK7tlUPCqwrp44TYESQk4TZzcNoll89eQbkYeaLN7nLy1NC RKhgZFzhhze6lwhgzVEdEchqBW9qtznz/D2rxKfuRrlKylG7WzOIPHjIWFpkuRcm 7rTJnqMTBndH8zfGd8c+q7YVRxgA4r4UG8NMq9Mqrp0LmgECQQD7eisZIbsbgVpW cM3zusTYcud+eky0TJhHuZWRFoIrvNk9iHEcI47J+0t4bTlXxuU9oarL3bvMmNBb HMceWwnpAkEA19UP2MgM6yKioYJ+2pCYlNdWLR3HHAX4QY1VJk4C2+V5Sw7Ld3NP WBOH5XYK5tfWmmt+C8g2ga1iY9BEb9cjvQJAIAGDfLZbTvvemIPQ4oVRyk6Ngf5k xsm809wd2hJoTNLDP16fLrqj0Lcn+tLD6pUI1hg+WaYF4dtNIVt/SDDECQJBAIpi TbrM6ZuJpYSwyu0QcQRd3R8oTJWnLjm5iLL6qdKcG10Iq2R3RpROUX/KY8sG8M4p xbOAN5KFvOQKkRa0dnECQQDkz6bXTDHQlerNZ5B0MFFL5VrOC/n4qyVvtJ4jasK9 3GF3X27zr4XyMfKgL+WPLJMG5nmv62MV1vhUtbvM+GqN -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/client-encrypted.key0000664000175000017500000000170313245550210020427 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,A17B16521713FB61 B/x474t6DV07g7r7Le3Ekh/ggZ7ZM8EdwdzqiXom4ZR8eSCk4gIDpQrfn7bqzVY2 25CG1qc4xadk4gFV8GKQeXn3/bVdqfOsTnawq6X9RylwA1HV1st2fVows2DSqskg tHS+tAYW1ZEu1qGEM5g1zmAuE4odtMD7jzZR2JMEHHFi5O1XY31EHY25jifDjIml 370zKyPV5VxjrvJRFJq+aY7gn+jnEeVUnF6RtG11RPb101a+vyax4C5z9xO+JfNQ JkEDdFTEejHWabz43gSju8lwgrrzlhR5Yo/AbItk5XduG9VkJX27Jezr87Cn7IqX Xqja+DCUSFGX++nUCDWLs46Pw9VCp6kZsZt/yUa2cA/JGnmZv06aEf1tn6WsGY5/ Fnq7K5RJTwbkpPdUckXK6OQZdRwb4uRqbj7F2OaWLYwr/jfj2innk+TQXmcxs4xz d6greZqyKmx0LcXlI3mpcY3CqKXFazl1pVqiIDdYNMWrNucvMnWX1D5YlCCoyICl xMtOjk3I2nVba1bdOPtHSXb+BiGkf2Y67ffNCtg2Z7YMCF2yVLVXFuuf4hoRwbOU fTwdPcdNZeAMF86stw71hMVq0SDagPV4kTO2IuzbJAWts8sUI0xpZnqZ5AxbQF0v uuE5Q259K+dneI7NaLpSidWW6+wslMABwuKEhGRlO6vZcpN7bqtGbRKKvHoj2ii3 ebVhk44meh74aWYDoVbtY5HeKFqMSOo6gz6vyZ4udXKM9YpMX4xPx66BBI+8SGez vouO1xEE1mTtxcQcSHdDFSE8aKdOX1sVwaq/S++dXBFklbwZzj0bAw== -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/client.csr0000664000175000017500000000124013245550210016427 0ustar rogerroger-----BEGIN CERTIFICATE REQUEST----- MIIBuDCCASECAQAweDELMAkGA1UEBhMCR0IxGDAWBgNVBAgMD05vdHRpbmdoYW1z aGlyZTETMBEGA1UEBwwKTm90dGluZ2hhbTEPMA0GA1UECgwGU2VydmVyMRMwEQYD VQQLDApQcm9kdWN0aW9uMRQwEgYDVQQDDAt0ZXN0IGNsaWVudDCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAmvC+cVdROE4a3jUdPDdmatZadxd9+WZVL8W4FwQ8 WeaPqq4WucFkoaA7ygztNekqhem2NmXWrmJx0YkU5joYwQsoyHfIJuL8+VF2biFw QihOMoCcXqZYJrJsQLmvlyPB/kvBf7YF0o71kDTMCijtMddxW9xtL/9Da3gaxW9C Ax8CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAH5l2eVGP+//MBFAT+ne3/KQvoRQ yF4xlDjvKUlK3LHjT+js/fxGQJWmXqea5jRmEZjAxNnjDcjf828jaFkaQGsoajym ebNL5RvrPykwaXjdhHgavDiM/LCRR6bDCUYzS5akjZx2ENQ1TM7BVThOJQ2W+KPn xdxeRH8KxKGJ3wp0 -----END CERTIFICATE REQUEST----- mosquitto-1.4.15/test/ssl/test-bad-root-ca.key0000664000175000017500000000156713245550210020233 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDYHC6H3lBpdt1SyvGTIKHPP7Ia1UBUYAQJOP9EuvhxzWYNeTZt xApfb6AuKn2WNINGQhr1gPUD4ptZUe0Y81pOBgo8siaxgD2kPeg69besavXjt5dE MgIMrld1FyGIVobn96vh7R5mSX6H9UUi4zX+SRUQsVqGChpjj/pw1XIQpwIDAQAB AoGAMo+dX1JnE9WogGdUz6xRzzBC1j5QV61DJHk+V/E6kT2SA9L5JgM4vg1at5Jf YZYVpIlwz0GFkYwh9mrRgwXkeXB4LfA31VTOw5l3NzRGyHERiFlhnf5W5pEJOaWm gaOm7/5M5MBrQqgdNHGNhr1hgggXnSXbrhoOu8LmItcGxrECQQD5HBsQSlE+AJg7 ayAfugbmRD+P9OyCDPx19GHL3D0FWc9xGLn5XQ9qFyGgY8vKkRUUsAn4TyDLjyBa zWsX0chvAkEA3hZpfDtZuEtdhA2H5xq8WCH3DU4a2Qf/isB+r1PMV1xZ+FfmqmBE d6g83NpjyWreZG9bafERCLO8mAjhQdknSQJAVref/DXCvlC6rcSG9ERv7mzHq7dZ NZSLtgwSl0LdwyUWf4paAyKQISBYRls3MBb9PaxibBwvkG0MmE91/l665QJAfwGk K6apZYq8HTO7v797bI9oAJTlJ666RjhVeqDaoC8xSKPERzUskp2EyOyf2mUib597 ULfK/QYE2ZFieMzd+QJAIYYxEYBb1LJ4PPDsV5JQRmaMb6r5ElOMl0sJs878o0L+ oOOeyn/8cbKHTtJLfm21YfNUO1TsRJZ3bOlhAPrT/g== -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/test-fake-root-ca.crt0000664000175000017500000000174513245550210020411 0ustar rogerroger-----BEGIN CERTIFICATE----- MIICsjCCAhugAwIBAgIJAOOjGsO7TBrTMA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV BAYTAkdCMRMwEQYDVQQIDApEZXJieXNoaXJlMQ4wDAYDVQQHDAVEZXJieTEaMBgG A1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNVBAsMB1Rlc3RpbmcxEDAOBgNV BAMMB1Jvb3QgQ0EwHhcNMTMwODMwMjIwMzE3WhcNMjMwODI4MjIwMzE3WjByMQsw CQYDVQQGEwJHQjETMBEGA1UECAwKRGVyYnlzaGlyZTEOMAwGA1UEBwwFRGVyYnkx GjAYBgNVBAoMEU1vc3F1aXR0byBQcm9qZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRAw DgYDVQQDDAdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCih0Ux pn7wdxufnDagJtW/mf4at3n1TKGVNirCIh8hoU+EdIqLarNt9ayWnJc3h8cHvG9F 21ic2zbM+I5L9Iavqkpb9hChLm3Ft+HIxKliXnB48Fr5r1J/rt3jIHHwE02HcPm1 TqLKejHpjngZuMjRV/A5CVJ/iAQZy9ABRjEnRQIDAQABo1AwTjAdBgNVHQ4EFgQU 8YIrNiwFO8c97RWwfMUGokdbxU0wHwYDVR0jBBgwFoAU8YIrNiwFO8c97RWwfMUG okdbxU0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCI9QpvF3fdWO1g W+zOZzBPspqIXqoRou8P135lNTLWHTixFAscWNdPOZn19zzmPGRKMMmtzOqoRMAx XDORn9n7ZhyIn2kjw5nTfwrO21TsgYaUOGQSCay5GPFryAEX+1kWkqOoVbJ3F99Q wU8uq/pogwQ/VTSQJqgUCEvN1aiyLw== -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/test-alt-ca.crt0000664000175000017500000000572013245550210017277 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, L=Derby, O=Mosquitto Project, OU=Testing, CN=Root CA Validity Not Before: Aug 30 22:03:27 2013 GMT Not After : Aug 29 22:03:27 2018 GMT Subject: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Alternative Signing CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:d4:04:e6:69:13:5c:2d:56:c5:0e:10:f3:5b:34: b8:f0:db:00:4f:e4:c4:e3:2d:a4:32:0b:d6:ab:53: a1:a8:31:e9:e8:3d:6f:fb:8d:d4:f7:09:ad:54:5c: 47:b3:27:4a:c8:d1:95:1e:43:2a:c9:4b:b6:c2:81: 8a:4b:84:56:f2:88:43:b9:53:5a:e2:f8:91:6b:2f: 26:1e:87:62:73:eb:c1:45:9e:7a:97:3f:f8:db:d2: bf:d6:44:20:a7:84:fb:11:eb:e9:cb:83:5f:74:39: a7:95:85:4c:0f:07:c0:01:50:01:ff:34:b4:2c:8f: 50:d8:ee:61:cd:35:40:2c:05 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 9A:86:EB:20:AE:18:31:4F:8D:E2:0D:B9:FA:63:31:EA:DF:A4:8C:35 X509v3 Authority Key Identifier: keyid:28:8D:BF:F8:DE:D1:F5:BB:26:37:A4:4D:27:FD:37:91:EC:6B:0C:DD X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption af:8e:86:a9:b0:74:70:1b:46:4f:85:3c:7d:4e:6d:a0:de:f4: 45:e2:34:d8:3f:a1:c6:18:35:ed:1b:f2:19:88:79:b5:da:a5: df:e8:82:a1:e8:72:c0:da:68:3c:3b:83:fa:23:2d:85:d6:97: b0:70:02:22:39:10:40:de:e6:45:86:a8:ee:85:a9:04:f2:51: 99:82:a2:e3:8f:b6:fd:8a:29:e8:3a:47:92:56:a6:98:cf:b7: 39:5c:4f:83:80:a9:9f:89:f6:a6:33:95:d1:f3:5d:65:30:aa: ad:89:40:c0:fd:d1:24:6a:f5:b2:c8:50:71:9b:01:c6:cc:8c: af:35 -----BEGIN CERTIFICATE----- MIICqTCCAhKgAwIBAgIBAjANBgkqhkiG9w0BAQUFADByMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEOMAwGA1UEBwwFRGVyYnkxGjAYBgNVBAoMEU1v c3F1aXR0byBQcm9qZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRAwDgYDVQQDDAdSb290 IENBMB4XDTEzMDgzMDIyMDMyN1oXDTE4MDgyOTIyMDMyN1owcTELMAkGA1UEBhMC R0IxEzARBgNVBAgMCkRlcmJ5c2hpcmUxGjAYBgNVBAoMEU1vc3F1aXR0byBQcm9q ZWN0MRAwDgYDVQQLDAdUZXN0aW5nMR8wHQYDVQQDDBZBbHRlcm5hdGl2ZSBTaWdu aW5nIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUBOZpE1wtVsUOEPNb NLjw2wBP5MTjLaQyC9arU6GoMenoPW/7jdT3Ca1UXEezJ0rI0ZUeQyrJS7bCgYpL hFbyiEO5U1ri+JFrLyYeh2Jz68FFnnqXP/jb0r/WRCCnhPsR6+nLg190OaeVhUwP B8ABUAH/NLQsj1DY7mHNNUAsBQIDAQABo1AwTjAdBgNVHQ4EFgQUmobrIK4YMU+N 4g25+mMx6t+kjDUwHwYDVR0jBBgwFoAUKI2/+N7R9bsmN6RNJ/03kexrDN0wDAYD VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCvjoapsHRwG0ZPhTx9Tm2g3vRF 4jTYP6HGGDXtG/IZiHm12qXf6IKh6HLA2mg8O4P6Iy2F1pewcAIiORBA3uZFhqju hakE8lGZgqLjj7b9iinoOkeSVqaYz7c5XE+DgKmfifamM5XR811lMKqtiUDA/dEk avWyyFBxmwHGzIyvNQ== -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/client.crt0000664000175000017500000000611113245550210016432 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Validity Not Before: Aug 30 22:03:31 2013 GMT Not After : Aug 29 22:03:31 2018 GMT Subject: C=GB, ST=Nottinghamshire, L=Nottingham, O=Server, OU=Production, CN=test client Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:9a:f0:be:71:57:51:38:4e:1a:de:35:1d:3c:37: 66:6a:d6:5a:77:17:7d:f9:66:55:2f:c5:b8:17:04: 3c:59:e6:8f:aa:ae:16:b9:c1:64:a1:a0:3b:ca:0c: ed:35:e9:2a:85:e9:b6:36:65:d6:ae:62:71:d1:89: 14:e6:3a:18:c1:0b:28:c8:77:c8:26:e2:fc:f9:51: 76:6e:21:70:42:28:4e:32:80:9c:5e:a6:58:26:b2: 6c:40:b9:af:97:23:c1:fe:4b:c1:7f:b6:05:d2:8e: f5:90:34:cc:0a:28:ed:31:d7:71:5b:dc:6d:2f:ff: 43:6b:78:1a:c5:6f:42:03:1f Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: CC:E1:DD:22:B5:A1:24:98:8F:47:1E:FF:4F:AE:88:7E:E5:40:56:DB X509v3 Authority Key Identifier: keyid:40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB Signature Algorithm: sha1WithRSAEncryption 0f:0c:fa:e2:7d:c6:64:58:70:0b:f1:22:1b:bc:ef:ba:60:17: d8:29:9b:51:bf:a7:6f:cd:89:7c:bd:b7:02:b8:3c:4e:f2:22: 24:31:3d:4a:54:4d:14:98:ce:37:14:3a:74:23:31:bd:50:53: b2:aa:d1:9e:d0:b0:a8:1d:e2:b5:be:7e:6f:26:20:d8:b2:5b: 5c:c4:9d:5d:f1:c3:6f:e1:3b:c1:ea:eb:18:39:79:d9:78:96: 44:c7:88:65:68:41:05:58:40:83:99:8e:fc:11:64:1b:cf:96: fe:62:df:68:a8:a7:cb:fe:f1:cc:bf:a6:cb:8a:74:94:14:dd: 69:12 -----BEGIN CERTIFICATE----- MIICzjCCAjegAwIBAgIBAjANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTMwODMw MjIwMzMxWhcNMTgwODI5MjIwMzMxWjB4MQswCQYDVQQGEwJHQjEYMBYGA1UECAwP Tm90dGluZ2hhbXNoaXJlMRMwEQYDVQQHDApOb3R0aW5naGFtMQ8wDQYDVQQKDAZT ZXJ2ZXIxEzARBgNVBAsMClByb2R1Y3Rpb24xFDASBgNVBAMMC3Rlc3QgY2xpZW50 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCa8L5xV1E4ThreNR08N2Zq1lp3 F335ZlUvxbgXBDxZ5o+qrha5wWShoDvKDO016SqF6bY2ZdauYnHRiRTmOhjBCyjI d8gm4vz5UXZuIXBCKE4ygJxeplgmsmxAua+XI8H+S8F/tgXSjvWQNMwKKO0x13Fb 3G0v/0NreBrFb0IDHwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUzOHdIrWh JJiPRx7/T66IfuVAVtswHwYDVR0jBBgwFoAUQENQFNFjfgt8lxQgY+WKlZaf1Ksw DQYJKoZIhvcNAQEFBQADgYEADwz64n3GZFhwC/EiG7zvumAX2CmbUb+nb82JfL23 Arg8TvIiJDE9SlRNFJjONxQ6dCMxvVBTsqrRntCwqB3itb5+byYg2LJbXMSdXfHD b+E7werrGDl52XiWRMeIZWhBBVhAg5mO/BFkG8+W/mLfaKiny/7xzL+my4p0lBTd aRI= -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/server.key0000664000175000017500000000156713245550210016474 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCrjZiXX5f6gvpWAW3xbqvvR6YkbB/xmuWADVhxL74IJYeBEgui quoZ7nWMZohbNax5pv/k4BuXGdqNKFBXccH/RLu+T+fo51S/FM8SkbENJJskHIQ2 qJmeHocYGfGDyK79oq9eKbqsrFtWHBwNZMOA0UzFIahuuLLzA3obNeOfDwIDAQAB AoGAIbMdCI9kwXc9SevZ9xVwfP6sKnd7BvEQqEj22LUyNVN5/ObYlknQ1us6+Cuk GZa/nN4rYoCLqvEPN691qNfV7cbiIJcGEMXkBnjaM/ISh6Iv0eGNsX+D7PZOchLK dlVg7wdzRsuOlbGkWAOPpCLL8JazHKp89+RjiPajB1IEQaECQQDaI/ZZVbiDvTBY ZI57XJR7eSrn5WcN+LGhOv8G+3HXNDh7hcTAlvfQkZxXHIcc/SgWnkfKBEaC7P5W T4ImQHqZAkEAyVO+tq/w6rcCK8x0LHjyQ2lmMCKCL/oJ/oWjQCEeZPyII1anZKhk 9Lkbzf432FZn8s2aOS9D5x6TjfJxgkNX5wJAK2CLVChfkJLGUk1sp8s5G3R0u7g6 TeTuLYl1vQWzFYAk2ys2fLWIgcjytb/Ofk0484Z18A35l39Y9ADLeJ/JwQJAZf02 r/WRZlYvk2CPubfLgrryOZBBw2w3g+jPOr2MWDxV+xD629My0Ya0vzX5tG6RWj8t 0apQC9VBirc3KXZUIQJBAJ+y07xmUN5a2wpDu3UzmeZn3HdzJO7fBAPi4h8xnLZQ N5Qu629DQq+X/TzVv2GjBWQHePjezL0NPfch9VzKrMM= -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/all-ca.crt0000664000175000017500000000763113245550210016315 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, L=Derby, O=Mosquitto Project, OU=Testing, CN=Root CA Validity Not Before: Aug 30 22:03:18 2013 GMT Not After : Aug 29 22:03:18 2018 GMT Subject: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:a4:b5:b9:31:d8:b4:d6:de:49:c0:cc:15:3f:b8: 50:8b:be:4a:f4:d3:94:a9:dd:53:2a:e9:df:aa:0d: 3c:08:7b:a7:51:6d:b9:44:98:b7:8d:03:ab:67:9e: e1:c4:23:4d:33:8d:0a:90:9f:c6:de:82:14:4c:f6: 75:5d:a4:e1:a3:ea:fc:9b:79:dd:cb:36:20:87:a3: 9d:eb:e6:5b:0c:53:34:73:cb:dd:a8:e4:0e:7f:f0: 5f:8a:3c:d8:8f:01:ff:66:31:16:41:1b:e3:7a:61: 2c:3d:44:a5:a9:dd:1d:42:e5:5a:a1:df:29:35:dc: 91:5e:9d:82:60:0d:7a:08:db Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB X509v3 Authority Key Identifier: keyid:28:8D:BF:F8:DE:D1:F5:BB:26:37:A4:4D:27:FD:37:91:EC:6B:0C:DD X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 8a:b1:49:b4:53:eb:bb:9d:5e:20:f4:d7:8d:b8:24:a1:28:95: 56:72:03:ed:15:ef:f0:ff:65:b5:6e:34:cf:27:83:7b:57:40: a7:93:61:f0:93:ff:02:b4:74:e0:43:dc:65:0c:e8:a6:20:f9: 8c:88:82:8f:0e:8d:33:4d:ba:bb:28:ff:29:5f:a8:96:60:31: f5:13:15:19:60:a4:00:0e:fc:a7:79:b6:10:95:0b:7b:88:75: 03:ec:7d:94:63:9e:67:2e:2e:9c:fe:79:89:61:93:75:52:f2: 36:48:a6:2d:c0:b2:a7:36:c2:36:50:53:b3:cd:e7:07:1d:e5: 6a:1d -----BEGIN CERTIFICATE----- MIICnTCCAgagAwIBAgIBATANBgkqhkiG9w0BAQUFADByMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEOMAwGA1UEBwwFRGVyYnkxGjAYBgNVBAoMEU1v c3F1aXR0byBQcm9qZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRAwDgYDVQQDDAdSb290 IENBMB4XDTEzMDgzMDIyMDMxOFoXDTE4MDgyOTIyMDMxOFowZTELMAkGA1UEBhMC R0IxEzARBgNVBAgMCkRlcmJ5c2hpcmUxGjAYBgNVBAoMEU1vc3F1aXR0byBQcm9q ZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRMwEQYDVQQDDApTaWduaW5nIENBMIGfMA0G CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCktbkx2LTW3knAzBU/uFCLvkr005Sp3VMq 6d+qDTwIe6dRbblEmLeNA6tnnuHEI00zjQqQn8beghRM9nVdpOGj6vybed3LNiCH o53r5lsMUzRzy92o5A5/8F+KPNiPAf9mMRZBG+N6YSw9RKWp3R1C5Vqh3yk13JFe nYJgDXoI2wIDAQABo1AwTjAdBgNVHQ4EFgQUQENQFNFjfgt8lxQgY+WKlZaf1Ksw HwYDVR0jBBgwFoAUKI2/+N7R9bsmN6RNJ/03kexrDN0wDAYDVR0TBAUwAwEB/zAN BgkqhkiG9w0BAQUFAAOBgQCKsUm0U+u7nV4g9NeNuCShKJVWcgPtFe/w/2W1bjTP J4N7V0Cnk2Hwk/8CtHTgQ9xlDOimIPmMiIKPDo0zTbq7KP8pX6iWYDH1ExUZYKQA DvynebYQlQt7iHUD7H2UY55nLi6c/nmJYZN1UvI2SKYtwLKnNsI2UFOzzecHHeVq HQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICsjCCAhugAwIBAgIJAPTHt3psLAUTMA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV BAYTAkdCMRMwEQYDVQQIDApEZXJieXNoaXJlMQ4wDAYDVQQHDAVEZXJieTEaMBgG A1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNVBAsMB1Rlc3RpbmcxEDAOBgNV BAMMB1Jvb3QgQ0EwHhcNMTMwODMwMjIwMzE2WhcNMjMwODI4MjIwMzE2WjByMQsw CQYDVQQGEwJHQjETMBEGA1UECAwKRGVyYnlzaGlyZTEOMAwGA1UEBwwFRGVyYnkx GjAYBgNVBAoMEU1vc3F1aXR0byBQcm9qZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRAw DgYDVQQDDAdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB3KGu pkiSYbDAaH0ewiCb44CLsAdV5PdYgZHH0jlH8oXkNH0MU3qs7Se2UWrnPQb1VbdI K2DpSTk+3XuWO0BOqQ+/JuRFN/omwrucyKcRNm4MQP1aY2Tm04zsP0Muy4aSyMIk F6jxQzAmIgj8VgkQ/y/knS5tbQ2kkoWKRn1RCQIDAQABo1AwTjAdBgNVHQ4EFgQU KI2/+N7R9bsmN6RNJ/03kexrDN0wHwYDVR0jBBgwFoAUKI2/+N7R9bsmN6RNJ/03 kexrDN0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCn2WxbxDd5ar2U UvttJW4I+/V1h3iAQCXVDAegOGzsYp3cfIdd2oZY++Q9FhzHh8nP18D+CeC9MMu2 H2iLULUV08cGSaDLlpo1eq2oJc5ygLOEt/XK7/aIMRwrlP/CoSrI2GPkeA8rka96 G0WtyGRkzqBKHpt6CnseA2evP5NVcQ== -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/client-revoked.key0000664000175000017500000000156713245550210020101 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDOGbML0YeXBkhEhHdlvKcl/exJFgtzyS96nBQWr83TPpoqGByQ 8RpbbTHV/WwEK4fi/iuoAa0AZFDH7NFP7HZ/TKP0mIK/U68G4yaHPkTja7u4nJ3v ov5ZPr2aMcA8d6lpTDoaqsQ/aEx/4gXqOJjWvpMnJvyso9C0nGWpEOZdtwIDAQAB AoGAWOgPK6b8dbK5FA2Mr+98r0/lUPXYhN8hwyN3Kv41rM3RlR0HnaLUOuJU4DnN EdNxcAMy8+udJJEho8zN0ktwJd3Mi/LHVRAZx5EwuZ1m5kSbM/n4iD5TMpDIoFD4 hkq/sxl6EcPBjwDAoykWiYYMcatAyjlxQzs4/FxP9VsgM3kCQQDnUz0K+3zSgE12 MNx5+mynN6Ugt9wp731sNNirkPrLkp7AG6VF5nX5j4SMqROMOfGSPZ2sKwXnyFUz /Aj4KXWbAkEA5BWm8VB1hI1vklGdkCfEcE6lIrND62mQ1hmoF3oaxL8XwnLgzv2U 9r3jWUJWZE9AFx0VHj457oN5GpbU/xaoFQJAEr02e7ZFtVO5crKgma0EskMauFzM lAUXlvVs+/EBsA4PmCZlLBVwRyguJ6rmr3xeKmedZz4Q+2bKKCzpmRjaswJAEJuT AFc/d1tlGF5g/rIml5biZ1huRaH2LeDIYI0/jbvsWvhKbkgApMbG2yT9bWhn3kb7 1qvpQ/jGxKze7YQU0QJALPCnF5/cvmnvOgsCbtLvD4yobKpeYTOUz8BESqDWzKKA L9WyvcvAGneKR55UzIGNeo3c51WWGovlh66TMrXfmA== -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/test-root-ca.crt0000664000175000017500000000174513245550210017505 0ustar rogerroger-----BEGIN CERTIFICATE----- MIICsjCCAhugAwIBAgIJAPTHt3psLAUTMA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV BAYTAkdCMRMwEQYDVQQIDApEZXJieXNoaXJlMQ4wDAYDVQQHDAVEZXJieTEaMBgG A1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNVBAsMB1Rlc3RpbmcxEDAOBgNV BAMMB1Jvb3QgQ0EwHhcNMTMwODMwMjIwMzE2WhcNMjMwODI4MjIwMzE2WjByMQsw CQYDVQQGEwJHQjETMBEGA1UECAwKRGVyYnlzaGlyZTEOMAwGA1UEBwwFRGVyYnkx GjAYBgNVBAoMEU1vc3F1aXR0byBQcm9qZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRAw DgYDVQQDDAdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB3KGu pkiSYbDAaH0ewiCb44CLsAdV5PdYgZHH0jlH8oXkNH0MU3qs7Se2UWrnPQb1VbdI K2DpSTk+3XuWO0BOqQ+/JuRFN/omwrucyKcRNm4MQP1aY2Tm04zsP0Muy4aSyMIk F6jxQzAmIgj8VgkQ/y/knS5tbQ2kkoWKRn1RCQIDAQABo1AwTjAdBgNVHQ4EFgQU KI2/+N7R9bsmN6RNJ/03kexrDN0wHwYDVR0jBBgwFoAUKI2/+N7R9bsmN6RNJ/03 kexrDN0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCn2WxbxDd5ar2U UvttJW4I+/V1h3iAQCXVDAegOGzsYp3cfIdd2oZY++Q9FhzHh8nP18D+CeC9MMu2 H2iLULUV08cGSaDLlpo1eq2oJc5ygLOEt/XK7/aIMRwrlP/CoSrI2GPkeA8rka96 G0WtyGRkzqBKHpt6CnseA2evP5NVcQ== -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/crl.pem0000664000175000017500000000100413245550210015721 0ustar rogerroger-----BEGIN X509 CRL----- MIIBVTCBvwIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJHQjETMBEGA1UE CAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNV BAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EXDTEzMDgzMDIyMDMzNVoY DzIwOTUxMDE5MjIwMzM1WjAUMBICAQQXDTEzMDgzMDIyMDMzNVqgDjAMMAoGA1Ud FAQDAgEBMA0GCSqGSIb3DQEBBQUAA4GBAHq0ebJDiawBBbMDohyfoFlmtCvJDUuS 79x239ublxRGg8vB9eALiru16YGL2/x3AUYDjr9Xh4cm4BvA5+F6vdebzVcSH/Xe qxa1YZTvmuZko2Fp7kHMs1bn5diFoGCSXD4OqGFJJwtIOHLXXwtcGaAaGSLtWT8M 2+/Fn+oFhax/ -----END X509 CRL----- mosquitto-1.4.15/test/ssl/server.crt0000664000175000017500000000610213245550210016462 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Validity Not Before: Aug 30 22:03:29 2013 GMT Not After : Aug 29 22:03:29 2018 GMT Subject: C=GB, ST=Nottinghamshire, L=Nottingham, O=Server, OU=Production, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:ab:8d:98:97:5f:97:fa:82:fa:56:01:6d:f1:6e: ab:ef:47:a6:24:6c:1f:f1:9a:e5:80:0d:58:71:2f: be:08:25:87:81:12:0b:a2:aa:ea:19:ee:75:8c:66: 88:5b:35:ac:79:a6:ff:e4:e0:1b:97:19:da:8d:28: 50:57:71:c1:ff:44:bb:be:4f:e7:e8:e7:54:bf:14: cf:12:91:b1:0d:24:9b:24:1c:84:36:a8:99:9e:1e: 87:18:19:f1:83:c8:ae:fd:a2:af:5e:29:ba:ac:ac: 5b:56:1c:1c:0d:64:c3:80:d1:4c:c5:21:a8:6e:b8: b2:f3:03:7a:1b:35:e3:9f:0f Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 07:C5:AF:95:28:37:45:F4:2C:F5:BA:6A:60:79:DC:0F:A2:46:99:72 X509v3 Authority Key Identifier: keyid:40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB Signature Algorithm: sha1WithRSAEncryption 90:dd:85:cb:9f:4a:89:78:2b:26:c4:82:b9:34:ea:39:5a:8b: d9:3b:56:5c:78:df:69:ab:4a:f7:c6:10:8a:a3:9a:1a:5d:c5: be:55:a1:36:df:36:d6:ea:3a:ec:be:99:38:9f:34:19:50:c4: 30:6a:18:2a:42:9f:45:a0:d2:57:bf:37:47:b7:2c:b0:1e:f4: 2e:95:1a:9a:90:2d:41:95:00:e8:23:3c:c1:99:ea:39:56:b1: ea:8f:2d:db:e9:2c:ea:c8:5b:e7:90:8e:98:2e:ff:13:aa:73: c2:da:fa:af:ee:aa:86:b6:1d:dc:91:4e:24:df:19:4d:aa:3f: 1b:d7 -----BEGIN CERTIFICATE----- MIICzDCCAjWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTMwODMw MjIwMzI5WhcNMTgwODI5MjIwMzI5WjB2MQswCQYDVQQGEwJHQjEYMBYGA1UECAwP Tm90dGluZ2hhbXNoaXJlMRMwEQYDVQQHDApOb3R0aW5naGFtMQ8wDQYDVQQKDAZT ZXJ2ZXIxEzARBgNVBAsMClByb2R1Y3Rpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAq42Yl1+X+oL6VgFt8W6r70emJGwf 8ZrlgA1YcS++CCWHgRILoqrqGe51jGaIWzWseab/5OAblxnajShQV3HB/0S7vk/n 6OdUvxTPEpGxDSSbJByENqiZnh6HGBnxg8iu/aKvXim6rKxbVhwcDWTDgNFMxSGo briy8wN6GzXjnw8CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYd T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFAfFr5UoN0X0 LPW6amB53A+iRplyMB8GA1UdIwQYMBaAFEBDUBTRY34LfJcUIGPlipWWn9SrMA0G CSqGSIb3DQEBBQUAA4GBAJDdhcufSol4KybEgrk06jlai9k7Vlx432mrSvfGEIqj mhpdxb5VoTbfNtbqOuy+mTifNBlQxDBqGCpCn0Wg0le/N0e3LLAe9C6VGpqQLUGV AOgjPMGZ6jlWseqPLdvpLOrIW+eQjpgu/xOqc8La+q/uqoa2HdyRTiTfGU2qPxvX -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/client.key0000664000175000017500000000156713245550210016444 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCa8L5xV1E4ThreNR08N2Zq1lp3F335ZlUvxbgXBDxZ5o+qrha5 wWShoDvKDO016SqF6bY2ZdauYnHRiRTmOhjBCyjId8gm4vz5UXZuIXBCKE4ygJxe plgmsmxAua+XI8H+S8F/tgXSjvWQNMwKKO0x13Fb3G0v/0NreBrFb0IDHwIDAQAB AoGAH3DpBHD2n1liJGNc2mJXmyiCVRZkTt7QPJB/ydPnN0sNLlKDdBBljlLIrziu TjlRkrkZa7KAvQRnGmEZ55o0eW8bMRkY7vrje+dr3btPet7driZbmkOJDmzPZucV 5IObA5j4sUAd7MOkvLfrK2wtn14PEwEznzZQeZO5NiSp9fECQQDOiCUEjg4/xwG4 OBKcT7G0zZnYlaqgus8JffC7NBp4nUi4Ol42Zkf3I6j83cUU7RwvhmpmX2IWzmjX jGDN8EV5AkEAwA0uz7hy6+Nj+boST35r8oUF/j/wgFzqNZwuGv6zIp2EAkjG+LMZ 6hU7MRR+L1V3FYkYr7uZyAv8mSYyn0bfVwJAagcw4ea/3/QdqOJ4g3DSbVzD55Hm d/+PfHMAXEsCb/tnMtUcOtdFiNXw0mhT3ktgFfHuu8GqDMVIw6fYpsD8GQJAVYTJ RogM7ItqFmbMBof2C50+iPPx5Ub6p/qu8Shfnldj1BySNWaTcJAZtoY4ll1JVNai noY8OT9VMOE4g4JsqwJAdZhegiH2/UGh2+81xQZNh8R0dBuK8SVu+FvMvK7np36Q OEuaW2NZMujP+j/GnNJ2OfzIWIv1LNAP8JhApyCCDg== -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/signingCA/0000775000175000017500000000000013245550210016305 5ustar rogerrogermosquitto-1.4.15/test/ssl/signingCA/index.txt0000664000175000017500000000076113245550210020161 0ustar rogerrogerV 180829220329Z 01 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=localhost V 180829220331Z 02 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=test client V 120821000000Z 03 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=test client expired R 180829220334Z 130830220335Z 04 unknown /C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production/CN=test client revoked V 190525125049Z 05 unknown /CN=test client encrypted mosquitto-1.4.15/test/ssl/signingCA/crlnumber0000664000175000017500000000000313245550210020212 0ustar rogerroger02 mosquitto-1.4.15/test/ssl/signingCA/serial0000664000175000017500000000000313245550210017500 0ustar rogerroger06 mosquitto-1.4.15/test/ssl/signingCA/index.txt.attr0000664000175000017500000000002513245550210021123 0ustar rogerrogerunique_subject = yes mosquitto-1.4.15/test/ssl/test-bad-root-ca.crt0000664000175000017500000000175513245550210020232 0ustar rogerroger-----BEGIN CERTIFICATE----- MIICujCCAiOgAwIBAgIJANMI717jaH+OMA0GCSqGSIb3DQEBBQUAMHYxCzAJBgNV BAYTAkdCMRMwEQYDVQQIDApEZXJieXNoaXJlMQ4wDAYDVQQHDAVEZXJieTEaMBgG A1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNVBAsMB1Rlc3RpbmcxFDASBgNV BAMMC0JhZCBSb290IENBMB4XDTEzMDgzMDIyMDMxN1oXDTIzMDgyODIyMDMxN1ow djELMAkGA1UEBhMCR0IxEzARBgNVBAgMCkRlcmJ5c2hpcmUxDjAMBgNVBAcMBURl cmJ5MRowGAYDVQQKDBFNb3NxdWl0dG8gUHJvamVjdDEQMA4GA1UECwwHVGVzdGlu ZzEUMBIGA1UEAwwLQmFkIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ AoGBANgcLofeUGl23VLK8ZMgoc8/shrVQFRgBAk4/0S6+HHNZg15Nm3ECl9voC4q fZY0g0ZCGvWA9QPim1lR7RjzWk4GCjyyJrGAPaQ96Dr1t6xq9eO3l0QyAgyuV3UX IYhWhuf3q+HtHmZJfof1RSLjNf5JFRCxWoYKGmOP+nDVchCnAgMBAAGjUDBOMB0G A1UdDgQWBBTeznI4RKjkyJl7N+BvRGCBZAIO2jAfBgNVHSMEGDAWgBTeznI4RKjk yJl7N+BvRGCBZAIO2jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAKnY Fco0xDWuqeJsGJzMiHqWVy6NAfZyMt1UJAojry+jDQXgW+zPscpwAd+24xQLPPOR R+Cp666oAr1oksaU93Lo5hUmc+1dkaFQZspZ4H29ItZ701OptgSABNTmj2nvdQEG t8HBAF1tzN8Vxrvy4Mtzs51E6M0oVIV+TegQgXSJ -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/client-encrypted.crt0000664000175000017500000000563413245550210020436 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 5 (0x5) Signature Algorithm: sha256WithRSAEncryption Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Validity Not Before: May 26 12:50:49 2014 GMT Not After : May 25 12:50:49 2019 GMT Subject: CN=test client encrypted Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:b5:a1:d6:a3:c8:4d:a1:e8:6a:4e:cc:ae:c0:42: 2b:4a:37:38:8e:60:2f:0d:b0:c7:30:b9:d7:f2:01: 2a:ce:5c:1e:c1:5e:e5:d8:a3:99:03:55:9f:62:ee: 9a:2f:5a:04:26:5a:88:79:86:cf:0c:fb:d1:7e:4e: 41:91:0f:07:27:14:bc:0e:bd:e1:4a:b8:9d:68:52: 42:91:d7:70:f1:94:64:3c:ad:35:5e:00:41:7d:65: cb:a5:6d:7f:c0:92:e8:bd:8f:06:20:c3:1e:ca:dd: a6:80:1a:53:78:3f:5a:27:6d:62:63:7a:2b:3d:15: 24:3e:1e:ee:6d:ad:ef:32:3d Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 9D:E6:CA:2F:54:0A:F5:E4:D0:A1:44:C7:EE:D4:78:FB:75:23:C2:BF X509v3 Authority Key Identifier: keyid:40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB Signature Algorithm: sha256WithRSAEncryption 1e:6e:24:24:4f:ae:5d:8a:82:8f:ea:77:76:2d:2a:96:b8:f0: b0:f1:16:b7:fc:35:ff:96:98:c6:08:aa:8f:93:2f:6a:5f:09: e7:f2:9b:30:53:01:e1:04:8e:55:4e:fe:8e:2f:d8:14:80:35: d0:29:03:6d:b4:bd:05:c9:fb:71:c5:7f:25:3c:4d:67:d4:7b: 33:f5:a3:ec:cd:2e:dd:4b:a9:60:80:d2:e3:74:37:ee:b7:4c: 22:eb:b2:e2:47:d0:42:9c:e6:74:7d:8a:d4:a9:22:5c:08:20: 2b:97:68:3f:de:3d:6a:37:57:9e:2c:af:84:b3:74:e9:0d:36: 40:e1 -----BEGIN CERTIFICATE----- MIICdjCCAd+gAwIBAgIBBTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTQwNTI2 MTI1MDQ5WhcNMTkwNTI1MTI1MDQ5WjAgMR4wHAYDVQQDDBV0ZXN0IGNsaWVudCBl bmNyeXB0ZWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALWh1qPITaHoak7M rsBCK0o3OI5gLw2wxzC51/IBKs5cHsFe5dijmQNVn2Lumi9aBCZaiHmGzwz70X5O QZEPBycUvA694Uq4nWhSQpHXcPGUZDytNV4AQX1ly6Vtf8CS6L2PBiDDHsrdpoAa U3g/WidtYmN6Kz0VJD4e7m2t7zI9AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZI AYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQW BBSd5sovVAr15NChRMfu1Hj7dSPCvzAfBgNVHSMEGDAWgBRAQ1AU0WN+C3yXFCBj 5YqVlp/UqzANBgkqhkiG9w0BAQsFAAOBgQAebiQkT65dioKP6nd2LSqWuPCw8Ra3 /DX/lpjGCKqPky9qXwnn8pswUwHhBI5VTv6OL9gUgDXQKQNttL0FyftxxX8lPE1n 1Hsz9aPszS7dS6lggNLjdDfut0wi67LiR9BCnOZ0fYrUqSJcCCArl2g/3j1qN1ee LK+Es3TpDTZA4Q== -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/test-ca.srl0000664000175000017500000000002113245550210016516 0ustar rogerrogerCDAE0E564A2891AA mosquitto-1.4.15/test/ssl/rootCA/0000775000175000017500000000000013245550210015632 5ustar rogerrogermosquitto-1.4.15/test/ssl/rootCA/index.txt0000664000175000017500000000030613245550210017501 0ustar rogerrogerV 180829220318Z 01 unknown /C=GB/ST=Derbyshire/O=Mosquitto Project/OU=Testing/CN=Signing CA V 180829220327Z 02 unknown /C=GB/ST=Derbyshire/O=Mosquitto Project/OU=Testing/CN=Alternative Signing CA mosquitto-1.4.15/test/ssl/rootCA/crlnumber0000664000175000017500000000000313245550210017537 0ustar rogerroger01 mosquitto-1.4.15/test/ssl/rootCA/serial0000664000175000017500000000000313245550210017025 0ustar rogerroger03 mosquitto-1.4.15/test/ssl/rootCA/index.txt.attr0000664000175000017500000000002513245550210020450 0ustar rogerrogerunique_subject = yes mosquitto-1.4.15/test/ssl/test-signing-ca.crt0000664000175000017500000000566413245550210020164 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, L=Derby, O=Mosquitto Project, OU=Testing, CN=Root CA Validity Not Before: Aug 30 22:03:18 2013 GMT Not After : Aug 29 22:03:18 2018 GMT Subject: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:a4:b5:b9:31:d8:b4:d6:de:49:c0:cc:15:3f:b8: 50:8b:be:4a:f4:d3:94:a9:dd:53:2a:e9:df:aa:0d: 3c:08:7b:a7:51:6d:b9:44:98:b7:8d:03:ab:67:9e: e1:c4:23:4d:33:8d:0a:90:9f:c6:de:82:14:4c:f6: 75:5d:a4:e1:a3:ea:fc:9b:79:dd:cb:36:20:87:a3: 9d:eb:e6:5b:0c:53:34:73:cb:dd:a8:e4:0e:7f:f0: 5f:8a:3c:d8:8f:01:ff:66:31:16:41:1b:e3:7a:61: 2c:3d:44:a5:a9:dd:1d:42:e5:5a:a1:df:29:35:dc: 91:5e:9d:82:60:0d:7a:08:db Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB X509v3 Authority Key Identifier: keyid:28:8D:BF:F8:DE:D1:F5:BB:26:37:A4:4D:27:FD:37:91:EC:6B:0C:DD X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 8a:b1:49:b4:53:eb:bb:9d:5e:20:f4:d7:8d:b8:24:a1:28:95: 56:72:03:ed:15:ef:f0:ff:65:b5:6e:34:cf:27:83:7b:57:40: a7:93:61:f0:93:ff:02:b4:74:e0:43:dc:65:0c:e8:a6:20:f9: 8c:88:82:8f:0e:8d:33:4d:ba:bb:28:ff:29:5f:a8:96:60:31: f5:13:15:19:60:a4:00:0e:fc:a7:79:b6:10:95:0b:7b:88:75: 03:ec:7d:94:63:9e:67:2e:2e:9c:fe:79:89:61:93:75:52:f2: 36:48:a6:2d:c0:b2:a7:36:c2:36:50:53:b3:cd:e7:07:1d:e5: 6a:1d -----BEGIN CERTIFICATE----- MIICnTCCAgagAwIBAgIBATANBgkqhkiG9w0BAQUFADByMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEOMAwGA1UEBwwFRGVyYnkxGjAYBgNVBAoMEU1v c3F1aXR0byBQcm9qZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRAwDgYDVQQDDAdSb290 IENBMB4XDTEzMDgzMDIyMDMxOFoXDTE4MDgyOTIyMDMxOFowZTELMAkGA1UEBhMC R0IxEzARBgNVBAgMCkRlcmJ5c2hpcmUxGjAYBgNVBAoMEU1vc3F1aXR0byBQcm9q ZWN0MRAwDgYDVQQLDAdUZXN0aW5nMRMwEQYDVQQDDApTaWduaW5nIENBMIGfMA0G CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCktbkx2LTW3knAzBU/uFCLvkr005Sp3VMq 6d+qDTwIe6dRbblEmLeNA6tnnuHEI00zjQqQn8beghRM9nVdpOGj6vybed3LNiCH o53r5lsMUzRzy92o5A5/8F+KPNiPAf9mMRZBG+N6YSw9RKWp3R1C5Vqh3yk13JFe nYJgDXoI2wIDAQABo1AwTjAdBgNVHQ4EFgQUQENQFNFjfgt8lxQgY+WKlZaf1Ksw HwYDVR0jBBgwFoAUKI2/+N7R9bsmN6RNJ/03kexrDN0wDAYDVR0TBAUwAwEB/zAN BgkqhkiG9w0BAQUFAAOBgQCKsUm0U+u7nV4g9NeNuCShKJVWcgPtFe/w/2W1bjTP J4N7V0Cnk2Hwk/8CtHTgQ9xlDOimIPmMiIKPDo0zTbq7KP8pX6iWYDH1ExUZYKQA DvynebYQlQt7iHUD7H2UY55nLi6c/nmJYZN1UvI2SKYtwLKnNsI2UFOzzecHHeVq HQ== -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/server-expired.crt0000664000175000017500000000000013245550210020107 0ustar rogerrogermosquitto-1.4.15/test/ssl/test-signing-ca.key0000664000175000017500000000156713245550210020162 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCktbkx2LTW3knAzBU/uFCLvkr005Sp3VMq6d+qDTwIe6dRbblE mLeNA6tnnuHEI00zjQqQn8beghRM9nVdpOGj6vybed3LNiCHo53r5lsMUzRzy92o 5A5/8F+KPNiPAf9mMRZBG+N6YSw9RKWp3R1C5Vqh3yk13JFenYJgDXoI2wIDAQAB AoGAHx3Jn9Ydy93wtwCXHxOV++B2TqxOEI0kch3+yCR56+xYXrTI5GGpg3VnA0tr wV8d7Zg+n7XfnxeZ+DQzVf6ZNc24mf7J7gM881GA1zmrUOyolpo5sgc9PW4mbyC1 rvMsLyEGP+fP93MDJ0CYhQjxa4eGNsiLTXtHOsg9y4a1cgkCQQDXgy5ajpo4vzvK 2zMPINIk2QdRQ6jIKwnKUtBmoNsCPcwIW1yhJUc6g1C3qGpi0p7edeLlOaAfugbm 5m1M70L3AkEAw6dAg6fWTDNxt6IO6GtdJWoEJbzV7fWvRUuT6Zh/m14OwGMJvOQN vz4U0FFZK2EbUBL+Za5enzJRyj2AUOiMPQJBAMo3pukF4aPZnIstvu01CLnWgs03 xUl9SMR1jGKgEKA7yBUXVQVH61v2F2kdOCXeJ3/p8arQtXTPouZJ1MlZv+UCQA80 XzIcB+5SDSNNJ8VuGoX+0CWyoBlm/2DuN6dun3QOgiz3RVl1i4/yHiH2QGy7lijJ 4RU70MSkX3DNCLzA5a0CQEb3xQSj+YJW7AHAQI8/9vSO5f2yYuyrtMy5aU8k7hKB Sopu/XLwoWt27pl596Gur0adYnBAZMYYueY8oCN5DNU= -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/client-revoked.csr0000664000175000017500000000125413245550210020071 0ustar rogerroger-----BEGIN CERTIFICATE REQUEST----- MIIBwTCCASoCAQAwgYAxCzAJBgNVBAYTAkdCMRgwFgYDVQQIDA9Ob3R0aW5naGFt c2hpcmUxEzARBgNVBAcMCk5vdHRpbmdoYW0xDzANBgNVBAoMBlNlcnZlcjETMBEG A1UECwwKUHJvZHVjdGlvbjEcMBoGA1UEAwwTdGVzdCBjbGllbnQgcmV2b2tlZDCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzhmzC9GHlwZIRIR3ZbynJf3sSRYL c8kvepwUFq/N0z6aKhgckPEaW20x1f1sBCuH4v4rqAGtAGRQx+zRT+x2f0yj9JiC v1OvBuMmhz5E42u7uJyd76L+WT69mjHAPHepaUw6GqrEP2hMf+IF6jiY1r6TJyb8 rKPQtJxlqRDmXbcCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBABqc8X/e5amA7jA3 cBEICNfQmwXl7KHkLN3vkoa6bm+gGkYWRQYKVk2lQ1zoWuuVSSRcHZhFAJEayQFq xLF+lr72707ncc+yUAwnw4/TTmsDizmDcYj3GwjF+u20CSxnbSgLQfpp5xgSNluc 07XSxkm6Zeolt9GyKliqTJ1kojLY -----END CERTIFICATE REQUEST----- mosquitto-1.4.15/test/ssl/openssl.cnf0000664000175000017500000002707013245550210016624 0ustar rogerroger# # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca', 'req' and 'ts'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 # Policies used by the TSA examples. tsa_policy1 = 1.2.3.4.1 tsa_policy2 = 1.2.3.4.5.6 tsa_policy3 = 1.2.3.4.5.7 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_signing ] dir = ./signingCA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. #unique_subject = no # Set to 'no' to allow creation of # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = test-signing-ca.crt # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem # The current CRL private_key = test-signing-ca.key # The private key RANDFILE = $dir/.rand # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext default_days = 1825 # how long to certify for default_crl_days= 30000 # how long before next CRL default_md = default # use public key default MD preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_anything [ CA_inter ] dir = ./interCA certs = $dir/certs crl_dir = $dir/crl database = $dir/index.txt new_certs_dir = $dir/newcerts certificate = test-inter-ca.crt serial = $dir/serial crlnumber = $dir/crlnumber crl = $dir/crl.pem private_key = test-inter-ca.key RANDFILE = $dir/.rand #x509_extensions = v3_ca x509_extensions = usr_cert name_opt = ca_default cert_opt = ca_default default_days = 1825 default_crl_days = 30 default_md = default preserve = no policy = policy_match unique_subject = yes [ CA_root ] dir = ./rootCA certs = $dir/certs crl_dir = $dir/crl database = $dir/index.txt new_certs_dir = $dir/newcerts certificate = test-root-ca.crt serial = $dir/serial crlnumber = $dir/crlnumber crl = $dir/crl.pem private_key = test-root-ca.key RANDFILE = $dir/.rand x509_extensions = v3_ca name_opt = ca_default cert_opt = ca_default default_days = 1825 default_crl_days = 30 default_md = default preserve = no policy = policy_match unique_subject = yes # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional #################################################################### [ req ] default_bits = 2048 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert # Passwords for private keys if not present they will be prompted for # input_password = secret # output_password = secret # This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString (PKIX recommendation before 2004) # utf8only: only UTF8Strings (PKIX recommendation after 2004). # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). # MASK:XXXX a literal mask value. # WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. string_mask = utf8only # req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = GB countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Derbyshire localityName = Locality Name (eg, city) localityName_default = Derby 0.organizationName = Organization Name (eg, company) 0.organizationName_default = Mosquitto Project # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = Testing commonName = Common Name (e.g. server FQDN or YOUR name) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64 # SET-ex3 = SET extension number 3 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 unstructuredName = An optional company name [ usr_cert ] # These extensions are added when 'ca' signs a request. # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName # This is required for TSA certificates. # extendedKeyUsage = critical,timeStamping [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer # This is what PKIX recommends but some broken software chokes on critical # extensions. #basicConstraints = critical,CA:true # So we do this instead. basicConstraints = CA:true # Key usage: this is typical for a CA certificate. However since it will # prevent it being used as an test self-signed certificate it is best # left out by default. # keyUsage = cRLSign, keyCertSign # Some might want this also # nsCertType = sslCA, emailCA # Include email address in subject alt name: another PKIX recommendation # subjectAltName=email:copy # Copy issuer details # issuerAltName=issuer:copy # DER hex encoding of an extension: beware experts only! # obj=DER:02:03 # Where 'obj' is a standard or added object # You can even override a supported extension: # basicConstraints= critical, DER:30:03:01:01:FF [ crl_ext ] # CRL extensions. # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always [ proxy_cert_ext ] # These extensions should be added when creating a proxy certificate # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName # This really needs to be in place for it to be a proxy certificate. proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo #################################################################### [ tsa ] default_tsa = tsa_config1 # the default TSA section [ tsa_config1 ] # These are used by the TSA reply generation only. dir = ./demoCA # TSA root directory serial = $dir/tsaserial # The current serial number (mandatory) crypto_device = builtin # OpenSSL engine to use for signing signer_cert = $dir/tsacert.pem # The TSA signing certificate # (optional) certs = $dir/cacert.pem # Certificate chain to include in reply # (optional) signer_key = $dir/private/tsakey.pem # The TSA private key (optional) default_policy = tsa_policy1 # Policy if request did not specify it # (optional) other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) digests = md5, sha1 # Acceptable message digests (mandatory) accuracy = secs:1, millisecs:500, microsecs:100 # (optional) clock_precision_digits = 0 # number of digits after dot. (optional) ordering = yes # Is ordering defined for timestamps? # (optional, default: no) tsa_name = yes # Must the TSA name be included in the reply? # (optional, default: no) ess_cert_id_chain = no # Must the ESS cert id chain be included? # (optional, default: no) mosquitto-1.4.15/test/ssl/test-fake-root-ca.key0000664000175000017500000000157313245550210020410 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQCih0Uxpn7wdxufnDagJtW/mf4at3n1TKGVNirCIh8hoU+EdIqL arNt9ayWnJc3h8cHvG9F21ic2zbM+I5L9Iavqkpb9hChLm3Ft+HIxKliXnB48Fr5 r1J/rt3jIHHwE02HcPm1TqLKejHpjngZuMjRV/A5CVJ/iAQZy9ABRjEnRQIDAQAB AoGBAJiL7l4Tr8FzifHdZUgcKzOTDfV1kHq0WlT6alecPywJg+EGoaMJmy/yDvOu NiBgyGZybt5aammPN3hbMvQHpwFqswU6H09YjNYGHgA1sqvZhgczLL6l0PM8dwTl LDL72SQL5sxM8podBaKVqbXgbGHugvV4cG3l/YzqIednfk0BAkEA1f9L3Fx9nN6B jUeS9QY80wk7CjAuARHxvlarmTMX08UZgmo4DgwFK0yP5mLiz+X+2xyyClOHOnU+ 8Gcw/pBAeQJBAMJt0o0VOBQW2L8lFnc6mJedTwpohAVJAb957UO4VcR+RmyARd5G gIYQzQp7pXikOBb97X7BSFDW/dnIbbCD4i0CQQC9MAWOHIrEq4XXNCa8zjXp0KhM eonBUm7o+lCckSoIg6DoxiUmbgQH4pj5cgTZDZmBdt4D+RJ9YPgyqtgKxdbpAkEA hOJ6nWJ7SX+z9DBtAmBSGo2xj/OPB+21/CBhQX+jXwDPMSkal6in/vlMqnWHysSy cURsJc4ElvvZ1BdgoNwCoQJAFceaHLS/G6PKZ+ASdjSUthYIPfXXh8eg4K082uUp TLN1/csizBLn5Z74T0gGBDD/w1K9/xZ2cUNO+wLkNT9JJg== -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/readme.txt0000664000175000017500000000015413245550210016441 0ustar rogerrogerThis directory contains certificates and keys required for SSL testing. The CA key has password "password". mosquitto-1.4.15/test/ssl/client-expired.crt0000664000175000017500000000613513245550210020076 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Validity Not Before: Aug 20 00:00:00 2012 GMT Not After : Aug 21 00:00:00 2012 GMT Subject: C=GB, ST=Nottinghamshire, L=Nottingham, O=Server, OU=Production, CN=test client expired Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:9a:f0:be:71:57:51:38:4e:1a:de:35:1d:3c:37: 66:6a:d6:5a:77:17:7d:f9:66:55:2f:c5:b8:17:04: 3c:59:e6:8f:aa:ae:16:b9:c1:64:a1:a0:3b:ca:0c: ed:35:e9:2a:85:e9:b6:36:65:d6:ae:62:71:d1:89: 14:e6:3a:18:c1:0b:28:c8:77:c8:26:e2:fc:f9:51: 76:6e:21:70:42:28:4e:32:80:9c:5e:a6:58:26:b2: 6c:40:b9:af:97:23:c1:fe:4b:c1:7f:b6:05:d2:8e: f5:90:34:cc:0a:28:ed:31:d7:71:5b:dc:6d:2f:ff: 43:6b:78:1a:c5:6f:42:03:1f Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: CC:E1:DD:22:B5:A1:24:98:8F:47:1E:FF:4F:AE:88:7E:E5:40:56:DB X509v3 Authority Key Identifier: keyid:40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB Signature Algorithm: sha1WithRSAEncryption 05:13:6e:9f:27:8b:1e:7b:3c:83:d4:be:d7:d9:3d:95:85:3e: 3f:d2:56:05:01:fa:3c:1f:4d:f5:b1:39:2e:af:cb:fe:39:4d: 3b:11:54:68:3e:c1:a9:e2:8b:6f:40:78:65:f5:d3:ec:04:de: 53:a9:c1:44:64:24:46:69:66:5e:33:41:02:d1:b5:d6:77:de: 8f:cb:cd:46:97:4a:d2:8c:af:b4:7d:fe:72:48:38:40:d9:75: 93:2c:a1:4c:70:e3:7d:cb:92:30:93:96:0e:92:9f:05:21:6e: 39:2d:cb:ec:83:fc:a4:34:ee:d3:ef:89:a7:11:ff:48:fa:1b: 12:e5 -----BEGIN CERTIFICATE----- MIIC1zCCAkCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTIwODIw MDAwMDAwWhcNMTIwODIxMDAwMDAwWjCBgDELMAkGA1UEBhMCR0IxGDAWBgNVBAgM D05vdHRpbmdoYW1zaGlyZTETMBEGA1UEBwwKTm90dGluZ2hhbTEPMA0GA1UECgwG U2VydmVyMRMwEQYDVQQLDApQcm9kdWN0aW9uMRwwGgYDVQQDDBN0ZXN0IGNsaWVu dCBleHBpcmVkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCa8L5xV1E4Thre NR08N2Zq1lp3F335ZlUvxbgXBDxZ5o+qrha5wWShoDvKDO016SqF6bY2ZdauYnHR iRTmOhjBCyjId8gm4vz5UXZuIXBCKE4ygJxeplgmsmxAua+XI8H+S8F/tgXSjvWQ NMwKKO0x13Fb3G0v/0NreBrFb0IDHwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E FgQUzOHdIrWhJJiPRx7/T66IfuVAVtswHwYDVR0jBBgwFoAUQENQFNFjfgt8lxQg Y+WKlZaf1KswDQYJKoZIhvcNAQEFBQADgYEABRNunyeLHns8g9S+19k9lYU+P9JW BQH6PB9N9bE5Lq/L/jlNOxFUaD7BqeKLb0B4ZfXT7ATeU6nBRGQkRmlmXjNBAtG1 1nfej8vNRpdK0oyvtH3+ckg4QNl1kyyhTHDjfcuSMJOWDpKfBSFuOS3L7IP8pDTu 0++JpxH/SPobEuU= -----END CERTIFICATE----- mosquitto-1.4.15/test/ssl/test-root-ca.key0000664000175000017500000000156713245550210017507 0ustar rogerroger-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDB3KGupkiSYbDAaH0ewiCb44CLsAdV5PdYgZHH0jlH8oXkNH0M U3qs7Se2UWrnPQb1VbdIK2DpSTk+3XuWO0BOqQ+/JuRFN/omwrucyKcRNm4MQP1a Y2Tm04zsP0Muy4aSyMIkF6jxQzAmIgj8VgkQ/y/knS5tbQ2kkoWKRn1RCQIDAQAB AoGAJJUM0ZdBVJYos3ZEPhyl6KTaqgFysOu/HS1+I/XwpzoFuBWLj1rlaGJsPwRI JxCmEn+1UWIWLI+LxOgonSXbMWg+G+un/UxgsPGIPeskDuqPXe97tdnd5c1HDwNf Sy6fzzd0PyyFHrUnxCDl5Y6oJ3O9ZJ1vfELIVyXDoXyCKi0CQQD3U1SM7YhgczaO 9EwHJI8DBeab09DZ3gUT/4zeNVeHGjRtYhZuxJWeINsj0gUJtG/yY6+CaHm3TGPj WOToqq0/AkEAyKlD6uIJ0YuBozmSTkBUJpEaQ1xkDszgUPlxS+73IGz+LZjstbML l1irYV5OyWMDdg/JUmnXl+8gOV+1UtFHtwJAfmDGQ3zcwuwcZM/QSZYUvaa2P8ns XmdkkON0R9dZ8l8hiwMkE1XAXhzL3XHjwSHCUkk91ZUtHMyb/f/eeEU+YQJBAJxD 3QVlBFpwNwPDCOHxjNb/9yDwKWexOxs0Nnv42/EfkA44YlbZ2TQCtGw+QkLo3cAq aRDKJkBG06R6mT2mhx8CQEhJ5VEhTuM88SQ9mEUup4XDc9wSPK5VK7HLR0Ip22fU Lh1L/oAsWDIFo3zBQ9aSpiTWzAS/D7gyZPZz17dsJZk= -----END RSA PRIVATE KEY----- mosquitto-1.4.15/test/ssl/demoCA/0000775000175000017500000000000013245550210015573 5ustar rogerrogermosquitto-1.4.15/test/ssl/demoCA/index.txt0000664000175000017500000000022613245550210017443 0ustar rogerrogerR 391118144000Z 120703155846Z CDAE0E564A2891A7 unknown /C=GB/ST=United Kingdom/L=Derby/O=Mosquitto Test Suite/OU=Broker Test/CN=localhost-client-test mosquitto-1.4.15/test/ssl/demoCA/crlnumber0000664000175000017500000000000313245550210017500 0ustar rogerroger05 mosquitto-1.4.15/test/ssl/demoCA/serial0000664000175000017500000000000313245550210016766 0ustar rogerroger01 mosquitto-1.4.15/test/ssl/demoCA/index.txt.attr0000664000175000017500000000002413245550210020410 0ustar rogerrogerunique_subject = no mosquitto-1.4.15/test/ssl/gen.sh0000775000175000017500000001030713245550210015554 0ustar rogerroger# This file generates the keys and certificates used for testing mosquitto. # None of the keys are encrypted, so do not just use this script to generate # files for your own use. rm -f *.crt *.key *.csr for a in root signing; do rm -rf ${a}CA/ mkdir -p ${a}CA/newcerts touch ${a}CA/index.txt echo 01 > ${a}CA/serial echo 01 > ${a}CA/crlnumber done rm -rf certs BASESUBJ="/C=GB/ST=Derbyshire/L=Derby/O=Mosquitto Project/OU=Testing" SBASESUBJ="/C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Production" BBASESUBJ="/C=GB/ST=Nottinghamshire/L=Nottingham/O=Server/OU=Bridge" # The root CA openssl genrsa -out test-root-ca.key 1024 openssl req -new -x509 -days 3650 -key test-root-ca.key -out test-root-ca.crt -config openssl.cnf -subj "${BASESUBJ}/CN=Root CA/" # Another root CA that doesn't sign anything openssl genrsa -out test-bad-root-ca.key 1024 openssl req -new -x509 -days 3650 -key test-bad-root-ca.key -out test-bad-root-ca.crt -config openssl.cnf -subj "${BASESUBJ}/CN=Bad Root CA/" # This is a root CA that has the exact same details as the real root CA, but is a different key and certificate. Effectively a "fake" CA. openssl genrsa -out test-fake-root-ca.key 1024 openssl req -new -x509 -days 3650 -key test-fake-root-ca.key -out test-fake-root-ca.crt -config openssl.cnf -subj "${BASESUBJ}/CN=Root CA/" # An intermediate CA, signed by the root CA, used to sign server/client csrs. openssl genrsa -out test-signing-ca.key 1024 openssl req -out test-signing-ca.csr -key test-signing-ca.key -new -config openssl.cnf -subj "${BASESUBJ}/CN=Signing CA/" openssl ca -config openssl.cnf -name CA_root -extensions v3_ca -out test-signing-ca.crt -infiles test-signing-ca.csr # An alternative intermediate CA, signed by the root CA, not used to sign anything. openssl genrsa -out test-alt-ca.key 1024 openssl req -out test-alt-ca.csr -key test-alt-ca.key -new -config openssl.cnf -subj "${BASESUBJ}/CN=Alternative Signing CA/" openssl ca -config openssl.cnf -name CA_root -extensions v3_ca -out test-alt-ca.crt -infiles test-alt-ca.csr # Valid server key and certificate. openssl genrsa -out server.key 1024 openssl req -new -key server.key -out server.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=localhost/" openssl ca -config openssl.cnf -name CA_signing -out server.crt -infiles server.csr # Expired server certificate, based on the above server key. openssl req -new -days 1 -key server.key -out server-expired.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=localhost/" openssl ca -config openssl.cnf -name CA_signing -days 1 -startdate 120820000000Z -enddate 120821000000Z -out server-expired.crt -infiles server-expired.csr # Valid client key and certificate. openssl genrsa -out client.key 1024 openssl req -new -key client.key -out client.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=test client/" openssl ca -config openssl.cnf -name CA_signing -out client.crt -infiles client.csr # Expired client certificate, based on the above client key. openssl req -new -days 1 -key client.key -out client-expired.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=test client expired/" openssl ca -config openssl.cnf -name CA_signing -days 1 -startdate 120820000000Z -enddate 120821000000Z -out client-expired.crt -infiles client-expired.csr # Revoked client certificate, based on a new client key. openssl genrsa -out client-revoked.key 1024 openssl req -new -days 1 -key client-revoked.key -out client-revoked.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=test client revoked/" openssl ca -config openssl.cnf -name CA_signing -out client-revoked.crt -infiles client-revoked.csr openssl ca -config openssl.cnf -name CA_signing -revoke client-revoked.crt openssl ca -config openssl.cnf -name CA_signing -gencrl -out crl.pem # Valid client key and certificate, encrypted (use "password" as password) openssl genrsa -des3 -out client-encrypted.key 1024 openssl req -new -key client-encrypted.key -out client-encrypted.csr -config openssl.cnf -subj "${SBASESUBJ}/CN=test client encrypted/" openssl ca -config openssl.cnf -name CA_signing -out client-encrypted.crt -infiles client-encrypted.csr cat test-signing-ca.crt test-root-ca.crt > all-ca.crt #mkdir certs #cp test-signing-ca.crt certs/test-signing-ca.pem #cp test-root-ca.crt certs/test-root.ca.pem c_rehash certs mosquitto-1.4.15/test/ssl/server.csr0000664000175000017500000000124013245550210016457 0ustar rogerroger-----BEGIN CERTIFICATE REQUEST----- MIIBtjCCAR8CAQAwdjELMAkGA1UEBhMCR0IxGDAWBgNVBAgMD05vdHRpbmdoYW1z aGlyZTETMBEGA1UEBwwKTm90dGluZ2hhbTEPMA0GA1UECgwGU2VydmVyMRMwEQYD VQQLDApQcm9kdWN0aW9uMRIwEAYDVQQDDAlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcN AQEBBQADgY0AMIGJAoGBAKuNmJdfl/qC+lYBbfFuq+9HpiRsH/Ga5YANWHEvvggl h4ESC6Kq6hnudYxmiFs1rHmm/+TgG5cZ2o0oUFdxwf9Eu75P5+jnVL8UzxKRsQ0k myQchDaomZ4ehxgZ8YPIrv2ir14puqysW1YcHA1kw4DRTMUhqG64svMDehs1458P AgMBAAGgADANBgkqhkiG9w0BAQUFAAOBgQBKfRvwCj6N1SlwGLwJ7NWrasIYE4qP L1+K5l0xnchICmB4r2kGMN7uoYZGf+rbufQXV6R4DrnsNQVLZGB0OIs0qH1dOIr4 dr9+VZwSKkig+EGSkefKCsqaS9IzlosT+tsOc2AAl4xpradpVbt7Ln6GlpNfNP+x ry3A9QBKB3zdMw== -----END CERTIFICATE REQUEST----- mosquitto-1.4.15/test/ssl/client-revoked.crt0000664000175000017500000000613513245550210020075 0ustar rogerrogerCertificate: Data: Version: 3 (0x2) Serial Number: 4 (0x4) Signature Algorithm: sha1WithRSAEncryption Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA Validity Not Before: Aug 30 22:03:34 2013 GMT Not After : Aug 29 22:03:34 2018 GMT Subject: C=GB, ST=Nottinghamshire, L=Nottingham, O=Server, OU=Production, CN=test client revoked Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:ce:19:b3:0b:d1:87:97:06:48:44:84:77:65:bc: a7:25:fd:ec:49:16:0b:73:c9:2f:7a:9c:14:16:af: cd:d3:3e:9a:2a:18:1c:90:f1:1a:5b:6d:31:d5:fd: 6c:04:2b:87:e2:fe:2b:a8:01:ad:00:64:50:c7:ec: d1:4f:ec:76:7f:4c:a3:f4:98:82:bf:53:af:06:e3: 26:87:3e:44:e3:6b:bb:b8:9c:9d:ef:a2:fe:59:3e: bd:9a:31:c0:3c:77:a9:69:4c:3a:1a:aa:c4:3f:68: 4c:7f:e2:05:ea:38:98:d6:be:93:27:26:fc:ac:a3: d0:b4:9c:65:a9:10:e6:5d:b7 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 96:E5:2B:FD:A2:61:F5:32:36:92:3F:CC:BA:28:A7:E2:4C:6C:A5:91 X509v3 Authority Key Identifier: keyid:40:43:50:14:D1:63:7E:0B:7C:97:14:20:63:E5:8A:95:96:9F:D4:AB Signature Algorithm: sha1WithRSAEncryption 22:82:2d:16:57:95:84:10:a5:5b:5b:0f:20:1a:5b:db:59:f5: 5c:d8:42:24:72:42:80:a8:30:77:82:b2:9c:ee:3e:61:3e:af: d0:4d:75:32:ee:cc:04:fc:d6:96:57:46:35:34:d6:7e:42:51: 41:fa:a3:2a:a5:02:3a:50:39:a6:5c:16:a3:8f:dc:2b:45:93: d6:a0:fd:cf:5c:db:fc:5d:ae:f7:5c:e1:2e:36:de:ee:82:38: de:db:76:af:fa:04:f2:a6:bc:14:56:2a:66:b9:9c:dc:88:41: 2d:e7:4e:2c:4d:a9:ae:22:ba:7c:29:65:15:48:85:e4:45:c5: 32:21 -----BEGIN CERTIFICATE----- MIIC1zCCAkCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJHQjET MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTMwODMw MjIwMzM0WhcNMTgwODI5MjIwMzM0WjCBgDELMAkGA1UEBhMCR0IxGDAWBgNVBAgM D05vdHRpbmdoYW1zaGlyZTETMBEGA1UEBwwKTm90dGluZ2hhbTEPMA0GA1UECgwG U2VydmVyMRMwEQYDVQQLDApQcm9kdWN0aW9uMRwwGgYDVQQDDBN0ZXN0IGNsaWVu dCByZXZva2VkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOGbML0YeXBkhE hHdlvKcl/exJFgtzyS96nBQWr83TPpoqGByQ8RpbbTHV/WwEK4fi/iuoAa0AZFDH 7NFP7HZ/TKP0mIK/U68G4yaHPkTja7u4nJ3vov5ZPr2aMcA8d6lpTDoaqsQ/aEx/ 4gXqOJjWvpMnJvyso9C0nGWpEOZdtwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E FgQUluUr/aJh9TI2kj/Muiin4kxspZEwHwYDVR0jBBgwFoAUQENQFNFjfgt8lxQg Y+WKlZaf1KswDQYJKoZIhvcNAQEFBQADgYEAIoItFleVhBClW1sPIBpb21n1XNhC JHJCgKgwd4KynO4+YT6v0E11Mu7MBPzWlldGNTTWfkJRQfqjKqUCOlA5plwWo4/c K0WT1qD9z1zb/F2u91zhLjbe7oI43tt2r/oE8qa8FFYqZrmc3IhBLedOLE2priK6 fCllFUiF5EXFMiE= -----END CERTIFICATE----- mosquitto-1.4.15/test/qos.c0000664000175000017500000001013413245550210014607 0ustar rogerroger#include #include #include #include #include #include #include struct msg_list{ struct msg_list *next; struct mosquitto_message msg; bool sent; }; struct sub{ uint16_t mid; char *topic; int qos; bool complete; }; struct sub subs[3]; struct msg_list *messages_received = NULL; struct msg_list *messages_sent = NULL; int sent_count = 0; int received_count = 0; void on_message(void *obj, const struct mosquitto_message *msg) { struct msg_list *tail, *new_list; received_count++; new_list = malloc(sizeof(struct msg_list)); if(!new_list){ fprintf(stderr, "Error allocating list memory.\n"); return; } new_list->next = NULL; if(!mosquitto_message_copy(&new_list->msg, msg)){ if(messages_received){ tail = messages_received; while(tail->next){ tail = tail->next; } tail->next = new_list; }else{ messages_received = new_list; } }else{ free(new_list); return; } } void on_publish(void *obj, uint16_t mid) { struct msg_list *tail = messages_sent; sent_count++; while(tail){ if(tail->msg.mid == mid){ tail->sent = true; return; } tail = tail->next; } fprintf(stderr, "ERROR: Invalid on_publish() callback for mid %d\n", mid); } void on_subscribe(void *obj, uint16_t mid, int qos_count, const uint8_t *granted_qos) { int i; for(i=0; i<3; i++){ if(subs[i].mid == mid){ if(subs[i].complete){ fprintf(stderr, "WARNING: Duplicate on_subscribe() callback for mid %d\n", mid); } subs[i].complete = true; return; } } fprintf(stderr, "ERROR: Invalid on_subscribe() callback for mid %d\n", mid); } void on_disconnect(void *obj) { printf("Disconnected cleanly.\n"); } void rand_publish(struct mosquitto *mosq, const char *topic, int qos) { int fd = open("/dev/urandom", O_RDONLY); uint8_t buf[100]; uint16_t mid; struct msg_list *new_list, *tail; if(fd >= 0){ if(read(fd, buf, 100) == 100){ if(!mosquitto_publish(mosq, &mid, topic, 100, buf, qos, false)){ new_list = malloc(sizeof(struct msg_list)); if(new_list){ new_list->msg.mid = mid; new_list->msg.topic = strdup(topic); new_list->msg.payloadlen = 100; new_list->msg.payload = malloc(100); memcpy(new_list->msg.payload, buf, 100); new_list->msg.retain = false; new_list->next = NULL; new_list->sent = false; if(messages_sent){ tail = messages_sent; while(tail->next){ tail = tail->next; } tail->next = new_list; }else{ messages_sent = new_list; } } } } close(fd); } } int main(int argc, char *argv[]) { struct mosquitto *mosq; int i; time_t start; mosquitto_lib_init(); mosq = mosquitto_new("qos-test", NULL); mosquitto_log_init(mosq, MOSQ_LOG_ALL, MOSQ_LOG_STDOUT); mosquitto_message_callback_set(mosq, on_message); mosquitto_publish_callback_set(mosq, on_publish); mosquitto_subscribe_callback_set(mosq, on_subscribe); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_connect(mosq, "127.0.0.1", 1883, 60, true); subs[0].topic = "qos-test/0"; subs[0].qos = 0; subs[0].complete = false; subs[1].topic = "qos-test/1"; subs[1].qos = 1; subs[1].complete = false; subs[2].topic = "qos-test/2"; subs[2].qos = 2; subs[2].complete = false; mosquitto_subscribe(mosq, &subs[0].mid, subs[0].topic, subs[0].qos); mosquitto_subscribe(mosq, &subs[1].mid, subs[1].topic, subs[1].qos); mosquitto_subscribe(mosq, &subs[2].mid, subs[2].topic, subs[2].qos); for(i=0; i<1; i++){ rand_publish(mosq, "qos-test/0", 0); rand_publish(mosq, "qos-test/0", 1); rand_publish(mosq, "qos-test/0", 2); rand_publish(mosq, "qos-test/1", 0); rand_publish(mosq, "qos-test/1", 1); rand_publish(mosq, "qos-test/1", 2); rand_publish(mosq, "qos-test/2", 0); rand_publish(mosq, "qos-test/2", 1); rand_publish(mosq, "qos-test/2", 2); } start = time(NULL); while(!mosquitto_loop(mosq, -1)){ if(time(NULL)-start > 20){ mosquitto_disconnect(mosq); } } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); printf("Sent messages: %d\n", sent_count); printf("Received messages: %d\n", received_count); return 0; } mosquitto-1.4.15/test/msgsps_common.h0000664000175000017500000000007213245550210016676 0ustar rogerroger#define MESSAGE_COUNT 100000L #define MESSAGE_SIZE 1024L mosquitto-1.4.15/test/random_client.c0000664000175000017500000001167213245550210016633 0ustar rogerroger/* Copyright (c) 2009, Roger Light All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of mosquitto nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include typedef enum { stStart, stSocketOpened, stConnSent, stConnAckd, stSubSent, stSubAckd, stPause } stateType; static stateType state = stStart; int handle_read(mqtt3_context *context) { uint8_t buf; int rc; rc = read(context->sock, &buf, 1); printf("rc: %d\n", rc); if(rc == -1){ printf("Error: %s\n", strerror(errno)); return 1; }else if(rc == 0){ return 2; } switch(buf&0xF0){ case CONNACK: if(mqtt3_handle_connack(context)) return 3; state = stConnAckd; break; case SUBACK: if(mqtt3_handle_suback(context)) return 3; state = stSubAckd; break; case PINGREQ: if(mqtt3_handle_pingreq(context)) return 3; break; case PINGRESP: if(mqtt3_handle_pingresp(context)) return 3; break; case PUBACK: if(mqtt3_handle_puback(context)) return 3; break; case PUBCOMP: if(mqtt3_handle_pubcomp(context)) return 3; break; case PUBLISH: if(mqtt3_handle_publish(context)) return 0; break; case PUBREC: if(mqtt3_handle_pubrec(context)) return 3; break; case UNSUBACK: if(mqtt3_handle_unsuback(context)) return 3; break; default: printf("Unknown command: %s (%d)\n", mqtt3_command_to_string(buf&0xF0), buf&0xF0); break; } return 0; } void send_random(mqtt3_context *context, int length) { int fd = open("/dev/urandom", O_RDONLY); uint8_t buf[length]; if(fd >= 0){ if(read(fd, buf, length) == length){ mqtt3_write_bytes(context, buf, length); } close(fd); } } /* pselect loop test */ int main(int argc, char *argv[]) { struct timespec timeout; fd_set readfds, writefds; int fdcount; int run = 1; mqtt3_context context; char id[30]; if(argc == 2){ sprintf(id, "test%s", argv[1]); }else{ sprintf(id, "test"); } context.sock = mqtt3_socket_connect("127.0.0.1", 1883); if(context.sock == -1){ return 1; } state = stSocketOpened; while(run){ FD_ZERO(&readfds); FD_SET(context.sock, &readfds); FD_ZERO(&writefds); //FD_SET(0, &writefds); timeout.tv_sec = 1; timeout.tv_nsec = 0; fdcount = pselect(context.sock+1, &readfds, &writefds, NULL, &timeout, NULL); if(fdcount == -1){ fprintf(stderr, "Error in pselect: %s\n", strerror(errno)); run = 0; }else if(fdcount == 0){ switch(state){ case stSocketOpened: mqtt3_raw_connect(&context, id, true, 2, true, "will", "aargh", 60, true); state = stConnSent; break; case stConnSent: printf("Waiting for CONNACK\n"); break; case stConnAckd: // printf("CONNACK received\n"); // mqtt3_raw_subscribe(&context, false, "a/b/c", 0); // state = stSubSent; send_random(&context, 100); break; case stSubSent: printf("Waiting for SUBACK\n"); break; case stSubAckd: printf("SUBACK received\n"); mqtt3_raw_publish(&context, 0, 0, 0, 1, "a/b/c", 5, (uint8_t *)"Roger"); state = stPause; break; case stPause: //mqtt3_raw_disconnect(&context); printf("Pause\n"); break; default: fprintf(stderr, "Error: Unknown state\n"); break; } }else{ printf("fdcount=%d\n", fdcount); if(FD_ISSET(context.sock, &readfds)){ if(handle_read(&context)){ fprintf(stderr, "Socket closed on remote side\n"); mqtt3_socket_close(&context); run = 0; } } } } return 0; } mosquitto-1.4.15/test/lib/0000775000175000017500000000000013245550210014410 5ustar rogerrogermosquitto-1.4.15/test/lib/09-util-topic-tokenise.py0000775000175000017500000000131413245550210021122 0ustar rogerroger#!/usr/bin/env python import inspect import os import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) client.wait() exit(client.returncode) mosquitto-1.4.15/test/lib/03-publish-b2c-qos2.py0000775000175000017500000000600413245550210020201 0ustar rogerroger#!/usr/bin/env python # Test whether a client responds correctly to a PUBLISH with QoS 1. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos2-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK the client should verify that rc==0. # The test will send the client a PUBLISH message with topic # "pub/qos2/receive", payload of "message", QoS=2 and mid=13423. The client # should handle this as per the spec by sending a PUBREC message. # The test will not respond to the first PUBREC message, so the client must # resend the PUBREC message with dup=1. Note that to keep test durations low, a # message retry timeout of less than 10 seconds is required for this test. # On receiving the second PUBREC with dup==1, the test will send the correct # PUBREL message. The client should respond to this with the correct PUBCOMP # message and then exit with return code=0. import inspect import os import socket import sys import time # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 13423 publish_packet = mosq_test.gen_publish("pub/qos2/receive", qos=2, mid=mid, payload="message") pubrec_packet = mosq_test.gen_pubrec(mid) pubrel_packet = mosq_test.gen_pubrel(mid) pubcomp_packet = mosq_test.gen_pubcomp(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) conn.send(publish_packet) if mosq_test.expect_packet(conn, "pubrec", pubrec_packet): # Should be repeated due to timeout if mosq_test.expect_packet(conn, "pubrec", pubrec_packet): conn.send(pubrel_packet) if mosq_test.expect_packet(conn, "pubcomp", pubcomp_packet): rc = 0 conn.close() finally: for i in range(0, 5): if client.returncode != None: break time.sleep(0.1) try: client.terminate() except OSError: pass client.wait() sock.close() if client.returncode != 0: exit(1) exit(rc) mosquitto-1.4.15/test/lib/02-subscribe-qos2.py0000775000175000017500000000437713245550210020062 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct SUBSCRIBE to a topic with QoS 2. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id subscribe-qos2-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a SUBSCRIBE # message to subscribe to topic "qos2/test" with QoS=2. If rc!=0, the client # should exit with an error. # Upon receiving the correct SUBSCRIBE message, the test will reply with a # SUBACK message with the accepted QoS set to 2. On receiving the SUBACK # message, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("subscribe-qos2-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 subscribe_packet = mosq_test.gen_subscribe(mid, "qos2/test", 2) suback_packet = mosq_test.gen_suback(mid, 2) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "subscribe", subscribe_packet): conn.send(suback_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/cpp/0000775000175000017500000000000013245550210015172 5ustar rogerrogermosquitto-1.4.15/test/lib/cpp/01-con-discon-success.cpp0000664000175000017500000000141113245550210021613 0ustar rogerroger//#include //#include //#include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ disconnect(); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("01-con-discon-success"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/01-no-clean-session.cpp0000664000175000017500000000110113245550210021262 0ustar rogerroger#include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id, bool clean_session); }; mosquittopp_test::mosquittopp_test(const char *id, bool clean_session) : mosqpp::mosquittopp(id, clean_session) { } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("01-no-clean-session", false); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/03-publish-c2b-qos2-timeout.cpp0000664000175000017500000000163413245550210022602 0ustar rogerroger#include #include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ publish(NULL, "pub/qos2/test", strlen("message"), "message", 2, false); } } void mosquittopp_test::on_disconnect(int rc) { run = 0; } void mosquittopp_test::on_publish(int mid) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos2-test"); mosq->message_retry_set(3); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/02-unsubscribe.cpp0000664000175000017500000000147613245550210020451 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_unsubscribe(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ unsubscribe(NULL, "unsubscribe/test"); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } void mosquittopp_test::on_unsubscribe(int mid) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("unsubscribe-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/03-publish-b2c-qos1.cpp0000664000175000017500000000251113245550210021110 0ustar rogerroger#include #include #include #include class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_message(const struct mosquitto_message *msg); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); } } void mosquittopp_test::on_message(const struct mosquitto_message *msg) { if(msg->mid != 123){ printf("Invalid mid (%d)\n", msg->mid); exit(1); } if(msg->qos != 1){ printf("Invalid qos (%d)\n", msg->qos); exit(1); } if(strcmp(msg->topic, "pub/qos1/receive")){ printf("Invalid topic (%s)\n", msg->topic); exit(1); } if(strcmp((char *)msg->payload, "message")){ printf("Invalid payload (%s)\n", (char *)msg->payload); exit(1); } if(msg->payloadlen != 7){ printf("Invalid payloadlen (%d)\n", msg->payloadlen); exit(1); } if(msg->retain != false){ printf("Invalid retain (%d)\n", msg->retain); exit(1); } exit(0); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos1-test"); mosq->message_retry_set(3); mosq->connect("localhost", 1888, 60); while(1){ mosq->loop(); } mosqpp::lib_cleanup(); return 1; } mosquitto-1.4.15/test/lib/cpp/03-publish-c2b-qos1-timeout.cpp0000664000175000017500000000163413245550210022601 0ustar rogerroger#include #include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ publish(NULL, "pub/qos1/test", strlen("message"), "message", 1, false); } } void mosquittopp_test::on_disconnect(int rc) { run = 0; } void mosquittopp_test::on_publish(int mid) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos1-test"); mosq->message_retry_set(3); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/04-retain-qos0.cpp0000664000175000017500000000131113245550210020255 0ustar rogerroger#include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ publish(NULL, "retain/qos0/test", strlen("retained message"), "retained message", 0, true); } } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("retain-qos0-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/Makefile0000664000175000017500000000653513245550210016643 0ustar rogerroger.PHONY: all test 01 02 03 04 08 09 clean reallyclean CFLAGS=-I../../../lib -I../../../lib/cpp -DDEBUG -Werror LIBS=../../../lib/libmosquitto.so.1 ../../../lib/cpp/libmosquittopp.so.1 all : 01 02 03 04 08 09 01-con-discon-success.test : 01-con-discon-success.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 01-will-set.test : 01-will-set.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 01-unpwd-set.test : 01-unpwd-set.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 01-will-unpwd-set.test : 01-will-unpwd-set.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 01-no-clean-session.test : 01-no-clean-session.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 01-keepalive-pingreq.test : 01-keepalive-pingreq.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 02-subscribe-qos0.test : 02-subscribe-qos0.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 02-subscribe-qos1.test : 02-subscribe-qos1.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 02-subscribe-qos2.test : 02-subscribe-qos2.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 02-unsubscribe.test : 02-unsubscribe.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-qos0.test : 03-publish-qos0.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-qos0-no-payload.test : 03-publish-qos0-no-payload.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos1-timeout.test : 03-publish-c2b-qos1-timeout.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos1-disconnect.test : 03-publish-c2b-qos1-disconnect.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos2.test : 03-publish-c2b-qos2.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos2-disconnect.test : 03-publish-c2b-qos2-disconnect.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos2-timeout.test : 03-publish-c2b-qos2-timeout.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-b2c-qos1.test : 03-publish-b2c-qos1.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-b2c-qos2.test : 03-publish-b2c-qos2.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 04-retain-qos0.test : 04-retain-qos0.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-connect-no-auth.test : 08-ssl-connect-no-auth.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-connect-cert-auth.test : 08-ssl-connect-cert-auth.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-connect-cert-auth-enc.test : 08-ssl-connect-cert-auth-enc.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-bad-cacert.test : 08-ssl-bad-cacert.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-fake-cacert.test : 08-ssl-fake-cacert.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 09-util-topic-matching.test : 09-util-topic-matching.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 09-util-topic-tokenise.test : 09-util-topic-tokenise.cpp $(CXX) $< -o $@ $(CFLAGS) $(LIBS) 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test 03 : 03-publish-qos0.test 03-publish-qos0-no-payload.test 03-publish-c2b-qos1-timeout.test 03-publish-c2b-qos1-disconnect.test 03-publish-c2b-qos2.test 03-publish-c2b-qos2-timeout.test 03-publish-c2b-qos2-disconnect.test 03-publish-b2c-qos1.test 03-publish-b2c-qos2.test 04 : 04-retain-qos0.test 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test 09 : 09-util-topic-matching.test 09-util-topic-tokenise.test reallyclean : clean -rm -f *.orig clean : rm -f *.test mosquitto-1.4.15/test/lib/cpp/08-ssl-connect-cert-auth-enc.cpp0000664000175000017500000000217313245550210023013 0ustar rogerroger#include #include static int run = -1; static int password_callback(char* buf, int size, int rwflag, void* userdata) { strncpy(buf, "password", size); buf[size-1] = '\0'; return strlen(buf); } class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ disconnect(); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("08-ssl-connect-crt-auth-enc"); mosq->tls_opts_set(1, "tlsv1", NULL); //mosq->tls_set("../ssl/test-ca.crt", NULL, "../ssl/client.crt", "../ssl/client.key"); mosq->tls_set("../ssl/all-ca.crt", NULL, "../ssl/client-encrypted.crt", "../ssl/client-encrypted.key", password_callback); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/02-subscribe-qos2.cpp0000664000175000017500000000160613245550210020763 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_subscribe(int mid, int qos_count, const int *granted_qos); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ subscribe(NULL, "qos2/test", 2); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } void mosquittopp_test::on_subscribe(int mid, int qos_count, const int *granted_qos) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("subscribe-qos2-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/08-ssl-connect-cert-auth.cpp0000664000175000017500000000163613245550210022253 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ disconnect(); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("08-ssl-connect-crt-auth"); mosq->tls_opts_set(1, "tlsv1", NULL); //mosq->tls_set("../ssl/test-ca.crt", NULL, "../ssl/client.crt", "../ssl/client.key"); mosq->tls_set("../ssl/all-ca.crt", NULL, "../ssl/client.crt", "../ssl/client.key"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/02-subscribe-qos1.cpp0000664000175000017500000000160613245550210020762 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_subscribe(int mid, int qos_count, const int *granted_qos); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ subscribe(NULL, "qos1/test", 1); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } void mosquittopp_test::on_subscribe(int mid, int qos_count, const int *granted_qos) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("subscribe-qos1-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/03-publish-c2b-qos2-disconnect.cpp0000664000175000017500000000203413245550210023240 0ustar rogerroger#include #include #include static int run = -1; static int first_connection = 1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ if(first_connection == 1){ publish(NULL, "pub/qos2/test", strlen("message"), "message", 2, false); first_connection = 0; } } } void mosquittopp_test::on_disconnect(int rc) { if(rc){ reconnect(); }else{ run = 0; } } void mosquittopp_test::on_publish(int mid) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos2-test"); mosq->message_retry_set(3); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/03-publish-qos0-no-payload.cpp0000664000175000017500000000152613245550210022511 0ustar rogerroger#include #include static int run = -1; static int sent_mid = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ publish(&sent_mid, "pub/qos0/no-payload/test", 0, NULL, 0, false); } } void mosquittopp_test::on_publish(int mid) { if(sent_mid == mid){ disconnect(); }else{ exit(1); } } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos0-test-np"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/01-keepalive-pingreq.cpp0000664000175000017500000000112213245550210021520 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); } } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("01-keepalive-pingreq"); mosq->connect("localhost", 1888, 4); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/03-publish-c2b-qos1-disconnect.cpp0000664000175000017500000000203413245550210023237 0ustar rogerroger#include #include #include static int run = -1; static int first_connection = 1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ if(first_connection == 1){ publish(NULL, "pub/qos1/test", strlen("message"), "message", 1, false); first_connection = 0; } } } void mosquittopp_test::on_disconnect(int rc) { if(rc){ reconnect(); }else{ run = 0; } } void mosquittopp_test::on_publish(int mid) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos1-test"); mosq->message_retry_set(3); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/01-unpwd-set.cpp0000664000175000017500000000105213245550210020040 0ustar rogerroger#include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("01-unpwd-set"); mosq->username_pw_set("uname", ";'[08gn=#"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/09-util-topic-tokenise.cpp0000664000175000017500000000554513245550210022045 0ustar rogerroger#include #include #include void print_error(const char *topic, char **topics, int topic_count) { int i; printf("TOPIC: %s\n", topic); printf("TOKENS: "); for(i=0; i #include void do_check(const char *sub, const char *topic, bool bad_res) { bool match; mosqpp::topic_matches_sub(sub, topic, &match); if(match == bad_res){ printf("s: %s t: %s\n", sub, topic); exit(1); } } int main(int argc, char *argv[]) { do_check("foo/bar", "foo/bar", false); do_check("foo/+", "foo/bar", false); do_check("foo/+/baz", "foo/bar/baz", false); do_check("foo/+/#", "foo/bar/baz", false); do_check("#", "foo/bar/baz", false); do_check("foo/bar", "foo", true); do_check("foo/+", "foo/bar/baz", true); do_check("foo/+/baz", "foo/bar/bar", true); do_check("foo/+/#", "fo2/bar/baz", true); do_check("#", "/foo/bar", false); do_check("/#", "/foo/bar", false); do_check("/#", "foo/bar", true); do_check("foo//bar", "foo//bar", false); do_check("foo//+", "foo//bar", false); do_check("foo/+/+/baz", "foo///baz", false); do_check("foo/bar/+", "foo/bar/", false); do_check("$SYS/bar", "$SYS/bar", false); do_check("#", "$SYS/bar", true); do_check("$BOB/bar", "$SYS/bar", true); return 0; } mosquitto-1.4.15/test/lib/cpp/03-publish-b2c-qos2.cpp0000664000175000017500000000255313245550210021117 0ustar rogerroger#include #include #include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_message(const struct mosquitto_message *msg); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); } } void mosquittopp_test::on_message(const struct mosquitto_message *msg) { if(msg->mid != 13423){ printf("Invalid mid (%d)\n", msg->mid); exit(1); } if(msg->qos != 2){ printf("Invalid qos (%d)\n", msg->qos); exit(1); } if(strcmp(msg->topic, "pub/qos2/receive")){ printf("Invalid topic (%s)\n", msg->topic); exit(1); } if(strcmp((char *)msg->payload, "message")){ printf("Invalid payload (%s)\n", (char *)msg->payload); exit(1); } if(msg->payloadlen != 7){ printf("Invalid payloadlen (%d)\n", msg->payloadlen); exit(1); } if(msg->retain != false){ printf("Invalid retain (%d)\n", msg->retain); exit(1); } run = 0; } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos2-test"); mosq->message_retry_set(3); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/03-publish-c2b-qos2.cpp0000664000175000017500000000157713245550210021124 0ustar rogerroger#include #include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ publish(NULL, "pub/qos2/test", strlen("message"), "message", 2, false); } } void mosquittopp_test::on_disconnect(int rc) { run = 0; } void mosquittopp_test::on_publish(int mid) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos2-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/08-ssl-fake-cacert.cpp0000664000175000017500000000140713245550210021071 0ustar rogerroger#include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { exit(1); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; int rc; mosqpp::lib_init(); mosq = new mosquittopp_test("08-ssl-fake-cacert"); mosq->tls_opts_set(1, "tlsv1", NULL); mosq->tls_set("../ssl/test-fake-root-ca.crt", NULL, "../ssl/client.crt", "../ssl/client.key"); mosq->connect("localhost", 1888, 60); rc = mosq->loop_forever(); if(rc == MOSQ_ERR_ERRNO && errno == EPROTO){ return 0; }else{ return 1; } } mosquitto-1.4.15/test/lib/cpp/03-publish-qos0.cpp0000664000175000017500000000153513245550210020450 0ustar rogerroger#include #include static int run = -1; static int sent_mid = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_publish(int mid); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ publish(&sent_mid, "pub/qos0/test", strlen("message"), "message", 0, false); } } void mosquittopp_test::on_publish(int mid) { if(sent_mid == mid){ disconnect(); }else{ exit(1); } } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("publish-qos0-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/08-ssl-bad-cacert.cpp0000664000175000017500000000103713245550210020710 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; int rc = 1; mosqpp::lib_init(); mosq = new mosquittopp_test("08-ssl-bad-cacert"); mosq->tls_opts_set(1, "tlsv1", NULL); if(mosq->tls_set("this/file/doesnt/exist") == MOSQ_ERR_INVAL){ rc = 0; } mosqpp::lib_cleanup(); return rc; } mosquitto-1.4.15/test/lib/cpp/01-will-set.cpp0000664000175000017500000000124013245550210017651 0ustar rogerroger//#include //#include //#include #include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("01-will-set"); mosq->will_set("topic/on/unexpected/disconnect", strlen("will message"), "will message", 1, true); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/08-ssl-connect-no-auth.cpp0000664000175000017500000000150213245550210021722 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ disconnect(); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("08-ssl-connect-no-auth"); mosq->tls_opts_set(1, "tlsv1", NULL); //mosq->tls_set("../ssl/test-root-ca.crt"); mosq->tls_set("../ssl/all-ca.crt"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/01-will-unpwd-set.cpp0000664000175000017500000000121213245550210021003 0ustar rogerroger#include #include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("01-will-unpwd-set"); mosq->username_pw_set("oibvvwqw", "#'^2hg9a&nm38*us"); mosq->will_set("will-topic", strlen("will message"), "will message", 2, false); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/cpp/02-subscribe-qos0.cpp0000664000175000017500000000160513245550210020760 0ustar rogerroger#include static int run = -1; class mosquittopp_test : public mosqpp::mosquittopp { public: mosquittopp_test(const char *id); void on_connect(int rc); void on_disconnect(int rc); void on_subscribe(int mid, int qos_count, const int *granted_qos); }; mosquittopp_test::mosquittopp_test(const char *id) : mosqpp::mosquittopp(id) { } void mosquittopp_test::on_connect(int rc) { if(rc){ exit(1); }else{ subscribe(NULL, "qos0/test", 0); } } void mosquittopp_test::on_disconnect(int rc) { run = rc; } void mosquittopp_test::on_subscribe(int mid, int qos_count, const int *granted_qos) { disconnect(); } int main(int argc, char *argv[]) { struct mosquittopp_test *mosq; mosqpp::lib_init(); mosq = new mosquittopp_test("subscribe-qos0-test"); mosq->connect("localhost", 1888, 60); while(run == -1){ mosq->loop(); } mosqpp::lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/08-ssl-connect-cert-auth-enc.py0000775000175000017500000000435713245550210022110 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect and subsequent disconnect when using SSL. # Client must provide a certificate. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id 08-ssl-connect-crt-auth # It should use the CA certificate ssl/test-root-ca.crt for verifying the server. # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. import inspect import os import socket import ssl import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("08-ssl-connect-crt-auth-enc", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", keyfile="../ssl/server.key", certfile="../ssl/server.crt", server_side=True, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED) ssock.settimeout(10) ssock.bind(('', 1888)) ssock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = ssock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() ssock.close() exit(rc) mosquitto-1.4.15/test/lib/08-ssl-bad-cacert.py0000775000175000017500000000146213245550210020001 0ustar rogerroger#!/usr/bin/env python import inspect import os import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) rc = 1 client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) client.wait() rc = client.returncode exit(rc) mosquitto-1.4.15/test/lib/03-publish-qos0-no-payload.py0000775000175000017500000000412713245550210021600 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 0 and no payload. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos0-test-np # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a PUBLISH message # to topic "pub/qos0/no-payload/test" with zero length payload and QoS=0. If # rc!=0, the client should exit with an error. # After sending the PUBLISH message, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos0-test-np", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) publish_packet = mosq_test.gen_publish("pub/qos0/no-payload/test", qos=0) disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/03-publish-c2b-qos2-timeout.py0000775000175000017500000000657713245550210021704 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 1 and responds to a delay. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos2-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK the client should verify that rc==0. If not, it should exit with # return code=1. # On a successful CONNACK, the client should send a PUBLISH message with topic # "pub/qos2/test", payload "message" and QoS=2. # The test will not respond to the first PUBLISH message, so the client must # resend the PUBLISH message with dup=1. Note that to keep test durations low, a # message retry timeout of less than 10 seconds is required for this test. # On receiving the second PUBLISH message, the test will send the correct # PUBREC response. On receiving the correct PUBREC response, the client should # send a PUBREL message. # The test will not respond to the first PUBREL message, so the client must # resend the PUBREL message with dup=1. On receiving the second PUBREL message, # the test will send the correct PUBCOMP response. On receiving the correct # PUBCOMP response, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 publish_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message") publish_dup_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message", dup=True) pubrec_packet = mosq_test.gen_pubrec(mid) pubrel_packet = mosq_test.gen_pubrel(mid) pubcomp_packet = mosq_test.gen_pubcomp(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): # Delay for > 3 seconds (message retry time) if mosq_test.expect_packet(conn, "dup publish", publish_dup_packet): conn.send(pubrec_packet) if mosq_test.expect_packet(conn, "pubrel", pubrel_packet): if mosq_test.expect_packet(conn, "dup pubrel", pubrel_packet): conn.send(pubcomp_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/03-publish-c2b-qos1-timeout.py0000775000175000017500000000544313245550210021672 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 1 and responds to a delay. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos1-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK the client should verify that rc==0. If not, it should exit with # return code=1. # On a successful CONNACK, the client should send a PUBLISH message with topic # "pub/qos1/test", payload "message" and QoS=1. # The test will not respond to the first PUBLISH message, so the client must # resend the PUBLISH message with dup=1. Note that to keep test durations low, a # message retry timeout of less than 10 seconds is required for this test. # On receiving the second PUBLISH message, the test will send the correct # PUBACK response. On receiving the correct PUBACK response, the client should # send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos1-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 publish_packet = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message") publish_packet_dup = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message", dup=True) puback_packet = mosq_test.gen_puback(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): # Delay for > 3 seconds (message retry time) if mosq_test.expect_packet(conn, "dup publish", publish_packet_dup): conn.send(puback_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/03-publish-c2b-qos1-disconnect.py0000775000175000017500000000434113245550210022331 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 1, then responds correctly to a disconnect. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos1-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 publish_packet = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message") publish_packet_dup = mosq_test.gen_publish("pub/qos1/test", qos=1, mid=mid, payload="message", dup=True) puback_packet = mosq_test.gen_puback(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(15) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): # Disconnect client. It should reconnect. conn.close() (conn, address) = sock.accept() conn.settimeout(15) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "retried publish", publish_packet_dup): conn.send(puback_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/08-ssl-connect-no-auth.py0000775000175000017500000000422313245550210021014 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect and subsequent disconnect when using SSL. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id 08-ssl-connect-no-auth # It should use the CA certificate ssl/test-ca.crt for verifying the server. # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. import inspect import os import socket import ssl import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("08-ssl-connect-no-auth", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", keyfile="../ssl/server.key", certfile="../ssl/server.crt", server_side=True, ssl_version=ssl.PROTOCOL_TLSv1) ssock.settimeout(10) ssock.bind(('', 1888)) ssock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = ssock.accept() conn.settimeout(100) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() ssock.close() exit(rc) mosquitto-1.4.15/test/lib/01-con-discon-success.py0000775000175000017500000000344313245550210020711 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect and subsequent disconnect. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id 01-con-discon-success # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("01-con-discon-success", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: #client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/01-will-unpwd-set.py0000775000175000017500000000325513245550210020103 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect with a will, username and password. # The client should connect to port 1888 with keepalive=60, clean session set, # client id 01-will-unpwd-set , will topic set to "will-topic", will payload # set to "will message", will qos=2, will retain not set, username set to # "oibvvwqw" and password set to "#'^2hg9a&nm38*us". import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("01-will-unpwd-set", keepalive=keepalive, username="oibvvwqw", password="#'^2hg9a&nm38*us", will_topic="will-topic", will_qos=2, will_payload="will message") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/Makefile0000664000175000017500000000355113245550210016054 0ustar rogerrogerinclude ../../config.mk .PHONY: all test test-compile test-compile-c test-compile-cpp c cpp .NOTPARALLEL: LD_LIBRARY_PATH=../../lib all : test : c cpp test-compile : test-compile-c test-compile-cpp test-compile-c : $(MAKE) -C c test-compile-cpp : $(MAKE) -C cpp c cpp : test-compile ./01-con-discon-success.py $@/01-con-discon-success.test ./01-will-set.py $@/01-will-set.test ./01-unpwd-set.py $@/01-unpwd-set.test ./01-will-unpwd-set.py $@/01-will-unpwd-set.test ./01-no-clean-session.py $@/01-no-clean-session.test ./01-keepalive-pingreq.py $@/01-keepalive-pingreq.test ./02-subscribe-qos0.py $@/02-subscribe-qos0.test ./02-subscribe-qos1.py $@/02-subscribe-qos1.test ./02-subscribe-qos2.py $@/02-subscribe-qos2.test ./02-unsubscribe.py $@/02-unsubscribe.test ./03-publish-qos0.py $@/03-publish-qos0.test ./03-publish-qos0-no-payload.py $@/03-publish-qos0-no-payload.test ./03-publish-c2b-qos1-timeout.py $@/03-publish-c2b-qos1-timeout.test ./03-publish-c2b-qos1-disconnect.py $@/03-publish-c2b-qos1-disconnect.test ./03-publish-c2b-qos2.py $@/03-publish-c2b-qos2.test ./03-publish-c2b-qos2-timeout.py $@/03-publish-c2b-qos2-timeout.test ./03-publish-c2b-qos2-disconnect.py $@/03-publish-c2b-qos2-disconnect.test ./03-publish-b2c-qos1.py $@/03-publish-b2c-qos1.test ./03-publish-b2c-qos2.py $@/03-publish-b2c-qos2.test ./04-retain-qos0.py $@/04-retain-qos0.test ifeq ($(WITH_TLS),yes) ./08-ssl-connect-no-auth.py $@/08-ssl-connect-no-auth.test ./08-ssl-connect-cert-auth.py $@/08-ssl-connect-cert-auth.test ./08-ssl-connect-cert-auth-enc.py $@/08-ssl-connect-cert-auth-enc.test ./08-ssl-bad-cacert.py $@/08-ssl-bad-cacert.test #./08-ssl-fake-cacert.py $@/08-ssl-fake-cacert.test endif ./09-util-topic-matching.py $@/09-util-topic-matching.test ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test clean : $(MAKE) -C c clean $(MAKE) -C cpp clean mosquitto-1.4.15/test/lib/03-publish-c2b-qos2-disconnect.py0000775000175000017500000000570413245550210022336 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 2 and responds to a disconnect. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 publish_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message") publish_dup_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message", dup=True) pubrec_packet = mosq_test.gen_pubrec(mid) pubrel_packet = mosq_test.gen_pubrel(mid) pubcomp_packet = mosq_test.gen_pubcomp(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): # Disconnect client. It should reconnect. conn.close() (conn, address) = sock.accept() conn.settimeout(15) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "retried publish", publish_dup_packet): conn.send(pubrec_packet) if mosq_test.expect_packet(conn, "pubrel", pubrel_packet): # Disconnect client. It should reconnect. conn.close() (conn, address) = sock.accept() conn.settimeout(15) # Complete connection and message flow. if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "retried pubrel", pubrel_packet): conn.send(pubcomp_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/09-util-topic-matching.py0000775000175000017500000000143413245550210021076 0ustar rogerroger#!/usr/bin/env python import inspect import os import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) client.wait() if client.returncode: (stdo, stde) = client.communicate() print(stdo) exit(client.returncode) mosquitto-1.4.15/test/lib/03-publish-c2b-qos2.py0000775000175000017500000000615113245550210020204 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 2. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos2-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK the client should verify that rc==0. If not, it should exit with # return code=1. # On a successful CONNACK, the client should send a PUBLISH message with topic # "pub/qos2/test", payload "message" and QoS=2. # The test will not respond to the first PUBLISH message, so the client must # resend the PUBLISH message with dup=1. Note that to keep test durations low, a # message retry timeout of less than 10 seconds is required for this test. # On receiving the second PUBLISH message, the test will send the correct # PUBREC response. On receiving the correct PUBREC response, the client should # send a PUBREL message. # The test will not respond to the first PUBREL message, so the client must # resend the PUBREL message with dup=1. On receiving the second PUBREL message, # the test will send the correct PUBCOMP response. On receiving the correct # PUBCOMP response, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos2-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 publish_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message") publish_dup_packet = mosq_test.gen_publish("pub/qos2/test", qos=2, mid=mid, payload="message", dup=True) pubrec_packet = mosq_test.gen_pubrec(mid) pubrel_packet = mosq_test.gen_pubrel(mid) pubcomp_packet = mosq_test.gen_pubcomp(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): conn.send(pubrec_packet) if mosq_test.expect_packet(conn, "pubrel", pubrel_packet): conn.send(pubcomp_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/08-ssl-fake-cacert.py0000775000175000017500000000276413245550210020167 0ustar rogerroger#!/usr/bin/env python import inspect import os import socket import ssl import sys import time # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", keyfile="../ssl/server.key", certfile="../ssl/server.crt", server_side=True, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED) ssock.settimeout(10) ssock.bind(('', 1888)) ssock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = ssock.accept() conn.close() except ssl.SSLError: # Expected error due to ca certs not matching. pass finally: time.sleep(1.0) try: client.terminate() except OSError: pass client.wait() ssock.close() if client.returncode == 0: exit(0) else: exit(1) mosquitto-1.4.15/test/lib/01-will-set.py0000775000175000017500000000313513245550210016745 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect with a will. # Will QoS=1, will retain=1. # The client should connect to port 1888 with keepalive=60, clean session set, # client id 01-will-set will topic set to topic/on/unexpected/disconnect , will # payload set to "will message", will qos set to 1 and will retain set. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("01-will-set", keepalive=keepalive, will_topic="topic/on/unexpected/disconnect", will_qos=1, will_retain=True, will_payload="will message") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/08-ssl-connect-cert-auth.py0000775000175000017500000000435313245550210021341 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect and subsequent disconnect when using SSL. # Client must provide a certificate. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id 08-ssl-connect-crt-auth # It should use the CA certificate ssl/test-root-ca.crt for verifying the server. # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a DISCONNECT # message. If rc!=0, the client should exit with an error. import inspect import os import socket import ssl import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test if sys.version < '2.7': print("WARNING: SSL not supported on Python 2.6") exit(0) rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("08-ssl-connect-crt-auth", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", keyfile="../ssl/server.key", certfile="../ssl/server.crt", server_side=True, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED) ssock.settimeout(10) ssock.bind(('', 1888)) ssock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = ssock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() ssock.close() exit(rc) mosquitto-1.4.15/test/lib/02-subscribe-qos0.py0000775000175000017500000000437713245550210020060 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct SUBSCRIBE to a topic with QoS 0. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id subscribe-qos0-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a SUBSCRIBE # message to subscribe to topic "qos0/test" with QoS=0. If rc!=0, the client # should exit with an error. # Upon receiving the correct SUBSCRIBE message, the test will reply with a # SUBACK message with the accepted QoS set to 0. On receiving the SUBACK # message, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("subscribe-qos0-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 subscribe_packet = mosq_test.gen_subscribe(mid, "qos0/test", 0) suback_packet = mosq_test.gen_suback(mid, 0) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "subscribe", subscribe_packet): conn.send(suback_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/02-unsubscribe.py0000775000175000017500000000327313245550210017535 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct UNSUBSCRIBE packet. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("unsubscribe-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 unsubscribe_packet = mosq_test.gen_unsubscribe(mid, "unsubscribe/test") unsuback_packet = mosq_test.gen_unsuback(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "unsubscribe", unsubscribe_packet): conn.send(unsuback_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/02-subscribe-qos1.py0000775000175000017500000000437713245550210020061 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct SUBSCRIBE to a topic with QoS 1. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id subscribe-qos1-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a SUBSCRIBE # message to subscribe to topic "qos1/test" with QoS=1. If rc!=0, the client # should exit with an error. # Upon receiving the correct SUBSCRIBE message, the test will reply with a # SUBACK message with the accepted QoS set to 1. On receiving the SUBACK # message, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("subscribe-qos1-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 1 subscribe_packet = mosq_test.gen_subscribe(mid, "qos1/test", 1) suback_packet = mosq_test.gen_suback(mid, 1) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "subscribe", subscribe_packet): conn.send(suback_packet) if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/01-keepalive-pingreq.py0000775000175000017500000000356213245550210020621 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a pingreq after the keepalive time # The client should connect to port 1888 with keepalive=4, clean session set, # and client id 01-keepalive-pingreq # The client should send a PINGREQ message after the appropriate amount of time # (4 seconds after no traffic). import inspect import os import socket import sys import time # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 4 connect_packet = mosq_test.gen_connect("01-keepalive-pingreq", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) pingreq_packet = mosq_test.gen_pingreq() pingresp_packet = mosq_test.gen_pingresp() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(keepalive+10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "pingreq", pingreq_packet): time.sleep(1.0) conn.send(pingresp_packet) if mosq_test.expect_packet(conn, "pingreq", pingreq_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/01-unpwd-set.py0000775000175000017500000000271013245550210017131 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect with a username and password. # The client should connect to port 1888 with keepalive=60, clean session set, # client id 01-unpwd-set, username set to uname and password set to ;'[08gn=# import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("01-unpwd-set", keepalive=keepalive, username="uname", password=";'[08gn=#") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/03-publish-b2c-qos1.py0000775000175000017500000000447113245550210020206 0ustar rogerroger#!/usr/bin/env python # Test whether a client responds correctly to a PUBLISH with QoS 1. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos1-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK the client should verify that rc==0. # The test will send the client a PUBLISH message with topic # "pub/qos1/receive", payload of "message", QoS=1 and mid=123. The client # should handle this as per the spec by sending a PUBACK message. # The client should then exit with return code==0. import inspect import os import socket import sys import time # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos1-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) disconnect_packet = mosq_test.gen_disconnect() mid = 123 publish_packet = mosq_test.gen_publish("pub/qos1/receive", qos=1, mid=mid, payload="message") puback_packet = mosq_test.gen_puback(mid) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) conn.send(publish_packet) if mosq_test.expect_packet(conn, "puback", puback_packet): rc = 0 conn.close() finally: for i in range(0, 5): if client.returncode != None: break time.sleep(0.1) try: client.terminate() except OSError: pass client.wait() sock.close() if client.returncode != 0: exit(1) exit(rc) mosquitto-1.4.15/test/lib/03-publish-qos0.py0000775000175000017500000000407513245550210017541 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct PUBLISH to a topic with QoS 0. # The client should connect to port 1888 with keepalive=60, clean session set, # and client id publish-qos0-test # The test will send a CONNACK message to the client with rc=0. Upon receiving # the CONNACK and verifying that rc=0, the client should send a PUBLISH message # to topic "pub/qos0/test" with payload "message" and QoS=0. If rc!=0, the # client should exit with an error. # After sending the PUBLISH message, the client should send a DISCONNECT message. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("publish-qos0-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) publish_packet = mosq_test.gen_publish("pub/qos0/test", qos=0, payload="message") disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): if mosq_test.expect_packet(conn, "disconnect", disconnect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/04-retain-qos0.py0000775000175000017500000000302213245550210017345 0ustar rogerroger#!/usr/bin/env python # Test whether a client sends a correct retained PUBLISH to a topic with QoS 0. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 mid = 16 connect_packet = mosq_test.gen_connect("retain-qos0-test", keepalive=keepalive) connack_packet = mosq_test.gen_connack(rc=0) publish_packet = mosq_test.gen_publish("retain/qos0/test", qos=0, payload="retained message", retain=True) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): conn.send(connack_packet) if mosq_test.expect_packet(conn, "publish", publish_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/01-no-clean-session.py0000775000175000017500000000262513245550210020365 0ustar rogerroger#!/usr/bin/env python # Test whether a client produces a correct connect with clean session not set. # The client should connect to port 1888 with keepalive=60, clean session not # set, and client id 01-no-clean-session. import inspect import os import socket import sys # From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],".."))) if cmd_subfolder not in sys.path: sys.path.insert(0, cmd_subfolder) import mosq_test rc = 1 keepalive = 60 connect_packet = mosq_test.gen_connect("01-no-clean-session", clean_session=False, keepalive=keepalive) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(10) sock.bind(('', 1888)) sock.listen(5) client_args = sys.argv[1:] env = dict(os.environ) env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp' try: pp = env['PYTHONPATH'] except KeyError: pp = '' env['PYTHONPATH'] = '../../lib/python:'+pp client = mosq_test.start_client(filename=sys.argv[1].replace('/', '-'), cmd=client_args, env=env) try: (conn, address) = sock.accept() conn.settimeout(10) if mosq_test.expect_packet(conn, "connect", connect_packet): rc = 0 conn.close() finally: client.terminate() client.wait() sock.close() exit(rc) mosquitto-1.4.15/test/lib/c/0000775000175000017500000000000013245550210014632 5ustar rogerrogermosquitto-1.4.15/test/lib/c/03-publish-qos0.c0000664000175000017500000000157713245550210017556 0ustar rogerroger#include #include #include #include #include static int run = -1; static int sent_mid = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, &sent_mid, "pub/qos0/test", strlen("message"), "message", 0, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { if(mid == sent_mid){ mosquitto_disconnect(mosq); run = 0; }else{ exit(1); } } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos0-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_publish_callback_set(mosq, on_publish); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/08-ssl-bad-cacert.c0000664000175000017500000000071113245550210020006 0ustar rogerroger#include #include #include #include #include int main(int argc, char *argv[]) { int rc = 1; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-ssl-bad-cacert", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); if(mosquitto_tls_set(mosq, "this/file/doesnt/exist", NULL, NULL, NULL, NULL) == MOSQ_ERR_INVAL){ rc = 0; } mosquitto_lib_cleanup(); return rc; } mosquitto-1.4.15/test/lib/c/01-con-discon-success.c0000664000175000017500000000132213245550210020714 0ustar rogerroger#include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_disconnect(mosq); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("01-con-discon-success", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-qos0-no-payload.c0000664000175000017500000000157013245550210021610 0ustar rogerroger#include #include #include #include #include static int run = -1; static int sent_mid = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, &sent_mid, "pub/qos0/no-payload/test", 0, NULL, 0, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { if(mid == sent_mid){ mosquitto_disconnect(mosq); run = 0; }else{ exit(1); } } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos0-test-np", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_publish_callback_set(mosq, on_publish); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/04-retain-qos0.c0000664000175000017500000000125213245550210017361 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, NULL, "retain/qos0/test", strlen("retained message"), "retained message", 0, true); } } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("retain-qos0-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-c2b-qos2-timeout.c0000664000175000017500000000172613245550210021704 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, NULL, "pub/qos2/test", strlen("message"), "message", 2, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { mosquitto_disconnect(mosq); } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = 0; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos2-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); mosquitto_message_retry_set(mosq, 3); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/08-ssl-fake-cacert.c0000664000175000017500000000135613245550210020174 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { exit(1); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-ssl-connect-crt-auth", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); mosquitto_tls_set(mosq, "../ssl/test-fake-root-ca.crt", NULL, "../ssl/client.crt", "../ssl/client.key", NULL); mosquitto_connect_callback_set(mosq, on_connect); rc = mosquitto_connect(mosq, "localhost", 1888, 60); rc = mosquitto_loop_forever(mosq, -1, 1); if(rc == MOSQ_ERR_ERRNO && errno == EPROTO){ return 0; }else{ return 1; } } mosquitto-1.4.15/test/lib/c/03-publish-c2b-qos2-disconnect.c0000664000175000017500000000214413245550210022342 0ustar rogerroger#include #include #include #include #include static int run = -1; static int first_connection = 1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ if(first_connection == 1){ mosquitto_publish(mosq, NULL, "pub/qos2/test", strlen("message"), "message", 2, false); first_connection = 0; } } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { mosquitto_disconnect(mosq); } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ mosquitto_reconnect(mosq); }else{ run = 0; } } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos2-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); mosquitto_message_retry_set(mosq, 3); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-c2b-qos1-timeout.c0000664000175000017500000000172613245550210021703 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, NULL, "pub/qos1/test", strlen("message"), "message", 1, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { mosquitto_disconnect(mosq); } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = 0; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos1-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); mosquitto_message_retry_set(mosq, 3); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-c2b-qos2.c0000664000175000017500000000165713245550210020223 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, NULL, "pub/qos2/test", strlen("message"), "message", 2, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { mosquitto_disconnect(mosq); } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = 0; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos2-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/Makefile0000664000175000017500000000631413245550210016276 0ustar rogerroger.PHONY: all test 01 02 03 04 08 09 clean reallyclean CFLAGS=-I../../../lib -Werror LIBS=../../../lib/libmosquitto.so.1 all : 01 02 03 04 08 09 01-con-discon-success.test : 01-con-discon-success.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 01-will-set.test : 01-will-set.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 01-unpwd-set.test : 01-unpwd-set.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 01-will-unpwd-set.test : 01-will-unpwd-set.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 01-no-clean-session.test : 01-no-clean-session.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 01-keepalive-pingreq.test : 01-keepalive-pingreq.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 02-subscribe-qos0.test : 02-subscribe-qos0.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 02-subscribe-qos1.test : 02-subscribe-qos1.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 02-subscribe-qos2.test : 02-subscribe-qos2.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 02-unsubscribe.test : 02-unsubscribe.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-qos0.test : 03-publish-qos0.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-qos0-no-payload.test : 03-publish-qos0-no-payload.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos1-timeout.test : 03-publish-c2b-qos1-timeout.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos1-disconnect.test : 03-publish-c2b-qos1-disconnect.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos2.test : 03-publish-c2b-qos2.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos2-timeout.test : 03-publish-c2b-qos2-timeout.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-c2b-qos2-disconnect.test : 03-publish-c2b-qos2-disconnect.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-b2c-qos1.test : 03-publish-b2c-qos1.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 03-publish-b2c-qos2.test : 03-publish-b2c-qos2.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 04-retain-qos0.test : 04-retain-qos0.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-connect-no-auth.test : 08-ssl-connect-no-auth.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-connect-cert-auth.test : 08-ssl-connect-cert-auth.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-connect-cert-auth-enc.test : 08-ssl-connect-cert-auth-enc.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-bad-cacert.test : 08-ssl-bad-cacert.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 08-ssl-fake-cacert.test : 08-ssl-fake-cacert.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 09-util-topic-matching.test : 09-util-topic-matching.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 09-util-topic-tokenise.test : 09-util-topic-tokenise.c $(CC) $< -o $@ $(CFLAGS) $(LIBS) 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test 03 : 03-publish-qos0.test 03-publish-qos0-no-payload.test 03-publish-c2b-qos1-timeout.test 03-publish-c2b-qos1-disconnect.test 03-publish-c2b-qos2.test 03-publish-c2b-qos2-timeout.test 03-publish-c2b-qos2-disconnect.test 03-publish-b2c-qos1.test 03-publish-b2c-qos2.test 04 : 04-retain-qos0.test 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-connect-cert-auth-enc.test 08-ssl-bad-cacert.test 08-ssl-fake-cacert.test 09 : 09-util-topic-matching.test 09-util-topic-tokenise.test reallyclean : clean -rm -f *.orig clean : rm -f *.test mosquitto-1.4.15/test/lib/c/01-will-unpwd-set.c0000664000175000017500000000110713245550210020106 0ustar rogerroger#include #include #include #include #include static int run = -1; int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("01-will-unpwd-set", true, NULL); mosquitto_username_pw_set(mosq, "oibvvwqw", "#'^2hg9a&nm38*us"); mosquitto_will_set(mosq, "will-topic", strlen("will message"), "will message", 2, false); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/01-no-clean-session.c0000664000175000017500000000065513245550210020377 0ustar rogerroger#include #include #include #include #include static int run = -1; int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("01-no-clean-session", false, NULL); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/01-will-set.c0000664000175000017500000000102213245550210016747 0ustar rogerroger#include #include #include #include #include static int run = -1; int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("01-will-set", true, NULL); mosquitto_will_set(mosq, "topic/on/unexpected/disconnect", strlen("will message"), "will message", 1, true); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-b2c-qos1.c0000664000175000017500000000240313245550210020210 0ustar rogerroger#include #include #include #include #include void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); } } void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) { if(msg->mid != 123){ printf("Invalid mid (%d)\n", msg->mid); exit(1); } if(msg->qos != 1){ printf("Invalid qos (%d)\n", msg->qos); exit(1); } if(strcmp(msg->topic, "pub/qos1/receive")){ printf("Invalid topic (%s)\n", msg->topic); exit(1); } if(strcmp(msg->payload, "message")){ printf("Invalid payload (%s)\n", (char *)msg->payload); exit(1); } if(msg->payloadlen != 7){ printf("Invalid payloadlen (%d)\n", msg->payloadlen); exit(1); } if(msg->retain != false){ printf("Invalid retain (%d)\n", msg->retain); exit(1); } exit(0); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos1-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_message_callback_set(mosq, on_message); mosquitto_message_retry_set(mosq, 3); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return 1; } mosquitto-1.4.15/test/lib/c/08-ssl-connect-cert-auth-enc.c0000664000175000017500000000214513245550210022112 0ustar rogerroger#include #include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_disconnect(mosq); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } static int password_callback(char* buf, int size, int rwflag, void* userdata) { strncpy(buf, "password", size); buf[size-1] = '\0'; return strlen(buf); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-ssl-connect-crt-auth-enc", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); mosquitto_tls_set(mosq, "../ssl/test-root-ca.crt", "../ssl/certs", "../ssl/client-encrypted.crt", "../ssl/client-encrypted.key", password_callback); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/01-keepalive-pingreq.c0000664000175000017500000000104313245550210020622 0ustar rogerroger#include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); } } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("01-keepalive-pingreq", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); rc = mosquitto_connect(mosq, "localhost", 1888, 4); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/09-util-topic-tokenise.c0000664000175000017500000000560213245550210021137 0ustar rogerroger#include #include #include void print_error(const char *topic, char **topics, int topic_count) { int i; printf("TOPIC: %s\n", topic); printf("TOKENS: "); for(i=0; i #include #include #include #include static int run = -1; int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("01-unpwd-set", true, NULL); mosquitto_username_pw_set(mosq, "uname", ";'[08gn=#"); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/08-ssl-connect-no-auth.c0000664000175000017500000000165513245550210021033 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_disconnect(mosq); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-ssl-connect-no-auth", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); //mosquitto_tls_set(mosq, "../ssl/test-root-ca.crt", NULL, NULL, NULL, NULL); mosquitto_tls_set(mosq, "../ssl/all-ca.crt", NULL, NULL, NULL, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/02-subscribe-qos2.c0000664000175000017500000000164313245550210020064 0ustar rogerroger#include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_subscribe(mosq, NULL, "qos2/test", 2); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { mosquitto_disconnect(mosq); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("subscribe-qos2-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_subscribe_callback_set(mosq, on_subscribe); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/02-subscribe-qos0.c0000664000175000017500000000164313245550210020062 0ustar rogerroger#include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_subscribe(mosq, NULL, "qos0/test", 0); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { mosquitto_disconnect(mosq); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("subscribe-qos0-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_subscribe_callback_set(mosq, on_subscribe); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/08-ssl-connect-cert-auth.c0000664000175000017500000000161513245550210021350 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_disconnect(mosq); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-ssl-connect-crt-auth", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); mosquitto_tls_set(mosq, "../ssl/test-root-ca.crt", "../ssl/certs", "../ssl/client.crt", "../ssl/client.key", NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-c2b-qos1-disconnect.c0000664000175000017500000000214413245550210022341 0ustar rogerroger#include #include #include #include #include static int run = -1; static int first_connection = 1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ if(first_connection == 1){ mosquitto_publish(mosq, NULL, "pub/qos1/test", strlen("message"), "message", 1, false); first_connection = 0; } } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { mosquitto_disconnect(mosq); } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ mosquitto_reconnect(mosq); }else{ run = 0; } } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos1-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); mosquitto_message_retry_set(mosq, 3); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/03-publish-b2c-qos2.c0000664000175000017500000000244513245550210020217 0ustar rogerroger#include #include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); } } void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) { if(msg->mid != 13423){ printf("Invalid mid (%d)\n", msg->mid); exit(1); } if(msg->qos != 2){ printf("Invalid qos (%d)\n", msg->qos); exit(1); } if(strcmp(msg->topic, "pub/qos2/receive")){ printf("Invalid topic (%s)\n", msg->topic); exit(1); } if(strcmp(msg->payload, "message")){ printf("Invalid payload (%s)\n", (char *)msg->payload); exit(1); } if(msg->payloadlen != 7){ printf("Invalid payloadlen (%d)\n", msg->payloadlen); exit(1); } if(msg->retain != false){ printf("Invalid retain (%d)\n", msg->retain); exit(1); } run = 0; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("publish-qos2-test", true, &run); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_message_callback_set(mosq, on_message); mosquitto_message_retry_set(mosq, 5); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, 300, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/09-util-topic-matching.c0000664000175000017500000000274713245550210021117 0ustar rogerroger#include #include #include #define EXPECT_MATCH(A, B) do_check((A), (B), false) #define EXPECT_NOMATCH(A, B) do_check((A), (B), true) void do_check(const char *sub, const char *topic, bool bad_res) { bool match; mosquitto_topic_matches_sub(sub, topic, &match); if(match == bad_res){ printf("s: %s t: %s\n", sub, topic); exit(1); } } int main(int argc, char *argv[]) { EXPECT_MATCH("foo/#", "foo/"); EXPECT_NOMATCH("foo#", "foo"); EXPECT_NOMATCH("fo#o/", "foo"); EXPECT_NOMATCH("foo#", "fooa"); EXPECT_NOMATCH("foo+", "foo"); EXPECT_NOMATCH("foo+", "fooa"); EXPECT_NOMATCH("test/6/#", "test/3"); EXPECT_MATCH("foo/bar", "foo/bar"); EXPECT_MATCH("foo/+", "foo/bar"); EXPECT_MATCH("foo/+/baz", "foo/bar/baz"); EXPECT_MATCH("A/B/+/#", "A/B/B/C"); EXPECT_MATCH("foo/+/#", "foo/bar/baz"); EXPECT_MATCH("foo/+/#", "foo/bar"); EXPECT_MATCH("#", "foo/bar/baz"); EXPECT_MATCH("#", "foo/bar/baz"); EXPECT_NOMATCH("foo/bar", "foo"); EXPECT_NOMATCH("foo/+", "foo/bar/baz"); EXPECT_NOMATCH("foo/+/baz", "foo/bar/bar"); EXPECT_NOMATCH("foo/+/#", "fo2/bar/baz"); EXPECT_MATCH("#", "/foo/bar"); EXPECT_MATCH("/#", "/foo/bar"); EXPECT_NOMATCH("/#", "foo/bar"); EXPECT_MATCH("foo//bar", "foo//bar"); EXPECT_MATCH("foo//+", "foo//bar"); EXPECT_MATCH("foo/+/+/baz", "foo///baz"); EXPECT_MATCH("foo/bar/+", "foo/bar/"); EXPECT_MATCH("$SYS/bar", "$SYS/bar"); EXPECT_NOMATCH("#", "$SYS/bar"); EXPECT_NOMATCH("$BOB/bar", "$SYS/bar"); return 0; } mosquitto-1.4.15/test/lib/c/02-subscribe-qos1.c0000664000175000017500000000164313245550210020063 0ustar rogerroger#include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_subscribe(mosq, NULL, "qos1/test", 1); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { mosquitto_disconnect(mosq); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("subscribe-qos1-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_subscribe_callback_set(mosq, on_subscribe); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/lib/c/02-unsubscribe.c0000664000175000017500000000160513245550210017543 0ustar rogerroger#include #include #include #include static int run = -1; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_unsubscribe(mosq, NULL, "unsubscribe/test"); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } void on_unsubscribe(struct mosquitto *mosq, void *obj, int mid) { mosquitto_disconnect(mosq); } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("unsubscribe-test", true, NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_unsubscribe_callback_set(mosq, on_unsubscribe); rc = mosquitto_connect(mosq, "localhost", 1888, 60); while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/msgsps_pub.c0000664000175000017500000000552413245550210016176 0ustar rogerroger/* This provides a crude manner of testing the performance of a broker in messages/s. */ #include #include #include #include #include #include #include static bool run = true; static int message_count = 0; static struct timeval start, stop; void my_connect_callback(struct mosquitto *mosq, void *obj, int rc) { printf("rc: %d\n", rc); gettimeofday(&start, NULL); } void my_disconnect_callback(struct mosquitto *mosq, void *obj, int result) { run = false; } void my_publish_callback(struct mosquitto *mosq, void *obj, int mid) { message_count++; //printf("%d ", message_count); if(message_count == MESSAGE_COUNT){ gettimeofday(&stop, NULL); mosquitto_disconnect((struct mosquitto *)obj); } } int create_data(void) { int i; FILE *fptr, *rnd; int rc = 0; char buf[MESSAGE_SIZE]; fptr = fopen("msgsps_pub.dat", "rb"); if(fptr){ fseek(fptr, 0, SEEK_END); if(ftell(fptr) >= MESSAGE_SIZE*MESSAGE_COUNT){ fclose(fptr); return 0; } fclose(fptr); } fptr = fopen("msgsps_pub.dat", "wb"); if(!fptr) return 1; rnd = fopen("/dev/urandom", "rb"); if(!rnd){ fclose(fptr); return 1; } for(i=0; i #include #include #include #include #include static int run = -1; static int sent_mid; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, &sent_mid, "psk/test", strlen("message"), "message", 0, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { if(mid == sent_mid){ mosquitto_disconnect(mosq); run = 0; }else{ exit(1); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-tls-psk-pub", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); rc = mosquitto_tls_psk_set(mosq, "deadbeef", "psk-id", NULL); if(rc){ mosquitto_destroy(mosq); return rc; } mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); rc = mosquitto_connect(mosq, "localhost", 1888, 60); if(rc){ mosquitto_destroy(mosq); return rc; } while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/broker/c/08-tls-psk-bridge.c0000664000175000017500000000234413245550210020573 0ustar rogerroger#include #include #include #include #include #include static int run = -1; static int sent_mid; void on_log(struct mosquitto *mosq, void *obj, int level, const char *str) { printf("%s\n", str); } void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ exit(1); }else{ mosquitto_publish(mosq, &sent_mid, "psk/test", strlen("message"), "message", 1, false); } } void on_publish(struct mosquitto *mosq, void *obj, int mid) { if(mid == sent_mid){ mosquitto_disconnect(mosq); run = 0; }else{ exit(1); } } void on_disconnect(struct mosquitto *mosq, void *obj, int rc) { run = rc; } int main(int argc, char *argv[]) { int rc; struct mosquitto *mosq; mosquitto_lib_init(); mosq = mosquitto_new("08-tls-psk-bridge", true, NULL); mosquitto_tls_opts_set(mosq, 1, "tlsv1", NULL); mosquitto_connect_callback_set(mosq, on_connect); mosquitto_disconnect_callback_set(mosq, on_disconnect); mosquitto_publish_callback_set(mosq, on_publish); mosquitto_log_callback_set(mosq, on_log); rc = mosquitto_connect(mosq, "localhost", 1890, 60); if(rc) return rc; while(run == -1){ mosquitto_loop(mosq, -1, 1); } mosquitto_lib_cleanup(); return run; } mosquitto-1.4.15/test/broker/c/Makefile0000664000175000017500000000076613245550210017021 0ustar rogerroger.PHONY: all test clean reallyclean 08 CFLAGS=-I../../../lib -I../../../src -Wall -Werror all : auth_plugin.so 08 08 : 08-tls-psk-pub.test 08-tls-psk-bridge.test auth_plugin.so : auth_plugin.c $(CC) ${CFLAGS} -fPIC -shared $^ -o $@ 08-tls-psk-pub.test : 08-tls-psk-pub.c $(CC) ${CFLAGS} $^ -o $@ ../../../lib/libmosquitto.so.1 08-tls-psk-bridge.test : 08-tls-psk-bridge.c $(CC) ${CFLAGS} $^ -o $@ ../../../lib/libmosquitto.so.1 reallyclean : clean -rm -f *.orig clean : rm -f *.so *.test mosquitto-1.4.15/test/broker/c/auth_plugin.c0000664000175000017500000000270513245550210020037 0ustar rogerroger#include #include #include #include int mosquitto_auth_plugin_version(void) { return MOSQ_AUTH_PLUGIN_VERSION; } int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count) { return MOSQ_ERR_SUCCESS; } int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count) { return MOSQ_ERR_SUCCESS; } int mosquitto_auth_security_init(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload) { return MOSQ_ERR_SUCCESS; } int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload) { return MOSQ_ERR_SUCCESS; } int mosquitto_auth_acl_check(void *user_data, const char *clientid, const char *username, const char *topic, int access) { if(!strcmp(username, "readonly") && access == MOSQ_ACL_READ){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_ACL_DENIED; } } int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char *password) { if(!strcmp(username, "test-username") && password && !strcmp(password, "cnwTICONIURW")){ return MOSQ_ERR_SUCCESS; }else if(!strcmp(username, "readonly")){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_AUTH; } } int mosquitto_auth_psk_key_get(void *user_data, const char *hint, const char *identity, char *key, int max_key_len) { return MOSQ_ERR_AUTH; } mosquitto-1.4.15/test/broker/03-publish-c2b-disconnect-qos2.conf0000664000175000017500000000003413245550210023335 0ustar rogerrogerretry_interval 10 port 1888 mosquitto-1.4.15/test/fake_user.c0000664000175000017500000000640613245550210015760 0ustar rogerroger/* Copyright (c) 2009,2010, Roger Light All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of mosquitto nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #ifndef WIN32 #include #else #include #define snprintf sprintf_s #endif #include void my_connect_callback(struct mosquitto *mosq, void *obj, int result) { char topic[100]; if(!result){ snprintf(topic, 100, "fake/%d", getpid()%100); mosquitto_subscribe(mosq, NULL, topic, rand()%3); } } int main(int argc, char *argv[]) { char id[30]; char *host = "localhost"; int port = 1883; int keepalive = 60; bool clean_session = false; struct mosquitto *mosq = NULL; void *will_payload = NULL; long will_payloadlen = 0; int will_qos = 0; bool will_retain = false; char will_topic[100], topic[100]; int pid; pid = getpid(); srand(pid); snprintf(id, 30, "fake_user_%d", pid); mosquitto_lib_init(); mosq = mosquitto_new(id, clean_session, NULL); if(!mosq){ fprintf(stderr, "Error: Out of memory.\n"); return 1; } if(rand()%5 == 0){ snprintf(will_topic, 100, "fake/wills/%d", rand()%100); if(mosquitto_will_set(mosq, will_topic, will_payloadlen, will_payload, will_qos, will_retain)){ fprintf(stderr, "Error: Problem setting will.\n"); return 1; } } mosquitto_connect_callback_set(mosq, my_connect_callback); while(1){ clean_session = rand()%10==0?false:true; if(mosquitto_connect(mosq, host, port, keepalive)){ fprintf(stderr, "Unable to connect.\n"); return 1; } mosquitto_subscribe(mosq, NULL, "#", 0); while(!mosquitto_loop(mosq, -1, 5)){ if(rand()%100==0){ snprintf(topic, 100, "fake/%d", rand()%100); mosquitto_publish(mosq, NULL, topic, 10, "0123456789", rand()%3, rand()%2); } if(rand()%50==0){ mosquitto_disconnect(mosq); } } sleep(10); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; }