mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
				synced 2025-11-04 04:37:46 +00:00 
			
		
		
		
	Compare commits
	
		
			1263 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					df65c4b02a | ||
| 
						 | 
					59e615d149 | ||
| 
						 | 
					3eb45c219c | ||
| 
						 | 
					7d8e15bf66 | ||
| 
						 | 
					3f60c5abc6 | ||
| 
						 | 
					d85fb32af9 | ||
| 
						 | 
					030991f13c | ||
| 
						 | 
					142541180f | ||
| 
						 | 
					9bd48bf029 | ||
| 
						 | 
					8581048528 | ||
| 
						 | 
					6cfb0ae975 | ||
| 
						 | 
					45561de44b | ||
| 
						 | 
					2fccfd756e | ||
| 
						 | 
					df42837a76 | ||
| 
						 | 
					4bc1ac1aef | ||
| 
						 | 
					77ee9d48d0 | ||
| 
						 | 
					7154cca4b9 | ||
| 
						 | 
					77732bdb95 | ||
| 
						 | 
					7a8a05d77d | ||
| 
						 | 
					aa2c28355b | ||
| 
						 | 
					b6cb5d003b | ||
| 
						 | 
					c93acdf54a | ||
| 
						 | 
					0c5e0d649e | ||
| 
						 | 
					1757440cfe | ||
| 
						 | 
					c3ccfe455e | ||
| 
						 | 
					66ec7745bb | ||
| 
						 | 
					531c51dd64 | ||
| 
						 | 
					227ec2dc96 | ||
| 
						 | 
					50c5c76484 | ||
| 
						 | 
					7a567e400b | ||
| 
						 | 
					148eabdbc2 | ||
| 
						 | 
					94ae20ce65 | ||
| 
						 | 
					fd80f02f0b | ||
| 
						 | 
					943cdd5010 | ||
| 
						 | 
					36a5f4a5da | ||
| 
						 | 
					e0e8cc1295 | ||
| 
						 | 
					d7bad290e9 | ||
| 
						 | 
					06766d2ed9 | ||
| 
						 | 
					913a3e4ce1 | ||
| 
						 | 
					4e713e4471 | ||
| 
						 | 
					cb10ea6a7f | ||
| 
						 | 
					f5095b9f79 | ||
| 
						 | 
					8a69089513 | ||
| 
						 | 
					ba6c657587 | ||
| 
						 | 
					177deb8cd2 | ||
| 
						 | 
					1dfc478d0e | ||
| 
						 | 
					f077fb7fad | ||
| 
						 | 
					0dc1be1f41 | ||
| 
						 | 
					e1a0864b68 | ||
| 
						 | 
					222c796eee | ||
| 
						 | 
					15fe0df04a | ||
| 
						 | 
					ad1a3c694c | ||
| 
						 | 
					04be75f037 | ||
| 
						 | 
					8cd26ce8cb | ||
| 
						 | 
					525f53aaa9 | ||
| 
						 | 
					ab95733067 | ||
| 
						 | 
					35f4e26ca4 | ||
| 
						 | 
					14f63cb324 | ||
| 
						 | 
					0962c8383a | ||
| 
						 | 
					891965a321 | ||
| 
						 | 
					4d2adc3c3a | ||
| 
						 | 
					24eb4079d7 | ||
| 
						 | 
					53010fca84 | ||
| 
						 | 
					6f3079ab0a | ||
| 
						 | 
					c73a7c6c09 | ||
| 
						 | 
					bb60fef3d6 | ||
| 
						 | 
					b52766d23a | ||
| 
						 | 
					6f9a9471c3 | ||
| 
						 | 
					992c169ac7 | ||
| 
						 | 
					ba8a932b36 | ||
| 
						 | 
					13dc97d35b | ||
| 
						 | 
					0ef01e5547 | ||
| 
						 | 
					138b236832 | ||
| 
						 | 
					a0d4606c22 | ||
| 
						 | 
					a5200e46b7 | ||
| 
						 | 
					2d3866a987 | ||
| 
						 | 
					0251b40287 | ||
| 
						 | 
					1e2f215902 | ||
| 
						 | 
					8184027534 | ||
| 
						 | 
					a43841b867 | ||
| 
						 | 
					c391ea2f04 | ||
| 
						 | 
					111faaa80d | ||
| 
						 | 
					687cbcd0a4 | ||
| 
						 | 
					c48665d4c5 | ||
| 
						 | 
					c873681adc | ||
| 
						 | 
					cb64f8a809 | ||
| 
						 | 
					0d8be1fd46 | ||
| 
						 | 
					e496f71e7d | ||
| 
						 | 
					de7c8b687a | ||
| 
						 | 
					61e346e0bf | ||
| 
						 | 
					67bf9ca8c6 | ||
| 
						 | 
					14b7fc8a0e | ||
| 
						 | 
					546d6f9ee0 | ||
| 
						 | 
					fe74fdecf9 | ||
| 
						 | 
					c53a67edd5 | ||
| 
						 | 
					5207f1e1a0 | ||
| 
						 | 
					53aa2f05d2 | ||
| 
						 | 
					2405b9fe95 | ||
| 
						 | 
					bc14bf28bf | ||
| 
						 | 
					878e705db5 | ||
| 
						 | 
					be62022344 | ||
| 
						 | 
					432434a377 | ||
| 
						 | 
					60860ad9de | ||
| 
						 | 
					29d6f2dda1 | ||
| 
						 | 
					330b4176f2 | ||
| 
						 | 
					75b76bb380 | ||
| 
						 | 
					c48d129f4a | ||
| 
						 | 
					673f506ff0 | ||
| 
						 | 
					ac078ec1b8 | ||
| 
						 | 
					2007998ae1 | ||
| 
						 | 
					8050228b40 | ||
| 
						 | 
					a73ea9b260 | ||
| 
						 | 
					334728ca4e | ||
| 
						 | 
					33e010bf78 | ||
| 
						 | 
					657c96f8cd | ||
| 
						 | 
					5cd421a4b9 | ||
| 
						 | 
					b5a0c96927 | ||
| 
						 | 
					e5a22a1af2 | ||
| 
						 | 
					4f1fa18cf6 | ||
| 
						 | 
					bc04d0b774 | ||
| 
						 | 
					598a15100d | ||
| 
						 | 
					3227883074 | ||
| 
						 | 
					4a4c771e52 | ||
| 
						 | 
					2f45a6955d | ||
| 
						 | 
					78015d2ecf | ||
| 
						 | 
					9235495e2c | ||
| 
						 | 
					84e4a201e7 | ||
| 
						 | 
					89522132d0 | ||
| 
						 | 
					780cf3e18f | ||
| 
						 | 
					6ba3c6d713 | ||
| 
						 | 
					eae89452ff | ||
| 
						 | 
					33884c8b81 | ||
| 
						 | 
					1b33470d69 | ||
| 
						 | 
					625ace2d50 | ||
| 
						 | 
					09b50cde9b | ||
| 
						 | 
					1c6022c227 | ||
| 
						 | 
					960640cc05 | ||
| 
						 | 
					ebc4fd6f4c | ||
| 
						 | 
					2542635aa8 | ||
| 
						 | 
					8150daa6d5 | ||
| 
						 | 
					06af6eb5a1 | ||
| 
						 | 
					fcc765c981 | ||
| 
						 | 
					98db7f19d1 | ||
| 
						 | 
					904d034d5f | ||
| 
						 | 
					52fa1ac922 | ||
| 
						 | 
					7790cde143 | ||
| 
						 | 
					1d294c86a2 | ||
| 
						 | 
					45ba1d94ba | ||
| 
						 | 
					bdcb1aebce | ||
| 
						 | 
					cb276b3246 | ||
| 
						 | 
					eeac5844f6 | ||
| 
						 | 
					396462c5a2 | ||
| 
						 | 
					b83b15d2a3 | ||
| 
						 | 
					1a6fb2a277 | ||
| 
						 | 
					c2012bcc00 | ||
| 
						 | 
					15f938fc07 | ||
| 
						 | 
					8718bb882d | ||
| 
						 | 
					bc38160b71 | ||
| 
						 | 
					99c037b1ed | ||
| 
						 | 
					c66ab909d4 | ||
| 
						 | 
					cf811a5767 | ||
| 
						 | 
					d7b5d7fda3 | ||
| 
						 | 
					797165f10d | ||
| 
						 | 
					32f094562a | ||
| 
						 | 
					bc8f714362 | ||
| 
						 | 
					ec0f2ae59e | ||
| 
						 | 
					8f34181ae5 | ||
| 
						 | 
					92f14f517a | ||
| 
						 | 
					caf1ec9381 | ||
| 
						 | 
					6b49c684c5 | ||
| 
						 | 
					5425366f0c | ||
| 
						 | 
					6ea604c64f | ||
| 
						 | 
					816885273d | ||
| 
						 | 
					da6a49cda6 | ||
| 
						 | 
					0b02e0d8fd | ||
| 
						 | 
					f03a5ca216 | ||
| 
						 | 
					cc1aac5520 | ||
| 
						 | 
					fb265ff767 | ||
| 
						 | 
					746458d6ac | ||
| 
						 | 
					63d2bcde53 | ||
| 
						 | 
					68827af75b | ||
| 
						 | 
					ba525dfc19 | ||
| 
						 | 
					174c0fa430 | ||
| 
						 | 
					e50392d837 | ||
| 
						 | 
					d28d70e5b9 | ||
| 
						 | 
					240950787c | ||
| 
						 | 
					e6da06e22c | ||
| 
						 | 
					7edbdb719c | ||
| 
						 | 
					992616c01b | ||
| 
						 | 
					a17529d0c4 | ||
| 
						 | 
					c1d4082401 | ||
| 
						 | 
					fabea09f3d | ||
| 
						 | 
					bb577a3fc1 | ||
| 
						 | 
					1d5007ab6a | ||
| 
						 | 
					624f995966 | ||
| 
						 | 
					e78ed60974 | ||
| 
						 | 
					df769135b6 | ||
| 
						 | 
					8a77ba8c76 | ||
| 
						 | 
					d0931d95d5 | ||
| 
						 | 
					a4c6d26a6c | ||
| 
						 | 
					6b0594a393 | ||
| 
						 | 
					9844b8a6b8 | ||
| 
						 | 
					3d1887c5a8 | ||
| 
						 | 
					ed845b6a0d | ||
| 
						 | 
					7d58000caa | ||
| 
						 | 
					0f3c847c60 | ||
| 
						 | 
					d5bc014618 | ||
| 
						 | 
					104da1278b | ||
| 
						 | 
					6933602706 | ||
| 
						 | 
					b7df12e7b0 | ||
| 
						 | 
					029bc8e3df | ||
| 
						 | 
					ed66a2cc2b | ||
| 
						 | 
					25383df599 | ||
| 
						 | 
					25fb62403d | ||
| 
						 | 
					c928c1492b | ||
| 
						 | 
					958b07b0df | ||
| 
						 | 
					642c2bb914 | ||
| 
						 | 
					0486907e33 | ||
| 
						 | 
					6b92d0619c | ||
| 
						 | 
					7093999c19 | ||
| 
						 | 
					ef2e4069d0 | ||
| 
						 | 
					3fdb6a6177 | ||
| 
						 | 
					3b9d3ee422 | ||
| 
						 | 
					a4ea9744cc | ||
| 
						 | 
					1aa3af7cec | ||
| 
						 | 
					10cced8d5e | ||
| 
						 | 
					de85d4e517 | ||
| 
						 | 
					a06a6a2b27 | ||
| 
						 | 
					1a4af66a8a | ||
| 
						 | 
					6db4feeedd | ||
| 
						 | 
					dfdfd06ab1 | ||
| 
						 | 
					842995f7f6 | ||
| 
						 | 
					ba01cfa02b | ||
| 
						 | 
					329dfbbcde | ||
| 
						 | 
					ac1b5df59a | ||
| 
						 | 
					8f2dd3ec6e | ||
| 
						 | 
					8edf3af709 | ||
| 
						 | 
					4392b37c0b | ||
| 
						 | 
					286607fc5d | ||
| 
						 | 
					4f15fb055d | ||
| 
						 | 
					3864082269 | ||
| 
						 | 
					076ad66754 | ||
| 
						 | 
					cd5d8365fb | ||
| 
						 | 
					1b4ba18d70 | ||
| 
						 | 
					80502c7414 | ||
| 
						 | 
					dea0e371fd | ||
| 
						 | 
					df9c11b640 | ||
| 
						 | 
					fef2e00fef | ||
| 
						 | 
					9f27ed2d64 | ||
| 
						 | 
					a9ebb18609 | ||
| 
						 | 
					7b2d557d90 | ||
| 
						 | 
					fe50bdc8c5 | ||
| 
						 | 
					3ae4676df2 | ||
| 
						 | 
					ff78235bf7 | ||
| 
						 | 
					68d11560ee | ||
| 
						 | 
					b468952e04 | ||
| 
						 | 
					aec6e6f71d | ||
| 
						 | 
					1020473e54 | ||
| 
						 | 
					3433a13b62 | ||
| 
						 | 
					b9ecb8632a | ||
| 
						 | 
					be97cca949 | ||
| 
						 | 
					0c46a0a957 | ||
| 
						 | 
					3e0d091f4d | ||
| 
						 | 
					1387c67219 | ||
| 
						 | 
					fd02712159 | ||
| 
						 | 
					c75689800e | ||
| 
						 | 
					b094709d4c | ||
| 
						 | 
					f1a6f42b8a | ||
| 
						 | 
					b8673c2dcc | ||
| 
						 | 
					13e8ceb7e3 | ||
| 
						 | 
					6c112c21a7 | ||
| 
						 | 
					1ca76459fe | ||
| 
						 | 
					52ebfd30b9 | ||
| 
						 | 
					44822e5a63 | ||
| 
						 | 
					2561fb5cd4 | ||
| 
						 | 
					96f25fd949 | ||
| 
						 | 
					ccbc6307e6 | ||
| 
						 | 
					39e625bb34 | ||
| 
						 | 
					8fd4e57fe8 | ||
| 
						 | 
					192b2d50b4 | ||
| 
						 | 
					6dd67a8218 | ||
| 
						 | 
					3edfb11c33 | ||
| 
						 | 
					fd607bf963 | ||
| 
						 | 
					c68cd6aad8 | ||
| 
						 | 
					f4674e93c7 | ||
| 
						 | 
					21a4eb2a71 | ||
| 
						 | 
					ed336bec0c | ||
| 
						 | 
					b5f8063ab7 | ||
| 
						 | 
					69dc1b8056 | ||
| 
						 | 
					a933376bf6 | ||
| 
						 | 
					21a4245204 | ||
| 
						 | 
					bcfbc0d2c0 | ||
| 
						 | 
					f453205a5d | ||
| 
						 | 
					a8d3ed0dba | ||
| 
						 | 
					42ab4717d5 | ||
| 
						 | 
					a36796ab4e | ||
| 
						 | 
					cd9a4f9902 | ||
| 
						 | 
					806f39bc88 | ||
| 
						 | 
					6afeb470d9 | ||
| 
						 | 
					991d60e019 | ||
| 
						 | 
					5cebcdd675 | ||
| 
						 | 
					fdb09654c2 | ||
| 
						 | 
					a657ce2f52 | ||
| 
						 | 
					7b17af5575 | ||
| 
						 | 
					cc2b9e536f | ||
| 
						 | 
					1a8a0b2ebc | ||
| 
						 | 
					c808d0146c | ||
| 
						 | 
					0bb107b48d | ||
| 
						 | 
					a4f2b8fd5e | ||
| 
						 | 
					4fd9b4f540 | ||
| 
						 | 
					d51980e0e5 | ||
| 
						 | 
					5ece25ebac | ||
| 
						 | 
					d578174b23 | ||
| 
						 | 
					08689107da | ||
| 
						 | 
					0d680934f8 | ||
| 
						 | 
					907d739943 | ||
| 
						 | 
					e5665769ef | ||
| 
						 | 
					8abbc73546 | ||
| 
						 | 
					0c86ffdfff | ||
| 
						 | 
					c0f59756ae | ||
| 
						 | 
					41dd567630 | ||
| 
						 | 
					6d87fafbc0 | ||
| 
						 | 
					dddc4f34ac | ||
| 
						 | 
					9a99bcd2c2 | ||
| 
						 | 
					e849a3eba0 | ||
| 
						 | 
					decb2bf8c2 | ||
| 
						 | 
					0ae5dc5cf9 | ||
| 
						 | 
					9160497b28 | ||
| 
						 | 
					9a4e19c651 | ||
| 
						 | 
					62bfb10ca3 | ||
| 
						 | 
					9e3d80f1ea | ||
| 
						 | 
					fc3b516c76 | ||
| 
						 | 
					ac183fcde6 | ||
| 
						 | 
					7ebc977601 | ||
| 
						 | 
					ec94cdb2df | ||
| 
						 | 
					9c61451f0f | ||
| 
						 | 
					d08afb6d75 | ||
| 
						 | 
					087ea5372b | ||
| 
						 | 
					b882796c90 | ||
| 
						 | 
					91c6a8fba1 | ||
| 
						 | 
					2e69ca7444 | ||
| 
						 | 
					58c08c3ff7 | ||
| 
						 | 
					737f1146a1 | ||
| 
						 | 
					0f85f2453b | ||
| 
						 | 
					a8c4cf1940 | ||
| 
						 | 
					cf320e63ee | ||
| 
						 | 
					95a11e8f96 | ||
| 
						 | 
					bf611d36cc | ||
| 
						 | 
					b543e03660 | ||
| 
						 | 
					c1e101366e | ||
| 
						 | 
					47f21ae17e | ||
| 
						 | 
					c1dd0151f9 | ||
| 
						 | 
					80efb654d5 | ||
| 
						 | 
					2ef9a9220f | ||
| 
						 | 
					c27edec0f7 | ||
| 
						 | 
					c8a65d6137 | ||
| 
						 | 
					f408a44898 | ||
| 
						 | 
					4f289427ca | ||
| 
						 | 
					2b89cc187b | ||
| 
						 | 
					59dc2ad032 | ||
| 
						 | 
					0d6e2c0e33 | ||
| 
						 | 
					37a02b699d | ||
| 
						 | 
					9772e95238 | ||
| 
						 | 
					f4d86120c4 | ||
| 
						 | 
					384d11d998 | ||
| 
						 | 
					5f8ea6a474 | ||
| 
						 | 
					9769a9fa24 | ||
| 
						 | 
					4d16155aec | ||
| 
						 | 
					00ca2a6d92 | ||
| 
						 | 
					ecddb5ba63 | ||
| 
						 | 
					6fe5298602 | ||
| 
						 | 
					1c3c7ec842 | ||
| 
						 | 
					e547ee40b0 | ||
| 
						 | 
					81806df5cb | ||
| 
						 | 
					3b9c574149 | ||
| 
						 | 
					4159ba4dca | ||
| 
						 | 
					a1eb8ab3d0 | ||
| 
						 | 
					2fb316b79e | ||
| 
						 | 
					ad3319496d | ||
| 
						 | 
					38a7d35c4b | ||
| 
						 | 
					3c6e24e50f | ||
| 
						 | 
					b127f38081 | ||
| 
						 | 
					82cdc4cc03 | ||
| 
						 | 
					2566237c91 | ||
| 
						 | 
					562c952d52 | ||
| 
						 | 
					23d160cba1 | ||
| 
						 | 
					8cbe0b7c4f | ||
| 
						 | 
					d804dad1f0 | ||
| 
						 | 
					72595922eb | ||
| 
						 | 
					f1c330eac7 | ||
| 
						 | 
					f143471723 | ||
| 
						 | 
					957e6acf03 | ||
| 
						 | 
					a6bc509c3d | ||
| 
						 | 
					5fd145c7d6 | ||
| 
						 | 
					f9b431e566 | ||
| 
						 | 
					a35acfeb88 | ||
| 
						 | 
					e028b2dd41 | ||
| 
						 | 
					69e539ffbe | ||
| 
						 | 
					4a8506f4fe | ||
| 
						 | 
					2621e2fdde | ||
| 
						 | 
					8425632453 | ||
| 
						 | 
					bce03ee024 | ||
| 
						 | 
					b6f76b70ab | ||
| 
						 | 
					30e62dd203 | ||
| 
						 | 
					ae9179eb0e | ||
| 
						 | 
					0d59e8b0c2 | ||
| 
						 | 
					545f787a4e | ||
| 
						 | 
					64199bbb62 | ||
| 
						 | 
					1ac4625947 | ||
| 
						 | 
					b45c16f2c0 | ||
| 
						 | 
					86a33ed818 | ||
| 
						 | 
					65c4a96f41 | ||
| 
						 | 
					b7908816a9 | ||
| 
						 | 
					dc55a3a180 | ||
| 
						 | 
					4b953d968b | ||
| 
						 | 
					81324da9e8 | ||
| 
						 | 
					54d94eef84 | ||
| 
						 | 
					397799278c | ||
| 
						 | 
					4b32a9cae0 | ||
| 
						 | 
					6f6fc32ed4 | ||
| 
						 | 
					429e0345d0 | ||
| 
						 | 
					67c3f39ae0 | ||
| 
						 | 
					50911d8a54 | ||
| 
						 | 
					d8d0eed1fb | ||
| 
						 | 
					d1eb584430 | ||
| 
						 | 
					c76e10299d | ||
| 
						 | 
					2949231f67 | ||
| 
						 | 
					d6731e4e5b | ||
| 
						 | 
					d92b064561 | ||
| 
						 | 
					ec4a7f64de | ||
| 
						 | 
					14877301e4 | ||
| 
						 | 
					d92cba15bb | ||
| 
						 | 
					33d92c9240 | ||
| 
						 | 
					737ed24d91 | ||
| 
						 | 
					670f497af4 | ||
| 
						 | 
					11ba1cc6e4 | ||
| 
						 | 
					e43ff02c3d | ||
| 
						 | 
					c69c4754cf | ||
| 
						 | 
					8478d761db | ||
| 
						 | 
					500a4dc130 | ||
| 
						 | 
					3e2a32544a | ||
| 
						 | 
					83e0f88827 | ||
| 
						 | 
					c420d9c572 | ||
| 
						 | 
					c94d90911f | ||
| 
						 | 
					04fd524b52 | ||
| 
						 | 
					b49744779e | ||
| 
						 | 
					60de792147 | ||
| 
						 | 
					e6d6da53c7 | ||
| 
						 | 
					cd62cb8b84 | ||
| 
						 | 
					3439eeb7b7 | ||
| 
						 | 
					85eb8546c3 | ||
| 
						 | 
					bc5a8bbe5b | ||
| 
						 | 
					6e413643de | ||
| 
						 | 
					bd64ceb82d | ||
| 
						 | 
					d92a93a872 | ||
| 
						 | 
					0def242b40 | ||
| 
						 | 
					eeb5e2d3be | ||
| 
						 | 
					e76132f464 | ||
| 
						 | 
					ac41327bf8 | ||
| 
						 | 
					0084b5d21c | ||
| 
						 | 
					69b4de1b74 | ||
| 
						 | 
					0c3e8d4630 | ||
| 
						 | 
					af739bc32b | ||
| 
						 | 
					b535ca2b35 | ||
| 
						 | 
					42a3f7f9c3 | ||
| 
						 | 
					a244a7ea09 | ||
| 
						 | 
					c03a3c336d | ||
| 
						 | 
					59d648517f | ||
| 
						 | 
					e24e62a556 | ||
| 
						 | 
					a61ab8f0fb | ||
| 
						 | 
					6841322a99 | ||
| 
						 | 
					3b7dab4c6a | ||
| 
						 | 
					229a403167 | ||
| 
						 | 
					8513601a77 | ||
| 
						 | 
					a13da08652 | ||
| 
						 | 
					5b19f4fdeb | ||
| 
						 | 
					ba9fab427b | ||
| 
						 | 
					72ffcbbb45 | ||
| 
						 | 
					e028768252 | ||
| 
						 | 
					a7d07f8c60 | ||
| 
						 | 
					9a16b51c28 | ||
| 
						 | 
					fd1edc0a10 | ||
| 
						 | 
					8deaeb26a7 | ||
| 
						 | 
					518d9232ca | ||
| 
						 | 
					a3e16eb1e2 | ||
| 
						 | 
					1d630e4770 | ||
| 
						 | 
					e843cf4575 | ||
| 
						 | 
					3cd4ef228c | ||
| 
						 | 
					7240a9aa51 | ||
| 
						 | 
					213323d713 | ||
| 
						 | 
					64cd687635 | ||
| 
						 | 
					3db5c9ac48 | ||
| 
						 | 
					acd0e46768 | ||
| 
						 | 
					b52c19cde9 | ||
| 
						 | 
					18c3902a7f | ||
| 
						 | 
					bfb6f3b662 | ||
| 
						 | 
					12d13df907 | ||
| 
						 | 
					d25c7cbdb9 | ||
| 
						 | 
					3e40b9312a | ||
| 
						 | 
					e74623ba75 | ||
| 
						 | 
					fe4f977848 | ||
| 
						 | 
					5884db2e53 | ||
| 
						 | 
					9a0b23e683 | ||
| 
						 | 
					5309c8fd08 | ||
| 
						 | 
					1f8912aa2e | ||
| 
						 | 
					873c348d50 | ||
| 
						 | 
					47d08002bf | ||
| 
						 | 
					47c2f21884 | ||
| 
						 | 
					da6aec9cf9 | ||
| 
						 | 
					703788a1c6 | ||
| 
						 | 
					fc0de059bb | ||
| 
						 | 
					448594e724 | ||
| 
						 | 
					ffbd3d8246 | ||
| 
						 | 
					128e4e99e7 | ||
| 
						 | 
					6983b0c2dd | ||
| 
						 | 
					87281b450b | ||
| 
						 | 
					3482057a68 | ||
| 
						 | 
					0c960010f7 | ||
| 
						 | 
					6bda58b24e | ||
| 
						 | 
					0c086a5e56 | ||
| 
						 | 
					53f738f39c | ||
| 
						 | 
					9be08e1921 | ||
| 
						 | 
					afccb5d0f2 | ||
| 
						 | 
					9769787337 | ||
| 
						 | 
					7d3a4dbfc7 | ||
| 
						 | 
					0b6b1c7e9d | ||
| 
						 | 
					f3ea96ca23 | ||
| 
						 | 
					e314b33d05 | ||
| 
						 | 
					68eff53911 | ||
| 
						 | 
					86b4c2a64e | ||
| 
						 | 
					dd6f845fe8 | ||
| 
						 | 
					8f183d4dfa | ||
| 
						 | 
					23fe484670 | ||
| 
						 | 
					aba5e50ddb | ||
| 
						 | 
					fc6e8802a3 | ||
| 
						 | 
					5414bb4757 | ||
| 
						 | 
					1f8b119b67 | ||
| 
						 | 
					54cfa15b29 | ||
| 
						 | 
					9b3dfafdcd | ||
| 
						 | 
					ec03dbae5e | ||
| 
						 | 
					e360ab3995 | ||
| 
						 | 
					b843c6e0db | ||
| 
						 | 
					b68e7c5fb4 | ||
| 
						 | 
					e184e3230c | ||
| 
						 | 
					532a1d135e | ||
| 
						 | 
					f940d10ca4 | ||
| 
						 | 
					11eb93b280 | ||
| 
						 | 
					68f34b0cc4 | ||
| 
						 | 
					d5c69dd634 | ||
| 
						 | 
					b512a83a5c | ||
| 
						 | 
					7c5f81dbde | ||
| 
						 | 
					370f3ac523 | ||
| 
						 | 
					4c75b784dd | ||
| 
						 | 
					efa481f624 | ||
| 
						 | 
					14c686b92f | ||
| 
						 | 
					c503f9fb03 | ||
| 
						 | 
					bdfaad90c5 | ||
| 
						 | 
					e2fafe6e8c | ||
| 
						 | 
					01902d9df3 | ||
| 
						 | 
					95d953b3ca | ||
| 
						 | 
					572ed17ac8 | ||
| 
						 | 
					c148825631 | ||
| 
						 | 
					3f92eb3025 | ||
| 
						 | 
					01f6986d6e | ||
| 
						 | 
					317236505d | ||
| 
						 | 
					3836e9aa69 | ||
| 
						 | 
					9436adc9ed | ||
| 
						 | 
					c826435268 | ||
| 
						 | 
					c748d162a7 | ||
| 
						 | 
					3ad15178e0 | ||
| 
						 | 
					a01aabba40 | ||
| 
						 | 
					a196e03c8e | ||
| 
						 | 
					00698ce31c | ||
| 
						 | 
					e93d8904dc | ||
| 
						 | 
					1a10f84e15 | ||
| 
						 | 
					cb1b290ec2 | ||
| 
						 | 
					2cb4129d03 | ||
| 
						 | 
					942bf438f4 | ||
| 
						 | 
					89bb47b913 | ||
| 
						 | 
					c35f8e1664 | ||
| 
						 | 
					4c8e1fe1f5 | ||
| 
						 | 
					1c2e349cb7 | ||
| 
						 | 
					41f551018b | ||
| 
						 | 
					b71b8e8c34 | ||
| 
						 | 
					ea91aec1fc | ||
| 
						 | 
					381b62b65b | ||
| 
						 | 
					4def172286 | ||
| 
						 | 
					be30a63c68 | ||
| 
						 | 
					d03fc90227 | ||
| 
						 | 
					904def81f1 | ||
| 
						 | 
					dd0fe0834a | ||
| 
						 | 
					89f516c3c8 | ||
| 
						 | 
					ff0028a7fd | ||
| 
						 | 
					4a41cda137 | ||
| 
						 | 
					208fd40ea1 | ||
| 
						 | 
					ef78269c86 | ||
| 
						 | 
					2469101020 | ||
| 
						 | 
					ee6dbc0c7d | ||
| 
						 | 
					7e2d4368be | ||
| 
						 | 
					99c4509793 | ||
| 
						 | 
					d102674c61 | ||
| 
						 | 
					d5085938fa | ||
| 
						 | 
					0dc43670c1 | ||
| 
						 | 
					b16e4026dd | ||
| 
						 | 
					dedfea75ef | ||
| 
						 | 
					2044a8f8b2 | ||
| 
						 | 
					d4cb886293 | ||
| 
						 | 
					eb62730693 | ||
| 
						 | 
					57531f147b | ||
| 
						 | 
					ea9868404a | ||
| 
						 | 
					1a2769c5bf | ||
| 
						 | 
					2708542410 | ||
| 
						 | 
					008eed2b67 | ||
| 
						 | 
					97d45125ba | ||
| 
						 | 
					f6ddfc7725 | ||
| 
						 | 
					c59d84ff59 | ||
| 
						 | 
					de37559249 | ||
| 
						 | 
					498a79f418 | ||
| 
						 | 
					179737df72 | ||
| 
						 | 
					c448e2bdb9 | ||
| 
						 | 
					d45f7044d9 | ||
| 
						 | 
					7e556af27e | ||
| 
						 | 
					45d9cd1bd6 | ||
| 
						 | 
					567b14da00 | ||
| 
						 | 
					e526ac1daa | ||
| 
						 | 
					6be14ff514 | ||
| 
						 | 
					7b1daefd53 | ||
| 
						 | 
					cc61983763 | ||
| 
						 | 
					b2444e454c | ||
| 
						 | 
					d6e94f5df4 | ||
| 
						 | 
					b6480f071a | ||
| 
						 | 
					c5404455f3 | ||
| 
						 | 
					651457304b | ||
| 
						 | 
					953826c516 | ||
| 
						 | 
					c658db6cfd | ||
| 
						 | 
					699a7d25ff | ||
| 
						 | 
					ddf209ebc5 | ||
| 
						 | 
					9f632ad794 | ||
| 
						 | 
					13eae2f5c4 | ||
| 
						 | 
					56cf0da5cd | ||
| 
						 | 
					301b76292e | ||
| 
						 | 
					04747ca43d | ||
| 
						 | 
					dbd976cd2f | ||
| 
						 | 
					0166fec840 | ||
| 
						 | 
					313776c724 | ||
| 
						 | 
					87ea75809a | ||
| 
						 | 
					8405a42cb4 | ||
| 
						 | 
					6e3edff660 | ||
| 
						 | 
					76eb301ace | ||
| 
						 | 
					f65f927544 | ||
| 
						 | 
					de5ea6c4bd | ||
| 
						 | 
					770183f0ad | ||
| 
						 | 
					cc5c7b5e26 | ||
| 
						 | 
					f43118abee | ||
| 
						 | 
					1e57f66e17 | ||
| 
						 | 
					4f781690dd | ||
| 
						 | 
					61dbd740b9 | ||
| 
						 | 
					407a14b018 | ||
| 
						 | 
					2df967d8be | ||
| 
						 | 
					b336ee4e23 | ||
| 
						 | 
					0cc023c4b0 | ||
| 
						 | 
					e323edd373 | ||
| 
						 | 
					bd08d60298 | ||
| 
						 | 
					0138a37f3a | ||
| 
						 | 
					d00a94e673 | ||
| 
						 | 
					5b1f7406fb | ||
| 
						 | 
					462b91a6d3 | ||
| 
						 | 
					b861f8b48c | ||
| 
						 | 
					1c9664febe | ||
| 
						 | 
					48e4e2a120 | ||
| 
						 | 
					bf82bf6cb5 | ||
| 
						 | 
					86131a642d | ||
| 
						 | 
					bd2034fa5b | ||
| 
						 | 
					26ebf360e6 | ||
| 
						 | 
					917da04b6d | ||
| 
						 | 
					85b8acd1b7 | ||
| 
						 | 
					699b28b9af | ||
| 
						 | 
					6739b42162 | ||
| 
						 | 
					657f62228d | ||
| 
						 | 
					cd547c168d | ||
| 
						 | 
					d85ff96a77 | ||
| 
						 | 
					31e5617e82 | ||
| 
						 | 
					80377ccc93 | ||
| 
						 | 
					bd88b31a0c | ||
| 
						 | 
					01d20b8162 | ||
| 
						 | 
					ecc7c813fd | ||
| 
						 | 
					c0ca83596d | ||
| 
						 | 
					62e4941ad4 | ||
| 
						 | 
					96a2e9133f | ||
| 
						 | 
					6b6f6a9055 | ||
| 
						 | 
					9907e92f66 | ||
| 
						 | 
					14f3e23216 | ||
| 
						 | 
					7deeb14b7e | ||
| 
						 | 
					fd0212f474 | ||
| 
						 | 
					4a708b7afe | ||
| 
						 | 
					b7ef3f61be | ||
| 
						 | 
					8e1f7cadca | ||
| 
						 | 
					71c40d6122 | ||
| 
						 | 
					6544bc27fe | ||
| 
						 | 
					62ac98157e | ||
| 
						 | 
					929ede64dd | ||
| 
						 | 
					9f5d52fc93 | ||
| 
						 | 
					2616674785 | ||
| 
						 | 
					52c1ec1150 | ||
| 
						 | 
					d3bf54ad85 | ||
| 
						 | 
					2bc928849e | ||
| 
						 | 
					8088b9054a | ||
| 
						 | 
					d30170f6cb | ||
| 
						 | 
					1cb2d78863 | ||
| 
						 | 
					54318b8dfd | ||
| 
						 | 
					2fc8cabb7d | ||
| 
						 | 
					8427a29843 | ||
| 
						 | 
					3bb48bbc64 | ||
| 
						 | 
					83fdb1c38a | ||
| 
						 | 
					5d6ff4cc47 | ||
| 
						 | 
					14235886f5 | ||
| 
						 | 
					2968bcd9a0 | ||
| 
						 | 
					1df3fd1185 | ||
| 
						 | 
					dd9a498813 | ||
| 
						 | 
					81401186f5 | ||
| 
						 | 
					2bb0a652e8 | ||
| 
						 | 
					6cc5c9e6b0 | ||
| 
						 | 
					c0e3303e49 | ||
| 
						 | 
					c7d8da1b69 | ||
| 
						 | 
					184debe26f | ||
| 
						 | 
					f1e6a9b708 | ||
| 
						 | 
					017d4ec40b | ||
| 
						 | 
					b41d31423c | ||
| 
						 | 
					3a9ca2ff04 | ||
| 
						 | 
					ddb037c70c | ||
| 
						 | 
					703cae55e8 | ||
| 
						 | 
					4ee2a523f1 | ||
| 
						 | 
					587ed9fa9c | ||
| 
						 | 
					7214b0fdd5 | ||
| 
						 | 
					41ba33da43 | ||
| 
						 | 
					9a268c3f4e | ||
| 
						 | 
					0393f2eeb2 | ||
| 
						 | 
					4f02ce7880 | ||
| 
						 | 
					75b24e6035 | ||
| 
						 | 
					1739e74dad | ||
| 
						 | 
					33fd644931 | ||
| 
						 | 
					cfdcc9bea0 | ||
| 
						 | 
					f986e4356c | ||
| 
						 | 
					6f2db198ec | ||
| 
						 | 
					d8ad6eedd8 | ||
| 
						 | 
					b188d2bc95 | ||
| 
						 | 
					61a32163a1 | ||
| 
						 | 
					7b1b97d430 | ||
| 
						 | 
					e42fd2c3ee | ||
| 
						 | 
					486bc21908 | ||
| 
						 | 
					4bb997b5ee | ||
| 
						 | 
					76f7861cd9 | ||
| 
						 | 
					36b558ab88 | ||
| 
						 | 
					551a749c5d | ||
| 
						 | 
					6609d3f86a | ||
| 
						 | 
					5c59766538 | ||
| 
						 | 
					9bc97fab98 | ||
| 
						 | 
					e46d551baa | ||
| 
						 | 
					2b38ddc764 | ||
| 
						 | 
					08772d3816 | ||
| 
						 | 
					1d7135bb51 | ||
| 
						 | 
					6bc6e588b0 | ||
| 
						 | 
					199e827566 | ||
| 
						 | 
					23af7e44ee | ||
| 
						 | 
					b640093f63 | ||
| 
						 | 
					c3d7dd14c9 | ||
| 
						 | 
					1150ade401 | ||
| 
						 | 
					8b7737141f | ||
| 
						 | 
					6f4354a82f | ||
| 
						 | 
					1042c00188 | ||
| 
						 | 
					9739985141 | ||
| 
						 | 
					3ddfb2f411 | ||
| 
						 | 
					4a66cb7a24 | ||
| 
						 | 
					f2012e396c | ||
| 
						 | 
					2f14700f10 | ||
| 
						 | 
					49e226e4c1 | ||
| 
						 | 
					8263eb0e5e | ||
| 
						 | 
					c1da544a9d | ||
| 
						 | 
					e74df56e0c | ||
| 
						 | 
					111b50b437 | ||
| 
						 | 
					0bf22d3406 | ||
| 
						 | 
					61bb2db3d1 | ||
| 
						 | 
					9fff261779 | ||
| 
						 | 
					b627ee7516 | ||
| 
						 | 
					a2ba11277e | ||
| 
						 | 
					d1a0f7954b | ||
| 
						 | 
					74e6264b47 | ||
| 
						 | 
					ced1522c61 | ||
| 
						 | 
					426845b192 | ||
| 
						 | 
					0be833e73c | ||
| 
						 | 
					64b1c9171c | ||
| 
						 | 
					ee33bc365e | ||
| 
						 | 
					bc02666ff0 | ||
| 
						 | 
					9c4a7a7a27 | ||
| 
						 | 
					3021e1b20d | ||
| 
						 | 
					99018fba32 | ||
| 
						 | 
					84e14c9f80 | ||
| 
						 | 
					2a375ed98d | ||
| 
						 | 
					0e9c8ce944 | ||
| 
						 | 
					2312513a27 | ||
| 
						 | 
					2d495b070f | ||
| 
						 | 
					1f1d40e166 | ||
| 
						 | 
					90e2b2e71f | ||
| 
						 | 
					08b3d5e316 | ||
| 
						 | 
					1ac475d48f | ||
| 
						 | 
					6f874baa54 | ||
| 
						 | 
					a9ffe80d27 | ||
| 
						 | 
					83b4f3341e | ||
| 
						 | 
					801704f065 | ||
| 
						 | 
					45b25c4e75 | ||
| 
						 | 
					ea311f70a0 | ||
| 
						 | 
					e3265c86a5 | ||
| 
						 | 
					e537259208 | ||
| 
						 | 
					b9c7990344 | ||
| 
						 | 
					d5c1cfe2f1 | ||
| 
						 | 
					1a4f27cbbf | ||
| 
						 | 
					11ad381534 | ||
| 
						 | 
					0b548a40f3 | ||
| 
						 | 
					28e5463196 | ||
| 
						 | 
					37ea632ac7 | ||
| 
						 | 
					2f641077e6 | ||
| 
						 | 
					78318f47c6 | ||
| 
						 | 
					c83c73a3ae | ||
| 
						 | 
					6305be8c55 | ||
| 
						 | 
					4b325ef22c | ||
| 
						 | 
					a422dff7ae | ||
| 
						 | 
					271ff4f6c4 | ||
| 
						 | 
					4cdd275d0b | ||
| 
						 | 
					9a36e86949 | ||
| 
						 | 
					fa806ed16c | ||
| 
						 | 
					57c270973e | ||
| 
						 | 
					17ebfb24f2 | ||
| 
						 | 
					26072691ab | ||
| 
						 | 
					e8b3ea56e0 | ||
| 
						 | 
					2b1a72b838 | ||
| 
						 | 
					352afc487a | ||
| 
						 | 
					6fae29981a | ||
| 
						 | 
					9569de1b21 | ||
| 
						 | 
					1a952946b2 | ||
| 
						 | 
					3b52cf6111 | ||
| 
						 | 
					74197e2aee | ||
| 
						 | 
					7152067b09 | ||
| 
						 | 
					ac3d061eee | ||
| 
						 | 
					8ee67713bf | ||
| 
						 | 
					e57cd4fea2 | ||
| 
						 | 
					5e3a71a6e7 | ||
| 
						 | 
					a602b8f844 | ||
| 
						 | 
					89da7d187a | ||
| 
						 | 
					6c5533aa8b | ||
| 
						 | 
					66249b258c | ||
| 
						 | 
					e03512ebf3 | ||
| 
						 | 
					b152c8477a | ||
| 
						 | 
					a298c4254b | ||
| 
						 | 
					b8f04c6d4a | ||
| 
						 | 
					753dc5c068 | ||
| 
						 | 
					bf70d6b512 | ||
| 
						 | 
					760f11ca70 | ||
| 
						 | 
					2bcd0ccbcb | ||
| 
						 | 
					0aee258af4 | ||
| 
						 | 
					9e879f306c | ||
| 
						 | 
					fb4a4d935a | ||
| 
						 | 
					282552cdfa | ||
| 
						 | 
					1d316ff28a | ||
| 
						 | 
					1da866a7da | ||
| 
						 | 
					1c628c28fa | ||
| 
						 | 
					a350b30a9c | ||
| 
						 | 
					cf6c3f9337 | ||
| 
						 | 
					2388eac41d | ||
| 
						 | 
					f0e0f2ba5b | ||
| 
						 | 
					0c8b9caaf3 | ||
| 
						 | 
					c0edeb8b23 | ||
| 
						 | 
					fdcf74788d | ||
| 
						 | 
					df9c82a4ae | ||
| 
						 | 
					2963cec1fb | ||
| 
						 | 
					8053e32c9c | ||
| 
						 | 
					1750ac5fb5 | ||
| 
						 | 
					b4d775db0c | ||
| 
						 | 
					3031483209 | ||
| 
						 | 
					97b990581d | ||
| 
						 | 
					98fa4799cc | ||
| 
						 | 
					95a853fc0e | ||
| 
						 | 
					7a14cadbf5 | ||
| 
						 | 
					ab5efcc8c1 | ||
| 
						 | 
					bb71ff2bad | ||
| 
						 | 
					c1a2efd32c | ||
| 
						 | 
					ca4d92fd66 | ||
| 
						 | 
					efb354031a | ||
| 
						 | 
					180d01c89d | ||
| 
						 | 
					f6c1a5e97f | ||
| 
						 | 
					54e7caafc1 | ||
| 
						 | 
					e76c97540c | ||
| 
						 | 
					3f01ef6d5e | ||
| 
						 | 
					8e118c7f7b | ||
| 
						 | 
					6dc5622bf2 | ||
| 
						 | 
					27a9ef01b6 | ||
| 
						 | 
					9390b9a646 | ||
| 
						 | 
					871f3c3436 | ||
| 
						 | 
					a41095a797 | ||
| 
						 | 
					bb94c9a813 | ||
| 
						 | 
					fcd991b8d6 | ||
| 
						 | 
					2df43cfd62 | ||
| 
						 | 
					014aafbd3d | ||
| 
						 | 
					d1d058a848 | ||
| 
						 | 
					d492396182 | ||
| 
						 | 
					2c710412a1 | ||
| 
						 | 
					7dcade3d79 | ||
| 
						 | 
					dc73a2d54b | ||
| 
						 | 
					6c2bb5b395 | ||
| 
						 | 
					fccf99cca5 | ||
| 
						 | 
					0d91dd9a6e | ||
| 
						 | 
					d84af0f18e | ||
| 
						 | 
					6b6c9ce0ae | ||
| 
						 | 
					5a31d6427f | ||
| 
						 | 
					8b3ff4a560 | ||
| 
						 | 
					53c81d2c76 | ||
| 
						 | 
					518bfc0b2c | ||
| 
						 | 
					c6851819d4 | ||
| 
						 | 
					d5851753c2 | ||
| 
						 | 
					379b1446f6 | ||
| 
						 | 
					6d50ef72b7 | ||
| 
						 | 
					f0954081c1 | ||
| 
						 | 
					9653d0affb | ||
| 
						 | 
					dd626461e8 | ||
| 
						 | 
					048b33e134 | ||
| 
						 | 
					eff7a70f6b | ||
| 
						 | 
					5f73966010 | ||
| 
						 | 
					911c9ac210 | ||
| 
						 | 
					f59c369b61 | ||
| 
						 | 
					526d239fe9 | ||
| 
						 | 
					939d704460 | ||
| 
						 | 
					b7e8da5e76 | ||
| 
						 | 
					c5d68e5397 | ||
| 
						 | 
					a2bbe71e53 | ||
| 
						 | 
					1c0cf65145 | ||
| 
						 | 
					60d41e8569 | ||
| 
						 | 
					76698476b6 | ||
| 
						 | 
					4e4ac89401 | ||
| 
						 | 
					e3e6a27348 | ||
| 
						 | 
					b419472fd7 | ||
| 
						 | 
					bd2af4df1d | ||
| 
						 | 
					bbbb4cd4fe | ||
| 
						 | 
					445568152c | ||
| 
						 | 
					ce70ff0f21 | ||
| 
						 | 
					6dbf16793e | ||
| 
						 | 
					eba69c8c35 | ||
| 
						 | 
					ae2e6c5ce6 | ||
| 
						 | 
					5a2a0cd074 | ||
| 
						 | 
					9c3a23a8a1 | ||
| 
						 | 
					b6f0f07bec | ||
| 
						 | 
					e060e11cd2 | ||
| 
						 | 
					883245de68 | ||
| 
						 | 
					9cfc411a51 | ||
| 
						 | 
					fb3a785227 | ||
| 
						 | 
					3fe8958323 | ||
| 
						 | 
					117f0e1637 | ||
| 
						 | 
					b09b1d5690 | ||
| 
						 | 
					e073e2b713 | ||
| 
						 | 
					8343443bd7 | ||
| 
						 | 
					c5ed66c40c | ||
| 
						 | 
					de65b2396c | ||
| 
						 | 
					c85cef57c8 | ||
| 
						 | 
					6c9bae518a | ||
| 
						 | 
					7232168037 | ||
| 
						 | 
					9da06d8384 | ||
| 
						 | 
					296a4721db | ||
| 
						 | 
					f2badf7b6d | ||
| 
						 | 
					766be1aa3c | ||
| 
						 | 
					4812219e0d | ||
| 
						 | 
					7b4e39aad2 | ||
| 
						 | 
					fbff951e22 | ||
| 
						 | 
					09198d5ec2 | ||
| 
						 | 
					3666995f7f | ||
| 
						 | 
					0572674279 | ||
| 
						 | 
					19f2265161 | ||
| 
						 | 
					f613449dff | ||
| 
						 | 
					a1291b1b16 | ||
| 
						 | 
					39ebc28396 | ||
| 
						 | 
					6017714363 | ||
| 
						 | 
					bff7092ce1 | ||
| 
						 | 
					1741742617 | ||
| 
						 | 
					b4a6bea1b4 | ||
| 
						 | 
					57e06b2d2f | ||
| 
						 | 
					0bc7363dae | ||
| 
						 | 
					44b2140230 | ||
| 
						 | 
					49bc934066 | ||
| 
						 | 
					53d337f462 | ||
| 
						 | 
					66e7791b95 | ||
| 
						 | 
					2180c5ff23 | ||
| 
						 | 
					2f4fa7572e | ||
| 
						 | 
					5923506237 | ||
| 
						 | 
					b9600654f8 | ||
| 
						 | 
					6b0a082ac9 | ||
| 
						 | 
					c5a108d672 | ||
| 
						 | 
					23c2925baf | ||
| 
						 | 
					fa4c72d59c | ||
| 
						 | 
					d66d901204 | ||
| 
						 | 
					b09eaf98cc | ||
| 
						 | 
					7f9bf85958 | ||
| 
						 | 
					d1d89fcd74 | ||
| 
						 | 
					bc3f5700d4 | ||
| 
						 | 
					3a938fd615 | ||
| 
						 | 
					dc3729aec2 | ||
| 
						 | 
					dd214ae5d1 | ||
| 
						 | 
					8f7f8c5736 | ||
| 
						 | 
					00701a8de4 | ||
| 
						 | 
					fc41c9aa2f | ||
| 
						 | 
					a5442eee0d | ||
| 
						 | 
					9dcf5b5320 | ||
| 
						 | 
					28b5295a6e | ||
| 
						 | 
					8261ae34bd | ||
| 
						 | 
					02baa9329c | ||
| 
						 | 
					7f01c7b861 | ||
| 
						 | 
					8d0f0c227a | ||
| 
						 | 
					c8170bc9f3 | ||
| 
						 | 
					83003b66b9 | ||
| 
						 | 
					cbdb15bc32 | ||
| 
						 | 
					712e15407d | ||
| 
						 | 
					e424e19d1c | ||
| 
						 | 
					546d8dee98 | ||
| 
						 | 
					60b9fc679a | ||
| 
						 | 
					79a4f24bc2 | ||
| 
						 | 
					02b8ecf300 | ||
| 
						 | 
					bdbc5a7a9d | ||
| 
						 | 
					680fe18bac | ||
| 
						 | 
					dd08b2e426 | ||
| 
						 | 
					285b1630ee | ||
| 
						 | 
					fdcaf9054f | ||
| 
						 | 
					65b5585797 | ||
| 
						 | 
					b31fdb202c | ||
| 
						 | 
					d13d906d11 | ||
| 
						 | 
					6a403ac916 | ||
| 
						 | 
					eff54e3202 | ||
| 
						 | 
					0a7dd7c3f7 | ||
| 
						 | 
					cf7f962ed1 | ||
| 
						 | 
					f412df29b5 | ||
| 
						 | 
					31204bae6a | ||
| 
						 | 
					a57cf08c00 | ||
| 
						 | 
					c0171156fa | ||
| 
						 | 
					a456e95139 | ||
| 
						 | 
					7f8e2d0f7f | ||
| 
						 | 
					d80aa68c40 | ||
| 
						 | 
					81c9090ec9 | ||
| 
						 | 
					0fa5c46f4b | ||
| 
						 | 
					d75977140a | ||
| 
						 | 
					b65440ba4e | ||
| 
						 | 
					ee15f8b8c2 | ||
| 
						 | 
					aebf8ba783 | ||
| 
						 | 
					9f2436b123 | ||
| 
						 | 
					cd774ea2df | ||
| 
						 | 
					007f54bc26 | ||
| 
						 | 
					9c03f3a9e3 | ||
| 
						 | 
					292365a837 | ||
| 
						 | 
					1091478e11 | ||
| 
						 | 
					47b94b3c5a | ||
| 
						 | 
					7cd62e7b26 | ||
| 
						 | 
					3397f2407a | ||
| 
						 | 
					52799659c8 | ||
| 
						 | 
					86e88942b0 | ||
| 
						 | 
					11592ebb98 | ||
| 
						 | 
					83f4bfc53d | ||
| 
						 | 
					43ed818015 | ||
| 
						 | 
					fd7f5b991a | ||
| 
						 | 
					feebcb339a | ||
| 
						 | 
					0368d4e435 | ||
| 
						 | 
					a57bad5bb9 | ||
| 
						 | 
					a0ee1a40d4 | ||
| 
						 | 
					5c5aa3551b | ||
| 
						 | 
					bd7daf4072 | ||
| 
						 | 
					dad844795f | ||
| 
						 | 
					1ef20f232a | ||
| 
						 | 
					78deaf8b38 | ||
| 
						 | 
					41107af0d0 | ||
| 
						 | 
					a1aec29ffd | ||
| 
						 | 
					07dc8617a4 | ||
| 
						 | 
					34cef1ae0a | ||
| 
						 | 
					144841d88d | ||
| 
						 | 
					b46a713968 | ||
| 
						 | 
					4ec7c30e28 | ||
| 
						 | 
					16c5825e3a | ||
| 
						 | 
					0f1129e51e | ||
| 
						 | 
					3e54201be8 | ||
| 
						 | 
					c34fba4c22 | ||
| 
						 | 
					625f8c7a2b | ||
| 
						 | 
					41a4a98c0a | ||
| 
						 | 
					c858d954a9 | ||
| 
						 | 
					aa0410edb3 | ||
| 
						 | 
					97cb61b7cf | ||
| 
						 | 
					0408d98538 | ||
| 
						 | 
					69e2f9640e | ||
| 
						 | 
					efd20dc370 | ||
| 
						 | 
					7a42598150 | ||
| 
						 | 
					7a45d96d9a | ||
| 
						 | 
					468a2553f8 | ||
| 
						 | 
					a4f7ccdba1 | ||
| 
						 | 
					a0b47aa4b3 | ||
| 
						 | 
					ee6dd54ab3 | ||
| 
						 | 
					518ca7cc9d | ||
| 
						 | 
					37053a40b7 | ||
| 
						 | 
					7eff8c9699 | ||
| 
						 | 
					49d9030bf4 | ||
| 
						 | 
					9e741c0348 | ||
| 
						 | 
					95dc3c1a6c | ||
| 
						 | 
					2fa7081f3f | ||
| 
						 | 
					288773a727 | ||
| 
						 | 
					06079115e6 | ||
| 
						 | 
					5db21677dc | ||
| 
						 | 
					5c7db88f10 | ||
| 
						 | 
					0060e81fae | ||
| 
						 | 
					1a6bf2d71b | ||
| 
						 | 
					59a6de92d0 | ||
| 
						 | 
					b7b013f669 | ||
| 
						 | 
					d8be1eca90 | ||
| 
						 | 
					d04f8965c3 | ||
| 
						 | 
					ffdbe6f4da | ||
| 
						 | 
					fafa915613 | ||
| 
						 | 
					f5f0af0dcd | ||
| 
						 | 
					23eb4d6b0b | ||
| 
						 | 
					f9d6020c4f | ||
| 
						 | 
					b9dfbdd5e8 | ||
| 
						 | 
					8f9d708285 | ||
| 
						 | 
					05b06d3eac | ||
| 
						 | 
					8b68ab8ac7 | ||
| 
						 | 
					80021d520f | ||
| 
						 | 
					363cfa1998 | ||
| 
						 | 
					9ea1a5cde6 | ||
| 
						 | 
					faeb6bf6b8 | ||
| 
						 | 
					1917b1346b | ||
| 
						 | 
					3feaf9221d | ||
| 
						 | 
					943b735150 | ||
| 
						 | 
					02ce04261d | ||
| 
						 | 
					eae5f4f5f9 | ||
| 
						 | 
					8ec8a02924 | ||
| 
						 | 
					12c34ef63d | ||
| 
						 | 
					a54848b636 | ||
| 
						 | 
					35c09940b4 | ||
| 
						 | 
					cb4fdaab28 | ||
| 
						 | 
					3501de22ed | ||
| 
						 | 
					1f59fccc97 | ||
| 
						 | 
					4307d23b00 | ||
| 
						 | 
					b83345c91a | ||
| 
						 | 
					76feb208bc | ||
| 
						 | 
					efa49593da | ||
| 
						 | 
					361d6fa22f | ||
| 
						 | 
					f7d1b8f972 | ||
| 
						 | 
					a9afc2dc2b | ||
| 
						 | 
					8d949b97ea | ||
| 
						 | 
					0d5a07ffe1 | ||
| 
						 | 
					11972c2511 | ||
| 
						 | 
					3081efebd8 | ||
| 
						 | 
					b27039dcc8 | ||
| 
						 | 
					847f107ac2 | ||
| 
						 | 
					ec9766a544 | ||
| 
						 | 
					7bdc148063 | ||
| 
						 | 
					7284e9f100 | ||
| 
						 | 
					03ecfbea25 | ||
| 
						 | 
					eb1716e078 | ||
| 
						 | 
					b11b8a2f22 | ||
| 
						 | 
					845bb37c8c | ||
| 
						 | 
					6f9f6495a0 | ||
| 
						 | 
					04ef327a86 | ||
| 
						 | 
					913b595587 | ||
| 
						 | 
					7628af35ba | ||
| 
						 | 
					cad8b7752b | ||
| 
						 | 
					7175546f54 | ||
| 
						 | 
					6186f46ec2 | ||
| 
						 | 
					2413867bf3 | ||
| 
						 | 
					545c539a08 | ||
| 
						 | 
					b0cfed809f | ||
| 
						 | 
					d5502e1527 | ||
| 
						 | 
					714d02060c | ||
| 
						 | 
					c8d0739692 | ||
| 
						 | 
					d4b9d61e2b | ||
| 
						 | 
					1f7f2f64ad | ||
| 
						 | 
					f26ca31dbc | ||
| 
						 | 
					92b6edc9a4 | ||
| 
						 | 
					e1a2b46333 | ||
| 
						 | 
					5744905f5a | ||
| 
						 | 
					d7c27150d3 | ||
| 
						 | 
					76a8260f1c | ||
| 
						 | 
					0d8f43dba2 | ||
| 
						 | 
					104c07cf6d | ||
| 
						 | 
					43f244a076 | ||
| 
						 | 
					e4bc41ed56 | ||
| 
						 | 
					1c2275537d | ||
| 
						 | 
					a062ff084e | ||
| 
						 | 
					7a78cd33eb | ||
| 
						 | 
					ff2dff5a51 | ||
| 
						 | 
					d122b86913 | ||
| 
						 | 
					43e45f7c28 | ||
| 
						 | 
					ba93725f62 | ||
| 
						 | 
					c32f0dfb02 | ||
| 
						 | 
					73dcd49d92 | ||
| 
						 | 
					56c2640900 | ||
| 
						 | 
					b33c52616d | ||
| 
						 | 
					7edc427ea7 | ||
| 
						 | 
					3c8549b872 | ||
| 
						 | 
					471b992d2d | ||
| 
						 | 
					ab2ed7492b | ||
| 
						 | 
					330cb7552c | ||
| 
						 | 
					b31fb67eda | ||
| 
						 | 
					874b8a5510 | ||
| 
						 | 
					624899b65c | ||
| 
						 | 
					d0bc6b96c4 | ||
| 
						 | 
					1781e58189 | ||
| 
						 | 
					9e536b5235 | ||
| 
						 | 
					208956d5c6 | ||
| 
						 | 
					60aba09614 | ||
| 
						 | 
					da1c3346d1 | ||
| 
						 | 
					ea4ee0d0f6 | ||
| 
						 | 
					d940bebb90 | ||
| 
						 | 
					77c6ce8a1e | ||
| 
						 | 
					98c761c375 | ||
| 
						 | 
					7166ad2ce7 | ||
| 
						 | 
					7f24aee8fa | ||
| 
						 | 
					8b16c08baa | ||
| 
						 | 
					f7045d6b40 | ||
| 
						 | 
					6b64b02192 | ||
| 
						 | 
					43f37a6e12 | ||
| 
						 | 
					9fc6d4efee | ||
| 
						 | 
					ac375e468d | ||
| 
						 | 
					1c8ce086df | ||
| 
						 | 
					8b73e4b232 | ||
| 
						 | 
					7c10d83b6b | ||
| 
						 | 
					99259cc6c5 | ||
| 
						 | 
					8062bb8bf7 | ||
| 
						 | 
					0bb51d2ac0 | ||
| 
						 | 
					cd9a30be4d | ||
| 
						 | 
					98fd924bd1 | ||
| 
						 | 
					20e0fe860f | ||
| 
						 | 
					10d87dab92 | ||
| 
						 | 
					cfb7ad21a2 | ||
| 
						 | 
					cc90306052 | ||
| 
						 | 
					b8f781b890 | ||
| 
						 | 
					f4af3da4c2 | ||
| 
						 | 
					a3f4143a67 | ||
| 
						 | 
					b8c1a35c3a | ||
| 
						 | 
					cd9345a54f | ||
| 
						 | 
					159d8112da | ||
| 
						 | 
					fc58822dd8 | ||
| 
						 | 
					ce4c47f568 | ||
| 
						 | 
					2d026fbcd8 | ||
| 
						 | 
					79f1a75a96 | ||
| 
						 | 
					b5a1da8649 | ||
| 
						 | 
					87511d39e7 | ||
| 
						 | 
					f0921a9bee | ||
| 
						 | 
					d136b77b43 | ||
| 
						 | 
					b2b29fe00e | ||
| 
						 | 
					5e1e6c964f | ||
| 
						 | 
					c3a4b97ba9 | ||
| 
						 | 
					4cb39e3ebc | ||
| 
						 | 
					2be1301542 | ||
| 
						 | 
					83f54c3203 | ||
| 
						 | 
					d7ddd4a491 | ||
| 
						 | 
					090fc89b75 | ||
| 
						 | 
					e5fad8efa5 | ||
| 
						 | 
					7fa0266545 | ||
| 
						 | 
					a4821577d8 | ||
| 
						 | 
					9f67845ba2 | ||
| 
						 | 
					f9bc2f3e99 | ||
| 
						 | 
					8bba101ef7 | ||
| 
						 | 
					cc6cf3bdd4 | ||
| 
						 | 
					b1685ad765 | ||
| 
						 | 
					8837b23e79 | 
							
								
								
									
										183
									
								
								.clang-format
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								.clang-format
									
									
									
									
									
								
							@@ -1,7 +1,178 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
BasedOnStyle: LLVM
 | 
					 | 
				
			||||||
TabWidth:     4
 | 
					 | 
				
			||||||
IndentWidth:  4
 | 
					 | 
				
			||||||
UseTab:       Always
 | 
					 | 
				
			||||||
ColumnLimit:  100
 | 
					 | 
				
			||||||
Language:        Cpp
 | 
					Language:        Cpp
 | 
				
			||||||
 | 
					# BasedOnStyle:  LLVM
 | 
				
			||||||
 | 
					AccessModifierOffset: -2
 | 
				
			||||||
 | 
					AlignAfterOpenBracket: Align
 | 
				
			||||||
 | 
					AlignArrayOfStructures: None
 | 
				
			||||||
 | 
					AlignConsecutiveMacros: None
 | 
				
			||||||
 | 
					AlignConsecutiveAssignments: None
 | 
				
			||||||
 | 
					AlignConsecutiveBitFields: None
 | 
				
			||||||
 | 
					AlignConsecutiveDeclarations: None
 | 
				
			||||||
 | 
					AlignEscapedNewlines: Right
 | 
				
			||||||
 | 
					AlignOperands:   Align
 | 
				
			||||||
 | 
					AlignTrailingComments: true
 | 
				
			||||||
 | 
					AllowAllArgumentsOnNextLine: true
 | 
				
			||||||
 | 
					AllowAllConstructorInitializersOnNextLine: true
 | 
				
			||||||
 | 
					AllowAllParametersOfDeclarationOnNextLine: true
 | 
				
			||||||
 | 
					AllowShortEnumsOnASingleLine: true
 | 
				
			||||||
 | 
					AllowShortBlocksOnASingleLine: Never
 | 
				
			||||||
 | 
					AllowShortCaseLabelsOnASingleLine: false
 | 
				
			||||||
 | 
					AllowShortFunctionsOnASingleLine: All
 | 
				
			||||||
 | 
					AllowShortLambdasOnASingleLine: All
 | 
				
			||||||
 | 
					AllowShortIfStatementsOnASingleLine: Never
 | 
				
			||||||
 | 
					AllowShortLoopsOnASingleLine: false
 | 
				
			||||||
 | 
					AlwaysBreakAfterDefinitionReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakAfterReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakBeforeMultilineStrings: false
 | 
				
			||||||
 | 
					AlwaysBreakTemplateDeclarations: MultiLine
 | 
				
			||||||
 | 
					AttributeMacros:
 | 
				
			||||||
 | 
					  - __capability
 | 
				
			||||||
 | 
					BinPackArguments: true
 | 
				
			||||||
 | 
					BinPackParameters: true
 | 
				
			||||||
 | 
					BraceWrapping:
 | 
				
			||||||
 | 
					  AfterCaseLabel:  false
 | 
				
			||||||
 | 
					  AfterClass:      false
 | 
				
			||||||
 | 
					  AfterControlStatement: Never
 | 
				
			||||||
 | 
					  AfterEnum:       false
 | 
				
			||||||
 | 
					  AfterFunction:   false
 | 
				
			||||||
 | 
					  AfterNamespace:  false
 | 
				
			||||||
 | 
					  AfterObjCDeclaration: false
 | 
				
			||||||
 | 
					  AfterStruct:     false
 | 
				
			||||||
 | 
					  AfterUnion:      false
 | 
				
			||||||
 | 
					  AfterExternBlock: false
 | 
				
			||||||
 | 
					  BeforeCatch:     false
 | 
				
			||||||
 | 
					  BeforeElse:      false
 | 
				
			||||||
 | 
					  BeforeLambdaBody: false
 | 
				
			||||||
 | 
					  BeforeWhile:     false
 | 
				
			||||||
 | 
					  IndentBraces:    false
 | 
				
			||||||
 | 
					  SplitEmptyFunction: true
 | 
				
			||||||
 | 
					  SplitEmptyRecord: true
 | 
				
			||||||
 | 
					  SplitEmptyNamespace: true
 | 
				
			||||||
 | 
					BreakBeforeBinaryOperators: None
 | 
				
			||||||
 | 
					BreakBeforeConceptDeclarations: true
 | 
				
			||||||
 | 
					BreakBeforeBraces: Attach
 | 
				
			||||||
 | 
					BreakBeforeInheritanceComma: false
 | 
				
			||||||
 | 
					BreakInheritanceList: BeforeColon
 | 
				
			||||||
 | 
					BreakBeforeTernaryOperators: true
 | 
				
			||||||
 | 
					BreakConstructorInitializersBeforeComma: false
 | 
				
			||||||
 | 
					BreakConstructorInitializers: BeforeColon
 | 
				
			||||||
 | 
					BreakAfterJavaFieldAnnotations: false
 | 
				
			||||||
 | 
					BreakStringLiterals: true
 | 
				
			||||||
 | 
					ColumnLimit:     100
 | 
				
			||||||
 | 
					CommentPragmas:  '^ IWYU pragma:'
 | 
				
			||||||
 | 
					CompactNamespaces: false
 | 
				
			||||||
 | 
					ConstructorInitializerAllOnOneLineOrOnePerLine: false
 | 
				
			||||||
 | 
					ConstructorInitializerIndentWidth: 4
 | 
				
			||||||
 | 
					ContinuationIndentWidth: 4
 | 
				
			||||||
 | 
					Cpp11BracedListStyle: true
 | 
				
			||||||
 | 
					DeriveLineEnding: true
 | 
				
			||||||
 | 
					DerivePointerAlignment: false
 | 
				
			||||||
 | 
					DisableFormat:   false
 | 
				
			||||||
 | 
					EmptyLineAfterAccessModifier: Never
 | 
				
			||||||
 | 
					EmptyLineBeforeAccessModifier: LogicalBlock
 | 
				
			||||||
 | 
					ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
 | 
					FixNamespaceComments: true
 | 
				
			||||||
 | 
					ForEachMacros:
 | 
				
			||||||
 | 
					  - foreach
 | 
				
			||||||
 | 
					  - Q_FOREACH
 | 
				
			||||||
 | 
					  - BOOST_FOREACH
 | 
				
			||||||
 | 
					IfMacros:
 | 
				
			||||||
 | 
					  - KJ_IF_MAYBE
 | 
				
			||||||
 | 
					IncludeBlocks:   Preserve
 | 
				
			||||||
 | 
					IncludeCategories:
 | 
				
			||||||
 | 
					  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
 | 
				
			||||||
 | 
					    Priority:        2
 | 
				
			||||||
 | 
					    SortPriority:    0
 | 
				
			||||||
 | 
					    CaseSensitive:   false
 | 
				
			||||||
 | 
					  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
 | 
				
			||||||
 | 
					    Priority:        3
 | 
				
			||||||
 | 
					    SortPriority:    0
 | 
				
			||||||
 | 
					    CaseSensitive:   false
 | 
				
			||||||
 | 
					  - Regex:           '.*'
 | 
				
			||||||
 | 
					    Priority:        1
 | 
				
			||||||
 | 
					    SortPriority:    0
 | 
				
			||||||
 | 
					    CaseSensitive:   false
 | 
				
			||||||
 | 
					IncludeIsMainRegex: '(Test)?$'
 | 
				
			||||||
 | 
					IncludeIsMainSourceRegex: ''
 | 
				
			||||||
 | 
					IndentAccessModifiers: false
 | 
				
			||||||
 | 
					IndentCaseLabels: false
 | 
				
			||||||
 | 
					IndentCaseBlocks: false
 | 
				
			||||||
 | 
					IndentGotoLabels: true
 | 
				
			||||||
 | 
					IndentPPDirectives: None
 | 
				
			||||||
 | 
					IndentExternBlock: AfterExternBlock
 | 
				
			||||||
 | 
					IndentRequires:  false
 | 
				
			||||||
 | 
					IndentWidth:     4
 | 
				
			||||||
 | 
					IndentWrappedFunctionNames: false
 | 
				
			||||||
 | 
					InsertTrailingCommas: None
 | 
				
			||||||
 | 
					JavaScriptQuotes: Leave
 | 
				
			||||||
 | 
					JavaScriptWrapImports: true
 | 
				
			||||||
 | 
					KeepEmptyLinesAtTheStartOfBlocks: true
 | 
				
			||||||
 | 
					LambdaBodyIndentation: Signature
 | 
				
			||||||
 | 
					MacroBlockBegin: ''
 | 
				
			||||||
 | 
					MacroBlockEnd:   ''
 | 
				
			||||||
 | 
					MaxEmptyLinesToKeep: 1
 | 
				
			||||||
 | 
					NamespaceIndentation: All
 | 
				
			||||||
 | 
					ObjCBinPackProtocolList: Auto
 | 
				
			||||||
 | 
					ObjCBlockIndentWidth: 2
 | 
				
			||||||
 | 
					ObjCBreakBeforeNestedBlockParam: true
 | 
				
			||||||
 | 
					ObjCSpaceAfterProperty: false
 | 
				
			||||||
 | 
					ObjCSpaceBeforeProtocolList: true
 | 
				
			||||||
 | 
					PenaltyBreakAssignment: 2
 | 
				
			||||||
 | 
					PenaltyBreakBeforeFirstCallParameter: 19
 | 
				
			||||||
 | 
					PenaltyBreakComment: 300
 | 
				
			||||||
 | 
					PenaltyBreakFirstLessLess: 120
 | 
				
			||||||
 | 
					PenaltyBreakString: 1000
 | 
				
			||||||
 | 
					PenaltyBreakTemplateDeclaration: 10
 | 
				
			||||||
 | 
					PenaltyExcessCharacter: 1000000
 | 
				
			||||||
 | 
					PenaltyReturnTypeOnItsOwnLine: 60
 | 
				
			||||||
 | 
					PenaltyIndentedWhitespace: 0
 | 
				
			||||||
 | 
					PointerAlignment: Right
 | 
				
			||||||
 | 
					PPIndentWidth:   -1
 | 
				
			||||||
 | 
					ReferenceAlignment: Pointer
 | 
				
			||||||
 | 
					ReflowComments:  true
 | 
				
			||||||
 | 
					ShortNamespaceLines: 1
 | 
				
			||||||
 | 
					SortIncludes:    CaseSensitive
 | 
				
			||||||
 | 
					SortJavaStaticImport: Before
 | 
				
			||||||
 | 
					SortUsingDeclarations: true
 | 
				
			||||||
 | 
					SpaceAfterCStyleCast: false
 | 
				
			||||||
 | 
					SpaceAfterLogicalNot: false
 | 
				
			||||||
 | 
					SpaceAfterTemplateKeyword: true
 | 
				
			||||||
 | 
					SpaceBeforeAssignmentOperators: true
 | 
				
			||||||
 | 
					SpaceBeforeCaseColon: false
 | 
				
			||||||
 | 
					SpaceBeforeCpp11BracedList: false
 | 
				
			||||||
 | 
					SpaceBeforeCtorInitializerColon: true
 | 
				
			||||||
 | 
					SpaceBeforeInheritanceColon: true
 | 
				
			||||||
 | 
					SpaceBeforeParens: ControlStatements
 | 
				
			||||||
 | 
					SpaceAroundPointerQualifiers: Default
 | 
				
			||||||
 | 
					SpaceBeforeRangeBasedForLoopColon: true
 | 
				
			||||||
 | 
					SpaceInEmptyBlock: false
 | 
				
			||||||
 | 
					SpaceInEmptyParentheses: false
 | 
				
			||||||
 | 
					SpacesBeforeTrailingComments: 1
 | 
				
			||||||
 | 
					SpacesInAngles:  Never
 | 
				
			||||||
 | 
					SpacesInConditionalStatement: false
 | 
				
			||||||
 | 
					SpacesInContainerLiterals: true
 | 
				
			||||||
 | 
					SpacesInCStyleCastParentheses: false
 | 
				
			||||||
 | 
					SpacesInLineCommentPrefix:
 | 
				
			||||||
 | 
					  Minimum:         1
 | 
				
			||||||
 | 
					  Maximum:         -1
 | 
				
			||||||
 | 
					SpacesInParentheses: false
 | 
				
			||||||
 | 
					SpacesInSquareBrackets: false
 | 
				
			||||||
 | 
					SpaceBeforeSquareBrackets: false
 | 
				
			||||||
 | 
					BitFieldColonSpacing: Both
 | 
				
			||||||
 | 
					Standard:        Latest
 | 
				
			||||||
 | 
					StatementAttributeLikeMacros:
 | 
				
			||||||
 | 
					  - Q_EMIT
 | 
				
			||||||
 | 
					StatementMacros:
 | 
				
			||||||
 | 
					  - Q_UNUSED
 | 
				
			||||||
 | 
					  - QT_REQUIRE_VERSION
 | 
				
			||||||
 | 
					TabWidth:        4
 | 
				
			||||||
 | 
					UseCRLF:         false
 | 
				
			||||||
 | 
					UseTab:          Always
 | 
				
			||||||
 | 
					WhitespaceSensitiveMacros:
 | 
				
			||||||
 | 
					  - STRINGIZE
 | 
				
			||||||
 | 
					  - PP_STRINGIZE
 | 
				
			||||||
 | 
					  - BOOST_PP_STRINGIZE
 | 
				
			||||||
 | 
					  - NS_SWIFT_NAME
 | 
				
			||||||
 | 
					  - CF_SWIFT_NAME
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -27,7 +27,7 @@ jobs:
 | 
				
			|||||||
      DOCKER_REGISTRY_USERNAME: ucentral
 | 
					      DOCKER_REGISTRY_USERNAME: ucentral
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
@@ -58,10 +58,10 @@ jobs:
 | 
				
			|||||||
    - name: Get base branch name and set as output
 | 
					    - name: Get base branch name and set as output
 | 
				
			||||||
      id: get_base_branch
 | 
					      id: get_base_branch
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')
 | 
					        echo "branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')" >> $GITHUB_OUTPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
@@ -85,7 +85,7 @@ jobs:
 | 
				
			|||||||
      - docker
 | 
					      - docker
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,7 +11,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout actions repo
 | 
					      - name: Checkout actions repo
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          repository: Telecominfraproject/.github
 | 
					          repository: Telecominfraproject/.github
 | 
				
			||||||
          path: github
 | 
					          path: github
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										41
									
								
								.github/workflows/openapi-pages.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								.github/workflows/openapi-pages.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					name: Update OpenAPI docs on GitHub Pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - 'openapi/**'
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - master
 | 
				
			||||||
 | 
					  workflow_dispatch:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaults:
 | 
				
			||||||
 | 
					  run:
 | 
				
			||||||
 | 
					    shell: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  docsgen:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Generate static HTML page with docs from OpenAPI definition
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml -g html2 --skip-validate-spec -o /local/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Update OpenAPI docs
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          mkdir tmp-docs
 | 
				
			||||||
 | 
					          mv index.html tmp-docs/index.html
 | 
				
			||||||
 | 
					          mkdir -p ~/.ssh
 | 
				
			||||||
 | 
					          ssh-keyscan -H github.com >> ~/.ssh/known_hosts
 | 
				
			||||||
 | 
					          echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
 | 
				
			||||||
 | 
					          git config --global credential.helper store
 | 
				
			||||||
 | 
					          git config --global user.email "tip-automation@telecominfraproject.com"
 | 
				
			||||||
 | 
					          git config --global user.name "TIP Automation User"
 | 
				
			||||||
 | 
					          git pull
 | 
				
			||||||
 | 
					          git checkout gh-pages || git checkout -b gh-pages
 | 
				
			||||||
 | 
					          rm -rf docs
 | 
				
			||||||
 | 
					          mv tmp-docs docs
 | 
				
			||||||
 | 
					          git add docs
 | 
				
			||||||
 | 
					          git commit -m'Update OpenAPI docs for GitHub pages'
 | 
				
			||||||
 | 
					          git push --set-upstream origin gh-pages
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,7 +17,7 @@ jobs:
 | 
				
			|||||||
      HELM_REPO_USERNAME: ucentral
 | 
					      HELM_REPO_USERNAME: ucentral
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout uCentral assembly chart repo
 | 
					      - name: Checkout uCentral assembly chart repo
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: wlan-cloud-ucentralgw
 | 
					          path: wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.idea/ucentral.iml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/ucentral.iml
									
									
									
										generated
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
				
			|||||||
<module classpath="CMake" type="CPP_MODULE" version="4">
 | 
					<module classpath="CMake" type="CPP_MODULE" version="4">
 | 
				
			||||||
  <component name="FacetManager">
 | 
					  <component name="FacetManager">
 | 
				
			||||||
    <facet type="Python" name="Python facet">
 | 
					    <facet type="Python" name="Python facet">
 | 
				
			||||||
      <configuration sdkName="Python 3.9 (venv)" />
 | 
					      <configuration sdkName="Python 3.9 (wlan-cloud-ucentralgw)" />
 | 
				
			||||||
    </facet>
 | 
					    </facet>
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
</module>
 | 
					</module>
 | 
				
			||||||
							
								
								
									
										1
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							@@ -2,5 +2,6 @@
 | 
				
			|||||||
<project version="4">
 | 
					<project version="4">
 | 
				
			||||||
  <component name="VcsDirectoryMappings">
 | 
					  <component name="VcsDirectoryMappings">
 | 
				
			||||||
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
 | 
					    <mapping directory="$PROJECT_DIR$" vcs="Git" />
 | 
				
			||||||
 | 
					    <mapping directory="$PROJECT_DIR$/cmake-build-debug/rapidjson-test" vcs="Git" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
</project>
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										190
									
								
								BUILDING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								BUILDING.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					# Building from source
 | 
				
			||||||
 | 
					In order to build the OWGW, you will need to install its dependencies, which includes the following:
 | 
				
			||||||
 | 
					- cmake
 | 
				
			||||||
 | 
					- boost
 | 
				
			||||||
 | 
					- POCO 1.10.1 or later
 | 
				
			||||||
 | 
					- a C++17 compiler
 | 
				
			||||||
 | 
					- openssl
 | 
				
			||||||
 | 
					- libpq-dev (PortgreSQL development libraries)
 | 
				
			||||||
 | 
					- mysql-client (MySQL client)
 | 
				
			||||||
 | 
					- librdkafka
 | 
				
			||||||
 | 
					- cppkafka
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
 | 
				
			||||||
 | 
					framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
 | 
				
			||||||
 | 
					from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building
 | 
				
			||||||
 | 
					Poco may take several minutes depending on the platform you are building on.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Ubuntu
 | 
				
			||||||
 | 
					These instructions have proven to work on Ubuntu 20.4.
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sudo apt install git cmake g++ libssl-dev libmariadb-dev 
 | 
				
			||||||
 | 
					sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
 | 
				
			||||||
 | 
					sudo apt install librdkafka-dev // default-libmysqlclient-dev
 | 
				
			||||||
 | 
					sudo apt install nlohmann-json-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
 | 
				
			||||||
 | 
					cd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
				
			||||||
 | 
					cd cppkafka
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/valijson --branch tip-v1
 | 
				
			||||||
 | 
					cd valijson
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
 | 
				
			||||||
 | 
					cd fmtlib
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					make install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					cd wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make -j 8
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Fedora
 | 
				
			||||||
 | 
					The following instructions have proven to work on Fedora 33
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
 | 
				
			||||||
 | 
					sudo yum install yaml-cpp-devel lua-devel 
 | 
				
			||||||
 | 
					sudo dnf install postgresql.x86_64 librdkafka-devel
 | 
				
			||||||
 | 
					sudo dnf install postgresql-devel json-devel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
 | 
				
			||||||
 | 
					cd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
				
			||||||
 | 
					cd cppkafka
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/valijson --branch tip-v1
 | 
				
			||||||
 | 
					cd valijson
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					cd wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## macOS Build
 | 
				
			||||||
 | 
					The following instructions have proven to work on macOS Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					brew install openssl \
 | 
				
			||||||
 | 
						cmake \
 | 
				
			||||||
 | 
						libpq \
 | 
				
			||||||
 | 
						mysql-client \
 | 
				
			||||||
 | 
						apr \
 | 
				
			||||||
 | 
						apr-util \
 | 
				
			||||||
 | 
						boost \
 | 
				
			||||||
 | 
						yaml-cpp \
 | 
				
			||||||
 | 
						postgresql \
 | 
				
			||||||
 | 
						librdkafka \
 | 
				
			||||||
 | 
						nlohmann-json \
 | 
				
			||||||
 | 
						fmt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/poco --branch poco-tip-v2
 | 
				
			||||||
 | 
					pushd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					push cmake-build
 | 
				
			||||||
 | 
					cmake -DOPENSSL_ROOT_DIR=</path/to/openssl> -DENABLE_NETSSL=1 -DENABLE_JWT=1 -DENABLE_CRYPTO=1 ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
				
			||||||
 | 
					pushd cppkafka
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					pushd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/AriliaWireless/valijson --branch tip-v1
 | 
				
			||||||
 | 
					cd valijson
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					pushd wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					pushd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make -j
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Raspberry
 | 
				
			||||||
 | 
					The build on a rPI takes a while. You can shorten that build time and requirements by disabling all the larger database
 | 
				
			||||||
 | 
					support. You can build with only SQLite support by not installing the packages for PostgreSQL, and MySQL by
 | 
				
			||||||
 | 
					adding -DSMALL_BUILD=1 on the cmake build line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev libboost-all-dev libyaml-cpp-dev
 | 
				
			||||||
 | 
					git clone https://github.com/stephb9959/poco
 | 
				
			||||||
 | 
					cd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd ~
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					cd wlan-cloud-ucentralgw
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake -DSMALL_BUILD=1 ..
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										77
									
								
								CLI.md
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								CLI.md
									
									
									
									
									
								
							@@ -7,139 +7,139 @@ cli help
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## The commands
 | 
					## The commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### getdevice <serial>                
 | 
					### getdevice `serial`                
 | 
				
			||||||
Get the device JSON document.
 | 
					Get the device JSON document.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### deletedevice <serial>             
 | 
					### deletedevice `serial`             
 | 
				
			||||||
Delete the device.
 | 
					Delete the device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### createdevice <serial> <cfg> <MAC> 
 | 
					### createdevice `serial` `cfg` `MAC` 
 | 
				
			||||||
Create a device using the default configuration. 
 | 
					Create a device using the default configuration. 
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `cfg`: JSON config file name
 | 
					- `cfg`: JSON config file name
 | 
				
			||||||
- `MAC`: string MAC Address
 | 
					- `MAC`: string MAC Address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### getdevicestatus <serial>
 | 
					### getdevicestatus `serial`
 | 
				
			||||||
Get the device status JSON document.
 | 
					Get the device status JSON document.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### getstats <serial>
 | 
					### getstats `serial`
 | 
				
			||||||
Get statistics for the device.
 | 
					Get statistics for the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### gethealthchecks <serial>
 | 
					### gethealthchecks `serial`
 | 
				
			||||||
Get healthchecks for a device.
 | 
					Get healthchecks for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### newesthealthchecks <serial>
 | 
					### newesthealthchecks `serial`
 | 
				
			||||||
Get newest healthchecks for a device.
 | 
					Get newest healthchecks for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### lasthealthcheck <serial>
 | 
					### lasthealthcheck `serial`
 | 
				
			||||||
Get the last healthcheck
 | 
					Get the last healthcheck
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### getcapababilities <serial>
 | 
					### getcapababilities `serial`
 | 
				
			||||||
Get the device capabilities JSON document.
 | 
					Get the device capabilities JSON document.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### deletecapababilities <serial>
 | 
					### deletecapababilities `serial`
 | 
				
			||||||
Delete the device capabilities JSON.
 | 
					Delete the device capabilities JSON.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### reboot <serial>                   
 | 
					### reboot `serial`                   
 | 
				
			||||||
Reboot the device.
 | 
					Reboot the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### upgrade <serial> <URI> 
 | 
					### upgrade `serial` `URI` 
 | 
				
			||||||
Do firmware upgrade for a device.
 | 
					Do firmware upgrade for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `URI`: complete URI where the upgrade file exists. No validation is performed.
 | 
					- `URI`: complete URI where the upgrade file exists. No validation is performed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### leds <serial> <pattern> <duration>       
 | 
					### leds `serial` `pattern` `duration`       
 | 
				
			||||||
Activate LEDs a device.
 | 
					Activate LEDs a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `pattern`: on/off/blink
 | 
					- `pattern`: on/off/blink
 | 
				
			||||||
- `duration`: number in seconds
 | 
					- `duration`: number in seconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### configure <serial> <cfg>          
 | 
					### configure `serial` `cfg`          
 | 
				
			||||||
Change configuration for a device.
 | 
					Change configuration for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `cfg`: JSON config file name
 | 
					- `cfg`: JSON config file name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### factory <serial> <keep_redirector>     
 | 
					### factory `serial` `keep_redirector`     
 | 
				
			||||||
Do factory reset for device. 
 | 
					Do factory reset for device. 
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `keep_redirector`: true=keep redirector, false=reset redirector
 | 
					- `keep_redirector`: true=keep redirector, false=reset redirector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### request <serial> <message>        
 | 
					### request `serial` `message`        
 | 
				
			||||||
Force a message from the device.
 | 
					Force a message from the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `message`: state or healthcheck
 | 
					- `message`: state or healthcheck
 | 
				
			||||||
                                 
 | 
					                                 
 | 
				
			||||||
### wifiscan <serial> <verbose>       
 | 
					### wifiscan `serial` `verbose`       
 | 
				
			||||||
Do wifiscan for a device.
 | 
					Do wifiscan for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `verbose`: verbose=true/false
 | 
					- `verbose`: verbose=true/false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### telemetry <serial>
 | 
					### telemetry `serial`
 | 
				
			||||||
Start `telemetry` stream for a device.
 | 
					Start `telemetry` stream for a device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### trace <serial> <duration> <network>            
 | 
					### trace `serial` `duration` `network`            
 | 
				
			||||||
Launch a remote trace for a device.
 | 
					Launch a remote trace for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
- `duration`: number in seconds
 | 
					- `duration`: number in seconds
 | 
				
			||||||
- `network`: which network to perform trace on: lan or wan  
 | 
					- `network`: which network to perform trace on: lan or wan  
 | 
				
			||||||
                                  
 | 
					                                  
 | 
				
			||||||
### getcommand <command-uuid>
 | 
					### getcommand `command-uuid`
 | 
				
			||||||
Get the command JSON document.
 | 
					Get the command JSON document.
 | 
				
			||||||
- `command-uuid`: command UUID
 | 
					- `command-uuid`: command UUID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### deletecommand <command-uuid>      
 | 
					### deletecommand `command-uuid`      
 | 
				
			||||||
Delete the command.
 | 
					Delete the command.
 | 
				
			||||||
- `command-uuid`: command UUID
 | 
					- `command-uuid`: command UUID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### newestcommands <serial>
 | 
					### newestcommands `serial`
 | 
				
			||||||
Get the newest commands for a device.
 | 
					Get the newest commands for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### listdevices
 | 
					### listdevices
 | 
				
			||||||
List devices.
 | 
					List devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### listcommands <serial>
 | 
					### listcommands `serial`
 | 
				
			||||||
List commands for a specific device.
 | 
					List commands for a specific device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### deletecommands <serial>
 | 
					### deletecommands `serial`
 | 
				
			||||||
Delete commands for a device.
 | 
					Delete commands for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### getlogs <serial>                  
 | 
					### getlogs `serial`                  
 | 
				
			||||||
Get logs for the device.
 | 
					Get logs for the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### newestlogs <serial>               
 | 
					### newestlogs `serial`               
 | 
				
			||||||
Get the latest logs for the device.
 | 
					Get the latest logs for the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### deletelogs <serial>               
 | 
					### deletelogs `serial`               
 | 
				
			||||||
Delete logs for the device.
 | 
					Delete logs for the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### eventqueue <serial>
 | 
					### eventqueue `serial`
 | 
				
			||||||
Request event queue for the device.
 | 
					Request event queue for the device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### listdefaultconfigs
 | 
					### listdefaultconfigs
 | 
				
			||||||
List default configurations.
 | 
					List default configurations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### createdefaultconfig <name> <ids> <cfg> 
 | 
					### createdefaultconfig `name` `ids` `cfg` 
 | 
				
			||||||
Create a default configuration
 | 
					Create a default configuration
 | 
				
			||||||
- `name`: unique name, no spaces
 | 
					- `name`: unique name, no spaces
 | 
				
			||||||
- `ids`: comma separated list of models
 | 
					- `ids`: comma separated list of models
 | 
				
			||||||
- `cfg`: JSON config file name
 | 
					- `cfg`: JSON config file name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### addblacklistdevice <serial> <reason>   
 | 
					### addblacklistdevice `serial` `reason`   
 | 
				
			||||||
Add a device to the black list
 | 
					Add a device to the black list
 | 
				
			||||||
- `serial`: serial number of the device to add
 | 
					- `serial`: serial number of the device to add
 | 
				
			||||||
- `reason`: reason for blacklisting
 | 
					- `reason`: reason for blacklisting
 | 
				
			||||||
@@ -147,7 +147,7 @@ Add a device to the black list
 | 
				
			|||||||
### getblacklist
 | 
					### getblacklist
 | 
				
			||||||
List all blacklisted devices
 | 
					List all blacklisted devices
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### deleteblacklistdevice  <serial>   
 | 
					### deleteblacklistdevice  `serial`   
 | 
				
			||||||
Add a device to the black list.
 | 
					Add a device to the black list.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -157,7 +157,7 @@ Get the number of devices in the DB.
 | 
				
			|||||||
### deviceserialnumbers               
 | 
					### deviceserialnumbers               
 | 
				
			||||||
Get only the serial numbers.
 | 
					Get only the serial numbers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### selectdevices <serial_list>       
 | 
					### selectdevices `serial_list`       
 | 
				
			||||||
Get a list of devices based on a list.
 | 
					Get a list of devices based on a list.
 | 
				
			||||||
- `serial_list`: serial numbers (must be comma separated).
 | 
					- `serial_list`: serial numbers (must be comma separated).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -179,27 +179,30 @@ Get the list of subsystems.
 | 
				
			|||||||
### systeminfo
 | 
					### systeminfo
 | 
				
			||||||
Get basic system information.
 | 
					Get basic system information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### reloadsubsystem <subsystem name>
 | 
					### reloadsubsystem `subsystem name`
 | 
				
			||||||
Reload the configuration for a subsystem.### getfile <uuid>					  
 | 
					Reload the configuration for a subsystem.### getfile <uuid>					  
 | 
				
			||||||
Get the file associated with trace command <uuid>.
 | 
					Get the file associated with trace command <uuid>.
 | 
				
			||||||
- `uuid`: UUID of file to retrieve
 | 
					- `uuid`: UUID of file to retrieve
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### rtty <serial>					  
 | 
					### rtty `serial number`					  
 | 
				
			||||||
Get the details for an rtty session.
 | 
					Get the details for an rtty session.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### lifetimestats <serial>			  
 | 
					### lifetimestats `serial number`			  
 | 
				
			||||||
Get the lifetime stats counters for a device
 | 
					Get the lifetime stats counters for a device
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### laststats <serial>			      
 | 
					### laststats `serial number`			      
 | 
				
			||||||
Get the last statistics for a device.
 | 
					Get the last statistics for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### neweststats <serial>			  
 | 
					### neweststats `serial number`			  
 | 
				
			||||||
Get the newest statistics for a device.
 | 
					Get the newest statistics for a device.
 | 
				
			||||||
- `serial`: device serial number
 | 
					- `serial`: device serial number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### deviceping `serial number`
 | 
				
			||||||
 | 
					This will return you the end-to-end latency from command-line to return value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Notes
 | 
					## Notes
 | 
				
			||||||
To pass additional flags to the CURL command, create an environment variable called FLAGS and git ve the values you
 | 
					To pass additional flags to the CURL command, create an environment variable called FLAGS and git ve the values you
 | 
				
			||||||
want. For example, for force all call to use IPv6, set FLAGS=\"-6\", for verbose mode and IPv6, set FLAGS=\"-6 -v\"
 | 
					want. For example, for force all call to use IPv6, set FLAGS=\"-6\", for verbose mode and IPv6, set FLAGS=\"-6 -v\"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										112
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								CMakeLists.txt
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.13)
 | 
					cmake_minimum_required(VERSION 3.13)
 | 
				
			||||||
project(owgw VERSION 2.7.0)
 | 
					project(owgw VERSION 3.0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_STANDARD 17)
 | 
					set(CMAKE_CXX_STANDARD 17)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,23 +39,23 @@ endif()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
find_package(Git QUIET)
 | 
					find_package(Git QUIET)
 | 
				
			||||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
 | 
					if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
 | 
				
			||||||
    execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
 | 
					    execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
 | 
				
			||||||
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
					            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
				
			||||||
            RESULT_VARIABLE GIT_RESULT
 | 
					            RESULT_VARIABLE GIT_RESULT
 | 
				
			||||||
            OUTPUT_VARIABLE GIT_HASH)
 | 
					            OUTPUT_VARIABLE GIT_HASH)
 | 
				
			||||||
    if(NOT GIT_RESULT EQUAL "0")
 | 
					    if(NOT GIT_RESULT EQUAL "0")
 | 
				
			||||||
        message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
 | 
					        message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
 | 
				
			||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
    string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
 | 
					    string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1")
 | 
					add_definitions(-DTIP_GATEWAY_SERVICE="1" -DPOCO_LOG_DEBUG="1" -DBOOST_NO_CXX98_FUNCTION_BASE=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
find_package(OpenSSL REQUIRED)
 | 
					find_package(OpenSSL REQUIRED)
 | 
				
			||||||
find_package(ZLIB REQUIRED)
 | 
					find_package(ZLIB REQUIRED)
 | 
				
			||||||
find_package(fmt  REQUIRED)
 | 
					find_package(fmt  REQUIRED)
 | 
				
			||||||
find_package(nlohmann_json  REQUIRED)
 | 
					find_package(nlohmann_json  REQUIRED)
 | 
				
			||||||
find_package(nlohmann_json_schema_validator REQUIRED)
 | 
					# find_package(valijson       REQUIRED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(SMALL_BUILD)
 | 
					if(SMALL_BUILD)
 | 
				
			||||||
    find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
 | 
					    find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
 | 
				
			||||||
@@ -82,10 +82,53 @@ add_executable( owgw
 | 
				
			|||||||
        src/framework/orm.h
 | 
					        src/framework/orm.h
 | 
				
			||||||
        src/framework/StorageClass.h
 | 
					        src/framework/StorageClass.h
 | 
				
			||||||
        src/framework/MicroServiceErrorHandler.h
 | 
					        src/framework/MicroServiceErrorHandler.h
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientServer.cpp
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientServer.h
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientNotifications.cpp
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientNotifications.h
 | 
				
			||||||
 | 
					        src/framework/utils.h
 | 
				
			||||||
 | 
					        src/framework/utils.cpp
 | 
				
			||||||
 | 
					        src/framework/AppServiceRegistry.h
 | 
				
			||||||
 | 
					        src/framework/SubSystemServer.cpp
 | 
				
			||||||
 | 
					        src/framework/SubSystemServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_utils.h
 | 
				
			||||||
 | 
					        src/framework/AuthClient.cpp
 | 
				
			||||||
 | 
					        src/framework/AuthClient.h
 | 
				
			||||||
 | 
					        src/framework/MicroServiceNames.h
 | 
				
			||||||
 | 
					        src/framework/MicroServiceFuncs.h
 | 
				
			||||||
 | 
					        src/framework/OpenAPIRequests.cpp
 | 
				
			||||||
 | 
					        src/framework/OpenAPIRequests.h
 | 
				
			||||||
 | 
					        src/framework/MicroServiceFuncs.cpp
 | 
				
			||||||
 | 
					        src/framework/ALBserver.cpp
 | 
				
			||||||
 | 
					        src/framework/ALBserver.h
 | 
				
			||||||
 | 
					        src/framework/KafkaManager.cpp
 | 
				
			||||||
 | 
					        src/framework/KafkaManager.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_RateLimiter.h
 | 
				
			||||||
 | 
					        src/framework/WebSocketLogger.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_GenericServerAccounting.h
 | 
				
			||||||
 | 
					        src/framework/CIDR.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_Handler.cpp
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_Handler.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_ExtServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_ExtServer.cpp
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_IntServer.cpp
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_IntServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_SystemCommand.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_WebSocketServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_SystemConfiguration.h
 | 
				
			||||||
 | 
					        src/framework/EventBusManager.cpp
 | 
				
			||||||
 | 
					        src/framework/EventBusManager.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_PartHandler.h
 | 
				
			||||||
 | 
					        src/framework/MicroService.cpp
 | 
				
			||||||
 | 
					        src/framework/MicroServiceExtra.h
 | 
				
			||||||
        src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
 | 
					        src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
 | 
				
			||||||
        src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
					 | 
				
			||||||
        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
 | 
					        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
 | 
				
			||||||
        src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
 | 
					        src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_devices_handler.cpp src/RESTAPI/RESTAPI_devices_handler.h
 | 
					        src/RESTAPI/RESTAPI_devices_handler.cpp src/RESTAPI/RESTAPI_devices_handler.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_device_handler.cpp src/RESTAPI/RESTAPI_device_handler.h
 | 
					        src/RESTAPI/RESTAPI_device_handler.cpp src/RESTAPI/RESTAPI_device_handler.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_device_commandHandler.cpp src/RESTAPI/RESTAPI_device_commandHandler.h
 | 
					        src/RESTAPI/RESTAPI_device_commandHandler.cpp src/RESTAPI/RESTAPI_device_commandHandler.h
 | 
				
			||||||
@@ -101,15 +144,19 @@ add_executable( owgw
 | 
				
			|||||||
        src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
 | 
					        src/RESTAPI/RESTAPI_RPC.cpp src/RESTAPI/RESTAPI_RPC.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
 | 
					        src/RESTAPI/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI/RESTAPI_deviceDashboardHandler.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.h
 | 
					        src/RESTAPI/RESTAPI_telemetryWebSocket.cpp src/RESTAPI/RESTAPI_telemetryWebSocket.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_scripts_handler.cpp src/RESTAPI/RESTAPI_scripts_handler.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_script_handler.cpp src/RESTAPI/RESTAPI_script_handler.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_regulatory.cpp src/RESTAPI/RESTAPI_regulatory.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_radiussessions_handler.cpp src/RESTAPI/RESTAPI_radiussessions_handler.h
 | 
				
			||||||
        src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
 | 
					        src/storage/storage_blacklist.cpp src/storage/storage_tables.cpp src/storage/storage_logs.cpp
 | 
				
			||||||
        src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
 | 
					        src/storage/storage_command.cpp src/storage/storage_healthcheck.cpp src/storage/storage_statistics.cpp
 | 
				
			||||||
        src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
 | 
					        src/storage/storage_device.cpp src/storage/storage_capabilities.cpp src/storage/storage_defconfig.cpp
 | 
				
			||||||
 | 
					        src/storage/storage_scripts.cpp src/storage/storage_scripts.h
 | 
				
			||||||
        src/storage/storage_tables.cpp
 | 
					        src/storage/storage_tables.cpp
 | 
				
			||||||
        src/RESTAPI/RESTAPI_routers.cpp
 | 
					        src/RESTAPI/RESTAPI_routers.cpp
 | 
				
			||||||
        src/Daemon.cpp src/Daemon.h
 | 
					        src/Daemon.cpp src/Daemon.h
 | 
				
			||||||
        src/AP_WS_Server.cpp src/AP_WS_Server.h
 | 
					        src/AP_WS_Server.cpp src/AP_WS_Server.h
 | 
				
			||||||
        src/StorageService.cpp src/StorageService.h
 | 
					        src/StorageService.cpp src/StorageService.h
 | 
				
			||||||
#        src/DeviceRegistry.cpp src/DeviceRegistry.h
 | 
					 | 
				
			||||||
        src/CommandManager.cpp src/CommandManager.h
 | 
					        src/CommandManager.cpp src/CommandManager.h
 | 
				
			||||||
        src/CentralConfig.cpp src/CentralConfig.h
 | 
					        src/CentralConfig.cpp src/CentralConfig.h
 | 
				
			||||||
        src/FileUploader.cpp src/FileUploader.h
 | 
					        src/FileUploader.cpp src/FileUploader.h
 | 
				
			||||||
@@ -123,17 +170,48 @@ add_executable( owgw
 | 
				
			|||||||
        src/CapabilitiesCache.h src/FindCountry.h
 | 
					        src/CapabilitiesCache.h src/FindCountry.h
 | 
				
			||||||
        src/rttys/RTTYS_server.cpp
 | 
					        src/rttys/RTTYS_server.cpp
 | 
				
			||||||
        src/rttys/RTTYS_server.h
 | 
					        src/rttys/RTTYS_server.h
 | 
				
			||||||
        src/rttys/RTTYS_device.cpp
 | 
					 | 
				
			||||||
        src/rttys/RTTYS_device.h
 | 
					 | 
				
			||||||
        src/rttys/RTTYS_ClientConnection.cpp
 | 
					 | 
				
			||||||
        src/rttys/RTTYS_ClientConnection.h
 | 
					 | 
				
			||||||
        src/rttys/RTTYS_WebServer.cpp
 | 
					        src/rttys/RTTYS_WebServer.cpp
 | 
				
			||||||
        src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h src/SDKcalls.cpp src/SDKcalls.h src/StateUtils.cpp src/StateUtils.h src/AP_WS_ReactorPool.h src/AP_WS_Connection.h src/AP_WS_Connection.cpp src/TelemetryClient.h src/TelemetryClient.cpp src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h src/framework/ow_constants.h src/GwWebSocketClient.cpp src/GwWebSocketClient.h src/framework/WebSocketClientNotifications.h src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h src/ParseWifiScan.h src/RADIUS_helpers.h src/VenueBroadcaster.h src/sdks/sdk_prov.h
 | 
					        src/rttys/RTTYS_WebServer.h src/RESTAPI/RESTAPI_device_helper.h
 | 
				
			||||||
 | 
					        src/SDKcalls.cpp
 | 
				
			||||||
 | 
					        src/SDKcalls.h
 | 
				
			||||||
 | 
					        src/StateUtils.cpp src/StateUtils.h
 | 
				
			||||||
 | 
					        src/AP_WS_ReactorPool.h
 | 
				
			||||||
 | 
					        src/AP_WS_Connection.h
 | 
				
			||||||
 | 
					        src/AP_WS_Connection.cpp
 | 
				
			||||||
 | 
					        src/TelemetryClient.h src/TelemetryClient.cpp
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_iptocountry_handler.cpp src/RESTAPI/RESTAPI_iptocountry_handler.h
 | 
				
			||||||
 | 
					        src/framework/ow_constants.h
 | 
				
			||||||
 | 
					        src/GwWebSocketClient.cpp src/GwWebSocketClient.h
 | 
				
			||||||
 | 
					        src/RADIUS_proxy_server.cpp src/RADIUS_proxy_server.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_radiusProxyConfig_handler.cpp src/RESTAPI/RESTAPI_radiusProxyConfig_handler.h
 | 
				
			||||||
 | 
					        src/ParseWifiScan.h
 | 
				
			||||||
 | 
					        src/RADIUS_helpers.h
 | 
				
			||||||
 | 
					        src/VenueBroadcaster.h
 | 
				
			||||||
 | 
					        src/sdks/sdk_prov.h
 | 
				
			||||||
        src/AP_WS_Process_connect.cpp
 | 
					        src/AP_WS_Process_connect.cpp
 | 
				
			||||||
        src/AP_WS_Process_state.cpp
 | 
					        src/AP_WS_Process_state.cpp
 | 
				
			||||||
        src/AP_WS_Process_healthcheck.cpp
 | 
					        src/AP_WS_Process_healthcheck.cpp
 | 
				
			||||||
        src/AP_WS_Process_log.cpp
 | 
					        src/AP_WS_Process_log.cpp
 | 
				
			||||||
        src/AP_WS_Process_crashlog.cpp src/AP_WS_Process_ping.cpp src/AP_WS_Process_cfgpending.cpp src/AP_WS_Process_recovery.cpp src/AP_WS_Process_deviceupdate.cpp src/AP_WS_Process_telemetry.cpp src/AP_WS_Process_venuebroadcast.cpp src/RADSECserver.h)
 | 
					        src/AP_WS_Process_crashlog.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_ping.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_cfgpending.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_recovery.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_deviceupdate.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_telemetry.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_venuebroadcast.cpp
 | 
				
			||||||
 | 
					        src/RADIUS_Destination.h
 | 
				
			||||||
 | 
					        src/UI_GW_WebSocketNotifications.cpp src/UI_GW_WebSocketNotifications.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_SystemConfiguration.h
 | 
				
			||||||
 | 
					        src/ScriptManager.cpp src/ScriptManager.h
 | 
				
			||||||
 | 
					        src/SignatureMgr.h
 | 
				
			||||||
 | 
					        src/AP_WS_Process_event.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_wifiscan.cpp
 | 
				
			||||||
 | 
					        src/AP_WS_Process_alarm.cpp
 | 
				
			||||||
 | 
					        src/GWKafkaEvents.cpp src/GWKafkaEvents.h
 | 
				
			||||||
 | 
					        src/RegulatoryInfo.cpp src/RegulatoryInfo.h
 | 
				
			||||||
 | 
					        src/RADIUSSessionTracker.cpp src/RADIUSSessionTracker.h
 | 
				
			||||||
 | 
					        src/libs/Scheduler.h src/libs/InterruptableSleep.h src/libs/ctpl_stl.h src/libs/Cron.h
 | 
				
			||||||
 | 
					        src/GenericScheduler.cpp src/GenericScheduler.h src/framework/default_device_types.h src/AP_WS_Process_rebootLog.cpp src/AP_WS_ConfigAutoUpgrader.cpp src/AP_WS_ConfigAutoUpgrader.h src/RESTAPI/RESTAPI_default_firmwares.cpp src/RESTAPI/RESTAPI_default_firmwares.h src/RESTAPI/RESTAPI_default_firmware.cpp src/RESTAPI/RESTAPI_default_firmware.h src/storage/storage_def_firmware.cpp src/firmware_revision_cache.h src/sdks/sdk_fms.h)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(NOT SMALL_BUILD)
 | 
					if(NOT SMALL_BUILD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,14 +223,16 @@ INSTALL(TARGETS owgw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
target_link_libraries(owgw PUBLIC
 | 
					target_link_libraries(owgw PUBLIC
 | 
				
			||||||
        ${Poco_LIBRARIES}
 | 
					        ${Poco_LIBRARIES}
 | 
				
			||||||
        ${ZLIB_LIBRARIES})
 | 
					        ${ZLIB_LIBRARIES}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(NOT SMALL_BUILD)
 | 
					if(NOT SMALL_BUILD)
 | 
				
			||||||
    target_link_libraries(owgw PUBLIC
 | 
					    target_link_libraries(owgw PUBLIC
 | 
				
			||||||
            ${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
 | 
					            ${MySQL_LIBRARIES}
 | 
				
			||||||
 | 
					            ${ZLIB_LIBRARIES}
 | 
				
			||||||
            CppKafka::cppkafka
 | 
					            CppKafka::cppkafka
 | 
				
			||||||
                nlohmann_json_schema_validator
 | 
					 | 
				
			||||||
            fmt::fmt
 | 
					            fmt::fmt
 | 
				
			||||||
 | 
					            resolv
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    if(UNIX AND NOT APPLE)
 | 
					    if(UNIX AND NOT APPLE)
 | 
				
			||||||
        target_link_libraries(owgw PUBLIC PocoJSON)
 | 
					        target_link_libraries(owgw PUBLIC PocoJSON)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,32 +0,0 @@
 | 
				
			|||||||
# Coding Style
 | 
					 | 
				
			||||||
I just want ot make sure we all follow the same rules when contributing 
 | 
					 | 
				
			||||||
code back into this tree.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Version of C++
 | 
					 | 
				
			||||||
This project is based on the C++17 standard. If compiles as-is on most platforms 
 | 
					 | 
				
			||||||
using either clang or g++. Do not use C++21 features for now. I would love to do some
 | 
					 | 
				
			||||||
of the new stuff but let's wait for these features to be available on
 | 
					 | 
				
			||||||
all compilers first. `coroutine` has to wait.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Naming
 | 
					 | 
				
			||||||
Naming of pretty much anything uses Pascal naming. I know... You might not be a big fan or have 
 | 
					 | 
				
			||||||
fallen to the JS gods and use camelNaming. Well, let's all make an effort to keep
 | 
					 | 
				
			||||||
this coherent. Member variable naming adds a `_` at the end of the vars. Try to
 | 
					 | 
				
			||||||
keep this standard going. Sometimes you must override a base class function and then of course
 | 
					 | 
				
			||||||
you need to follow the base class. Let's be real...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## File Sizes
 | 
					 | 
				
			||||||
Do you best to keep your file sizes < 300 lines. It just makes the code more readable
 | 
					 | 
				
			||||||
and shortens compile times. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## This is a cmake project
 | 
					 | 
				
			||||||
This is a cmake project and you need to adhere to the cmake rules. If you need
 | 
					 | 
				
			||||||
to add a package to the CMakeList, you need to ensure that the package is available
 | 
					 | 
				
			||||||
on all required platforms and compiles. Remember that this project runs on Linux, OS X, 
 | 
					 | 
				
			||||||
and the Raspberry PI.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Licensed packages
 | 
					 | 
				
			||||||
When adding a package, you must also state the licensing for the package. MIT, BSD, Apache licenses
 | 
					 | 
				
			||||||
are acceptable. No commercial licenses are allowed. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										415
									
								
								CONFIGURATION.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								CONFIGURATION.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,415 @@
 | 
				
			|||||||
 | 
					# Controller Configuration Parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## OWGW Specific Parameters
 | 
				
			||||||
 | 
					### Websocket parameters
 | 
				
			||||||
 | 
					This is the crucial section. I bet that 97.4% of all your problems will come from here, and it's boring. So put some good music on,
 | 
				
			||||||
 | 
					give the kids the iPad, get a cup of coffee, and pay attention. Every field will be explained.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.backlog = 500
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.rootca = $OWGW_ROOT/certs/root.pem
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.issuer = $OWGW_ROOT/certs/issuer.pem
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.cert = $OWGW_ROOT/certs/websocket-cert.pem
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.key = $OWGW_ROOT/certs/websocket-key.pem
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.clientcas = $OWGW_ROOT/certs/clientcas.pem
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.cas = $OWGW_ROOT/certs/cas
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.address = *
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.port = 15002
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.security = strict
 | 
				
			||||||
 | 
					ucentral.websocket.host.0.key.password = mypassword
 | 
				
			||||||
 | 
					ucentral.websocket.maxreactors = 20
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.backlog
 | 
				
			||||||
 | 
					This is the number of concurrent devices you are expecting to call all at once. Not the current number of devices. This is how many will connect in the same exact second.
 | 
				
			||||||
 | 
					Take the total number of devices you have and divide by 100. That's a good rule of thumb. Never go above 500.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.rootca
 | 
				
			||||||
 | 
					This is the root file as supplied by Digicert. You can find it [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/root.pem)
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.issuer
 | 
				
			||||||
 | 
					This is the issuer file as supplied by Digicert. You can find it [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/issuer.pem)
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.cert
 | 
				
			||||||
 | 
					This is a `pem` file that you will receive from Digicert for the gateway itself. This is the certificate for the gateway.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.key
 | 
				
			||||||
 | 
					This is a `pem` file that you will receive from Digicert for the gateway itself. The is the private key for the gateway.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.clientcas
 | 
				
			||||||
 | 
					This is a `pem` file that contains both the issuer and the root CA certificates. You can find it You can find it [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/clientcas.pem)
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.cas
 | 
				
			||||||
 | 
					This is a directory where you will copy your own `cert.pem`, the `root.pem`, and the `issuer.pem` files.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.address
 | 
				
			||||||
 | 
					Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.port
 | 
				
			||||||
 | 
					Leave to 15002 for now.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.security
 | 
				
			||||||
 | 
					Leave this as strict for now for devices.
 | 
				
			||||||
 | 
					#### ucentral.websocket.host.0.key.password
 | 
				
			||||||
 | 
					If you key file uses a password, please enter it here.
 | 
				
			||||||
 | 
					#### ucentral.websocket.maxreactors
 | 
				
			||||||
 | 
					A single reactor can handle between 1000-2000 devices. Never leave this smaller than 5 or larger than 50.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### File uploader parameters
 | 
				
			||||||
 | 
					Certain commands may require the Access Point to upload a file into the Controller. For this reason, there is a special embedded HTTP 
 | 
				
			||||||
 | 
					server to receive these files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.backlog = 100
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.security = relaxed
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.address = *
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.name = ucentral.dpaas.arilia.com
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.port = 16003
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.fileuploader.host.0.key.password = mypassword
 | 
				
			||||||
 | 
					openwifi.fileuploader.path = $OWGW_ROOT/uploads
 | 
				
			||||||
 | 
					openwifi.fileuploader.maxsize = 10000
 | 
				
			||||||
 | 
					openwifi.fileuploader.uri = https://ucentral.dpaas.arilia.com:16003
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.backlog
 | 
				
			||||||
 | 
					This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.rootca
 | 
				
			||||||
 | 
					This is the root file of your own certificate CA in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.cert
 | 
				
			||||||
 | 
					This is your own server certificate in `pem` format..
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.key
 | 
				
			||||||
 | 
					This is the private key associated with your own certificate in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.intfileuploaderernal.host.0.address
 | 
				
			||||||
 | 
					Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.port
 | 
				
			||||||
 | 
					The port on which the REST API server is listening. By default, this is 16003.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.security
 | 
				
			||||||
 | 
					Leave this as `relaxed` for now for devices.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.host.0.key.password
 | 
				
			||||||
 | 
					If you key file uses a password, please enter it here.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.path
 | 
				
			||||||
 | 
					This is the location where the files will be stored temporarily before processing. This `path` must exist.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.maxsize 
 | 
				
			||||||
 | 
					This is the maximum uploaded file size. The default maximum size if 10MB. This size is in KB.
 | 
				
			||||||
 | 
					#### openwifi.fileuploader.uri
 | 
				
			||||||
 | 
					This is the URI that will be passed to the AP. You must make sure that the AP can resolve this URI.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### OUI Service
 | 
				
			||||||
 | 
					The controller has a built-in OUI resolver for MAC addresses. The GW will periodically load this file to obtain the latest. 
 | 
				
			||||||
 | 
					This is ths URI for this file.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					oui.download.uri = https://standards-oui.ieee.org/oui/oui.txt
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Data-model Source
 | 
				
			||||||
 | 
					The gateway can make use of the latest uCentral data-model or use the built-in model. These 2 parameters allow you to 
 | 
				
			||||||
 | 
					choose which method you want. If you select the internal method, the URI is ignored. If for some reason you choose 
 | 
				
			||||||
 | 
					the on-line data-model from the URI and the URI is not reachable, the system will fall back on the internal model.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					ucentral.datamodel.internal = true
 | 
				
			||||||
 | 
					ucentral.datamodel.uri = https://raw.githubusercontent.com/Telecominfraproject/wlan-ucentral-schema/main/ucentral.schema.json
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Command Manager
 | 
				
			||||||
 | 
					The command manager is responsible for managing command sent and responses received with the APs. Several parameters allow you
 | 
				
			||||||
 | 
					to fine tune its behaviour. Unless you have some particular reasons to change tem the defaults are usually just fine.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					command.timeout = 14400
 | 
				
			||||||
 | 
					command.retry = 120
 | 
				
			||||||
 | 
					command.janitor = 120
 | 
				
			||||||
 | 
					command.queue = 30
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					#### command.timeout
 | 
				
			||||||
 | 
					How long will the GW wait in seconds before considering a commands has timed out. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### command.retry
 | 
				
			||||||
 | 
					How long between command retries.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### command.janitor
 | 
				
			||||||
 | 
					How long between outstanding RPC clean-ups.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### command.queue
 | 
				
			||||||
 | 
					How long should te gateway wait between running its queue.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### IP to Country Parameters
 | 
				
			||||||
 | 
					The controller has the ability to find the location of the IP of each Access Points. This uses an external IP location service. Currently,
 | 
				
			||||||
 | 
					the controller supports 3 services. Please note that these services will require to obtain an API key or token, and these may cause you to incur 
 | 
				
			||||||
 | 
					additional fees. Here is the list of the services supported:
 | 
				
			||||||
 | 
					- ip2location: ip2location.com
 | 
				
			||||||
 | 
					- ipdata: ipdata.co
 | 
				
			||||||
 | 
					- ipinfo: ipinfo.io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					iptocountry.default = US
 | 
				
			||||||
 | 
					iptocountry.provider = ipinfo
 | 
				
			||||||
 | 
					#iptocountry.provider = ipdata
 | 
				
			||||||
 | 
					#iptocountry.provider = ip2location
 | 
				
			||||||
 | 
					iptocountry.ipinfo.token =
 | 
				
			||||||
 | 
					iptocountry.ipdata.apikey =
 | 
				
			||||||
 | 
					iptocountry.ip2location.apikey =
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### iptocountry.default
 | 
				
			||||||
 | 
					This is the country code to be used if no information can be found at one of the providers or you have not configured any of the providers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### iptocountry.provider
 | 
				
			||||||
 | 
					You must select onf of the possible services and the fill the appropriate token or api key parameter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Provisioning link
 | 
				
			||||||
 | 
					This parameter tells the controller how to behave when it receives a request from a device for the first time. In this case, we tell
 | 
				
			||||||
 | 
					the controller to look at the provisioning service first, then apply any local configurations.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					autoprovisioning.process = prov,default
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Restricted Device Signature Manager
 | 
				
			||||||
 | 
					If are using restricted devices, then you can include different keys for each vendor who provided 
 | 
				
			||||||
 | 
					you with their information. This allows the controller to automatically sign requests to the device. You can have as many vendors
 | 
				
			||||||
 | 
					as it is necessary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					signature.manager.0.key.public = $OWGW_ROOT/certs/signatures/test1-public-key.pem
 | 
				
			||||||
 | 
					signature.manager.0.key.private = $OWGW_ROOT/certs/signatures/test1-private-key.pem
 | 
				
			||||||
 | 
					signature.manager.0.vendor = test1
 | 
				
			||||||
 | 
					signature.manager.1.key.public = $OWGW_ROOT/certs/signatures/test2-public-key.pem
 | 
				
			||||||
 | 
					signature.manager.1.key.private = $OWGW_ROOT/certs/signatures/test2-private-key.pem
 | 
				
			||||||
 | 
					signature.manager.1.vendor = test2
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### OWLS Simulator ID
 | 
				
			||||||
 | 
					If you plan on using OWLS (OpenWifi Load Simulator), then you will need to put your Simulator ID right here.
 | 
				
			||||||
 | 
					This ID must be obtained from TIP. 
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					simulatorid = 53494dFFEEDD
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### RTTY Service
 | 
				
			||||||
 | 
					The controller comes with the ability to run an RTTY service. The service can either be internal (the prefered choice) 
 | 
				
			||||||
 | 
					or external. If you decide to use the internal RTTY, the you only need to specify `rtty.internal = true`. If you choose 
 | 
				
			||||||
 | 
					to use an external RTTY, you must specify the remainder of the parameters.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					rtty.internal = true
 | 
				
			||||||
 | 
					rtty.enabled = true
 | 
				
			||||||
 | 
					rtty.server = rtty-tip.arilia.com
 | 
				
			||||||
 | 
					rtty.port = 5912
 | 
				
			||||||
 | 
					rtty.token = 96181c567b4d0d98c50f127230068fa8
 | 
				
			||||||
 | 
					rtty.timeout = 60
 | 
				
			||||||
 | 
					rtty.viewport = 5913
 | 
				
			||||||
 | 
					rtty.assets = $OWGW_ROOT/rtty_ui
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### RADIUS proxy config
 | 
				
			||||||
 | 
					If you are going to use the buil-in RADIUS proxy service, you need to enable this parameter and provide 
 | 
				
			||||||
 | 
					the ports for you PROXY.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					radius.proxy.enable = false
 | 
				
			||||||
 | 
					radius.proxy.accounting.port = 1813
 | 
				
			||||||
 | 
					radius.proxy.authentication.port = 1812
 | 
				
			||||||
 | 
					radius.proxy.coa.port = 3799
 | 
				
			||||||
 | 
					radsec.keepalive = 120
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Auto Archiver Parameters
 | 
				
			||||||
 | 
					The auto archiver is responsible for removing all stale data. The default is to remove old data after 7 days.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					archiver.enabled = true
 | 
				
			||||||
 | 
					archiver.schedule = 03:00
 | 
				
			||||||
 | 
					archiver.db.0.name = healthchecks
 | 
				
			||||||
 | 
					archiver.db.0.keep = 7
 | 
				
			||||||
 | 
					archiver.db.1.name = statistics
 | 
				
			||||||
 | 
					archiver.db.1.keep = 7
 | 
				
			||||||
 | 
					archiver.db.2.name = devicelogs
 | 
				
			||||||
 | 
					archiver.db.2.keep = 7
 | 
				
			||||||
 | 
					archiver.db.3.name = commandlist
 | 
				
			||||||
 | 
					archiver.db.3.keep = 7
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Generic OpenWiFi SDK parameters
 | 
				
			||||||
 | 
					### REST API External parameters
 | 
				
			||||||
 | 
					These are the parameters required for the configuration of the external facing REST API server
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.backlog = 100
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.security = relaxed
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.address = *
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.port = 16004
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.key.password = mypassword
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.backlog
 | 
				
			||||||
 | 
					This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.rootca
 | 
				
			||||||
 | 
					This is the root file of your own certificate CA in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.cert
 | 
				
			||||||
 | 
					This is your own server certificate in `pem` format..
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.key
 | 
				
			||||||
 | 
					This is the private key associated with your own certificate in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.address
 | 
				
			||||||
 | 
					Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.port
 | 
				
			||||||
 | 
					The port on which the REST API server is listening. By default, this is 16002.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.security
 | 
				
			||||||
 | 
					Leave this as `relaxed` for now for devices.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.key.password
 | 
				
			||||||
 | 
					If you key file uses a password, please enter it here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### REST API Intra microservice parameters
 | 
				
			||||||
 | 
					The following parameters describe the configuration for the inter-microservice HTTP server. You may use the same certificate/key
 | 
				
			||||||
 | 
					you are using for your extenral server or another certificate.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.backlog = 100
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.security = relaxed
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.address = *
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.port = 17004
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.key.password = mypassword
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.backlog
 | 
				
			||||||
 | 
					This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.rootca
 | 
				
			||||||
 | 
					This is the root file of your own certificate CA in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.cert
 | 
				
			||||||
 | 
					This is your own server certificate in `pem` format..
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.key
 | 
				
			||||||
 | 
					This is the private key associated with your own certificate in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.address
 | 
				
			||||||
 | 
					Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.port
 | 
				
			||||||
 | 
					The port on which the REST API server is listening. By default, this is 17002.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.security
 | 
				
			||||||
 | 
					Leave this as `relaxed` for now for devices.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.key.password
 | 
				
			||||||
 | 
					If you key file uses a password, please enter it here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Microservice information
 | 
				
			||||||
 | 
					These are different Microservie parameters. Following is a brief explanation.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.service.key = $OWGW_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.service.key.password = mypassword
 | 
				
			||||||
 | 
					openwifi.system.data = $OWGW_ROOT/data
 | 
				
			||||||
 | 
					openwifi.system.uri.private = https://localhost:17004
 | 
				
			||||||
 | 
					openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
 | 
				
			||||||
 | 
					openwifi.system.uri.ui = https://ucentral-ui.arilia.com
 | 
				
			||||||
 | 
					openwifi.security.restapi.disable = false
 | 
				
			||||||
 | 
					openwifi.system.commandchannel = /tmp/app.ucentralfms
 | 
				
			||||||
 | 
					openwifi.autoprovisioning = true
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					#### openwifi.service.key
 | 
				
			||||||
 | 
					From time to time, the microservice must encrypt information. This is the key it should use. You may use the
 | 
				
			||||||
 | 
					same keey as you RESTAPI or your server.
 | 
				
			||||||
 | 
					#### openwifi.service.key.password
 | 
				
			||||||
 | 
					The password for the `openwifi.service.key`
 | 
				
			||||||
 | 
					#### openwifi.system.data
 | 
				
			||||||
 | 
					The location of system data. This path must exist.
 | 
				
			||||||
 | 
					#### openwifi.system.uri.private
 | 
				
			||||||
 | 
					The URI to reach the controller on the internal port.
 | 
				
			||||||
 | 
					#### openwifi.system.uri.public
 | 
				
			||||||
 | 
					The URI to reach the controller from the outside world.
 | 
				
			||||||
 | 
					#### openwifi.system.uri.ui
 | 
				
			||||||
 | 
					The URI of the UI to manage this service
 | 
				
			||||||
 | 
					#### openwifi.security.restapi.disable
 | 
				
			||||||
 | 
					This allows to disable security for internal and external API calls. This should only be used if the controller
 | 
				
			||||||
 | 
					sits behind an application load balancer that will actually do TLS. Setting this to `true` disables security.
 | 
				
			||||||
 | 
					#### openwifi.system.commandchannel
 | 
				
			||||||
 | 
					The UNIX socket command channel used by this service.
 | 
				
			||||||
 | 
					#### openwifi.autoprovisioning
 | 
				
			||||||
 | 
					Allow unknown devices to be provisioned by the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### ALB Support
 | 
				
			||||||
 | 
					In order to support an application load balancer health check verification, your need to provide the following parameters.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					alb.enable = true
 | 
				
			||||||
 | 
					alb.port = 16102
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Kafka
 | 
				
			||||||
 | 
					The controller use Kafka, like all the other microservices. You must configure the kafka section in order for the
 | 
				
			||||||
 | 
					system to work.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.kafka.group.id = gateway
 | 
				
			||||||
 | 
					openwifi.kafka.client.id = gateway1
 | 
				
			||||||
 | 
					openwifi.kafka.enable = true
 | 
				
			||||||
 | 
					openwifi.kafka.brokerlist = my_Kafka.example.com:9092
 | 
				
			||||||
 | 
					openwifi.kafka.auto.commit = false
 | 
				
			||||||
 | 
					openwifi.kafka.queue.buffering.max.ms = 50
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### openwifi.kafka.group.id
 | 
				
			||||||
 | 
					The group ID is a single word that should identify the type of service tuning. In the case `gateway`
 | 
				
			||||||
 | 
					### openwifi.kafka.client.id
 | 
				
			||||||
 | 
					The client ID is a single service within that group ID. Each participant must have a unique client ID.
 | 
				
			||||||
 | 
					### openwifi.kafka.enable
 | 
				
			||||||
 | 
					Kafka should always be enabled.
 | 
				
			||||||
 | 
					### openwifi.kafka.brokerlist
 | 
				
			||||||
 | 
					The list of servers where your Kafka server is running. Comma separated.
 | 
				
			||||||
 | 
					### openwifi.kafka.auto.commit
 | 
				
			||||||
 | 
					Auto commit flag in Kafka. Leave as `false`.
 | 
				
			||||||
 | 
					### openwifi.kafka.queue.buffering.max.ms
 | 
				
			||||||
 | 
					Kafka buffering. Leave as `50`.
 | 
				
			||||||
 | 
					### Kafka security
 | 
				
			||||||
 | 
					If you intend to use SSL, you should look into Kafka Connect and specify the certificates below.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					penwifi.kafka.ssl.ca.location =
 | 
				
			||||||
 | 
					openwifi.kafka.ssl.certificate.location =
 | 
				
			||||||
 | 
					openwifi.kafka.ssl.key.location =
 | 
				
			||||||
 | 
					openwifi.kafka.ssl.key.password =
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### DB Type
 | 
				
			||||||
 | 
					The controller supports 3 types of Database. SQLite should only be used for sites with less than 100 APs or for testing in the lab.
 | 
				
			||||||
 | 
					In order to select which database to use, you must set the `storage.type` value to sqlite, postgresql, or mysql.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type = sqlite
 | 
				
			||||||
 | 
					#storage.type = postgresql
 | 
				
			||||||
 | 
					#storage.type = mysql
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Storage SQLite parameters
 | 
				
			||||||
 | 
					Additional parameters to set for SQLite. The only important one is `storage.type.sqlite.db` which is the database name on disk.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type.sqlite.db = gateway.db
 | 
				
			||||||
 | 
					storage.type.sqlite.idletime = 120
 | 
				
			||||||
 | 
					storage.type.sqlite.maxsessions = 128
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Storage Postgres
 | 
				
			||||||
 | 
					Additional parameters to set if you select Postgres for your database. You must specify `host`, `username`, `password`,
 | 
				
			||||||
 | 
					`database`, and `port`.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type.postgresql.maxsessions = 64
 | 
				
			||||||
 | 
					storage.type.postgresql.idletime = 60
 | 
				
			||||||
 | 
					storage.type.postgresql.host = localhost
 | 
				
			||||||
 | 
					storage.type.postgresql.username = gateway
 | 
				
			||||||
 | 
					storage.type.postgresql.password = gateway
 | 
				
			||||||
 | 
					storage.type.postgresql.database = gateway
 | 
				
			||||||
 | 
					storage.type.postgresql.port = 5432
 | 
				
			||||||
 | 
					storage.type.postgresql.connectiontimeout = 60
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Storage MySQL/MariaDB
 | 
				
			||||||
 | 
					Additional parameters to set if you select mysql for your database. You must specify `host`, `username`, `password`,
 | 
				
			||||||
 | 
					`database`, and `port`.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type.mysql.maxsessions = 64
 | 
				
			||||||
 | 
					storage.type.mysql.idletime = 60
 | 
				
			||||||
 | 
					storage.type.mysql.host = localhost
 | 
				
			||||||
 | 
					storage.type.postgresql.username = gateway
 | 
				
			||||||
 | 
					storage.type.postgresql.password = gateway
 | 
				
			||||||
 | 
					storage.type.postgresql.database = gateway
 | 
				
			||||||
 | 
					storage.type.mysql.port = 3306
 | 
				
			||||||
 | 
					storage.type.mysql.connectiontimeout = 60
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Logging Parameters
 | 
				
			||||||
 | 
					The microservice provides extensive logging. If you would like to keep logging on disk, set the `logging.type = file`. If you only want
 | 
				
			||||||
 | 
					console logging, `set logging.type = console`. When selecting file, `logging.path` must exist. `logging.level` sets the
 | 
				
			||||||
 | 
					basic logging level for the entire controller. `logging.websocket` disables WebSocket logging.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					logging.type = file
 | 
				
			||||||
 | 
					logging.path = $OWGW_ROOT/logs
 | 
				
			||||||
 | 
					logging.level = information
 | 
				
			||||||
 | 
					logging.asynch = true
 | 
				
			||||||
 | 
					logging.websocket = false
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										38
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					# How to Contribute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We'd love to accept your patches and contributions to this project. There are
 | 
				
			||||||
 | 
					just a few small guidelines you need to follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Version of C++
 | 
				
			||||||
 | 
					This project is based on the C++17 standard and compiles as-is on most platforms 
 | 
				
			||||||
 | 
					using either clang or g++. Do not use C++21 or C++23 features for now. Some core 
 | 
				
			||||||
 | 
					libraries used in this project do not support C++21 or C++23 yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Variable Naming
 | 
				
			||||||
 | 
					Naming of pretty much anything uses Pascal naming. Longer explicit names using casing. 
 | 
				
			||||||
 | 
					Member variable naming adds a `_` at the end of the vars. Try to
 | 
				
			||||||
 | 
					keep this standard going. Sometimes you must override a base class function and then of course
 | 
				
			||||||
 | 
					you need to follow the base class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## This is a cmake project
 | 
				
			||||||
 | 
					This is a cmake project, and you need to adhere to the cmake rules. If you need
 | 
				
			||||||
 | 
					to add a package to the CMakeList, you need to ensure that the package is available
 | 
				
			||||||
 | 
					on all required platforms and compiles. Remember that this project runs on Linux, OS X, 
 | 
				
			||||||
 | 
					and the Raspberry PI.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Licensed packages
 | 
				
			||||||
 | 
					When adding a package, you must also state the licensing for the package. MIT, BSD, Apache licenses
 | 
				
			||||||
 | 
					are acceptable. No commercial licenses are allowed. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## clang formatting
 | 
				
			||||||
 | 
					Please format your code using the included `.clang-format` file included in the project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					clang-format -i --style=<project root>/.clang-format myfile.cpp
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Pull Requests
 | 
				
			||||||
 | 
					All submissions, including submissions by project members, require review. We
 | 
				
			||||||
 | 
					accept GitHub pull requests. Please create a branch with the Jira name for addressing the issue you are fixing or the 
 | 
				
			||||||
 | 
					feature you are implementing.
 | 
				
			||||||
 | 
					Create a pull-request from the branch into master. 
 | 
				
			||||||
							
								
								
									
										94
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -1,8 +1,9 @@
 | 
				
			|||||||
ARG DEBIAN_VERSION=11.4-slim
 | 
					ARG DEBIAN_VERSION=11.5-slim
 | 
				
			||||||
ARG POCO_VERSION=poco-tip-v1
 | 
					ARG POCO_VERSION=poco-tip-v2
 | 
				
			||||||
ARG FMTLIB_VERSION=9.0.0
 | 
					 | 
				
			||||||
ARG CPPKAFKA_VERSION=tip-v1
 | 
					ARG CPPKAFKA_VERSION=tip-v1
 | 
				
			||||||
ARG JSON_VALIDATOR_VERSION=2.1.0
 | 
					ARG VALIJASON_VERSION=tip-v1
 | 
				
			||||||
 | 
					ARG APP_NAME=owgw
 | 
				
			||||||
 | 
					ARG APP_HOME_DIR=/openwifi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM debian:$DEBIAN_VERSION AS build-base
 | 
					FROM debian:$DEBIAN_VERSION AS build-base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,7 +11,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
				
			|||||||
    make cmake g++ git \
 | 
					    make cmake g++ git \
 | 
				
			||||||
    libpq-dev libmariadb-dev libmariadbclient-dev-compat \
 | 
					    libpq-dev libmariadb-dev libmariadbclient-dev-compat \
 | 
				
			||||||
    librdkafka-dev libboost-all-dev libssl-dev \
 | 
					    librdkafka-dev libboost-all-dev libssl-dev \
 | 
				
			||||||
    zlib1g-dev nlohmann-json3-dev ca-certificates
 | 
					    zlib1g-dev nlohmann-json3-dev ca-certificates libfmt-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS poco-build
 | 
					FROM build-base AS poco-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,20 +27,6 @@ RUN cmake ..
 | 
				
			|||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN cmake --build . --target install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS fmtlib-build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ARG FMTLIB_VERSION
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
 | 
					 | 
				
			||||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WORKDIR /fmtlib
 | 
					 | 
				
			||||||
RUN mkdir cmake-build
 | 
					 | 
				
			||||||
WORKDIR cmake-build
 | 
					 | 
				
			||||||
RUN cmake ..
 | 
					 | 
				
			||||||
RUN make
 | 
					 | 
				
			||||||
RUN make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FROM build-base AS cppkafka-build
 | 
					FROM build-base AS cppkafka-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG CPPKAFKA_VERSION
 | 
					ARG CPPKAFKA_VERSION
 | 
				
			||||||
@@ -54,75 +41,84 @@ RUN cmake ..
 | 
				
			|||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN cmake --build . --target install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS json-schema-validator-build
 | 
					FROM build-base AS valijson-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG JSON_VALIDATOR_VERSION
 | 
					ARG VALIJASON_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
 | 
					ADD https://api.github.com/repos/AriliaWireless/valijson/git/refs/tags/${VALIJASON_VERSION} version.json
 | 
				
			||||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
 | 
					RUN git clone https://github.com/AriliaWireless/valijson --branch ${VALIJASON_VERSION} /valijson
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /json-schema-validator
 | 
					WORKDIR /valijson
 | 
				
			||||||
RUN mkdir cmake-build
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
WORKDIR cmake-build
 | 
					WORKDIR cmake-build
 | 
				
			||||||
RUN cmake ..
 | 
					RUN cmake ..
 | 
				
			||||||
RUN make
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN make install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS owgw-build
 | 
					FROM build-base AS app-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD CMakeLists.txt build /owgw/
 | 
					ARG APP_NAME
 | 
				
			||||||
ADD cmake /owgw/cmake
 | 
					
 | 
				
			||||||
ADD src /owgw/src
 | 
					ADD CMakeLists.txt build /${APP_NAME}/
 | 
				
			||||||
ADD .git /owgw/.git
 | 
					ADD cmake /${APP_NAME}/cmake
 | 
				
			||||||
 | 
					ADD src /${APP_NAME}/src
 | 
				
			||||||
 | 
					ADD .git /${APP_NAME}/.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY --from=poco-build /usr/local/include /usr/local/include
 | 
					COPY --from=poco-build /usr/local/include /usr/local/include
 | 
				
			||||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
 | 
					COPY --from=poco-build /usr/local/lib /usr/local/lib
 | 
				
			||||||
COPY --from=cppkafka-build /usr/local/include /usr/local/include
 | 
					COPY --from=cppkafka-build /usr/local/include /usr/local/include
 | 
				
			||||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
 | 
					COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
 | 
				
			||||||
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
 | 
					COPY --from=valijson-build /usr/local/include /usr/local/include
 | 
				
			||||||
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
 | 
					 | 
				
			||||||
COPY --from=fmtlib-build /usr/local/include /usr/local/include
 | 
					 | 
				
			||||||
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /owgw
 | 
					WORKDIR /${APP_NAME}
 | 
				
			||||||
RUN mkdir cmake-build
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
WORKDIR /owgw/cmake-build
 | 
					WORKDIR /${APP_NAME}/cmake-build
 | 
				
			||||||
RUN cmake ..
 | 
					RUN cmake ..
 | 
				
			||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM debian:$DEBIAN_VERSION
 | 
					FROM debian:$DEBIAN_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENV OWGW_USER=owgw \
 | 
					ARG APP_NAME
 | 
				
			||||||
    OWGW_ROOT=/owgw-data \
 | 
					ARG APP_HOME_DIR
 | 
				
			||||||
    OWGW_CONFIG=/owgw-data
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN useradd "$OWGW_USER"
 | 
					ENV APP_NAME=$APP_NAME \
 | 
				
			||||||
 | 
					    APP_USER=$APP_NAME \
 | 
				
			||||||
 | 
					    APP_ROOT=/$APP_NAME-data \
 | 
				
			||||||
 | 
					    APP_CONFIG=/$APP_NAME-data \
 | 
				
			||||||
 | 
					    APP_HOME_DIR=$APP_HOME_DIR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN mkdir /openwifi
 | 
					# This is for legacy
 | 
				
			||||||
RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
 | 
					ENV OWGW_USER=$APP_USER \
 | 
				
			||||||
    chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
 | 
					    OWGW_ROOT=$APP_ROOT \
 | 
				
			||||||
 | 
					    OWGW_CONFIG=$APP_CONFIG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN useradd $APP_USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN mkdir $APP_HOME_DIR
 | 
				
			||||||
 | 
					RUN mkdir -p $APP_ROOT $APP_CONFIG && \
 | 
				
			||||||
 | 
					    chown $APP_USER: $APP_ROOT $APP_CONFIG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
					RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
				
			||||||
    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
					    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
				
			||||||
    libmariadb-dev-compat libpq5 unixodbc postgresql-client
 | 
					    libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt7 sqlite3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY readiness_check /readiness_check
 | 
					COPY readiness_check /readiness_check
 | 
				
			||||||
COPY test_scripts/curl/cli /cli
 | 
					COPY test_scripts/curl/cli /cli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY owgw.properties.tmpl /
 | 
					COPY $APP_NAME.properties.tmpl /
 | 
				
			||||||
COPY docker-entrypoint.sh /
 | 
					COPY docker-entrypoint.sh /
 | 
				
			||||||
COPY wait-for-postgres.sh /
 | 
					COPY wait-for-postgres.sh /
 | 
				
			||||||
COPY rtty_ui /dist/rtty_ui
 | 
					COPY rtty_ui /dist/rtty_ui
 | 
				
			||||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
					RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
				
			||||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
 | 
					    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY --from=owgw-build /owgw/cmake-build/owgw /openwifi/owgw
 | 
					COPY --from=app-build /$APP_NAME/cmake-build/$APP_NAME $APP_HOME_DIR/$APP_NAME
 | 
				
			||||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
 | 
					COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib /usr/local/lib/
 | 
				
			||||||
COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib
 | 
					COPY --from=poco-build /poco/cmake-build/lib /usr/local/lib/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN ldconfig
 | 
					RUN ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPOSE 15002 16002 16003 17002 16102
 | 
					EXPOSE 15002 16002 16003 17002 16102
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
 | 
					ENTRYPOINT ["/docker-entrypoint.sh"]
 | 
				
			||||||
CMD ["/openwifi/owgw"]
 | 
					CMD ${APP_HOME_DIR}/${APP_NAME}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								KAFKA.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								KAFKA.md
									
									
									
									
									
								
							@@ -4,15 +4,16 @@ This is a fast moving target, so please visit often or set an alert in GitHub.
 | 
				
			|||||||
## Current plans
 | 
					## Current plans
 | 
				
			||||||
Currently, most telemetry and reports created in the gateway will be issues as topics in Kafka. You should configure 
 | 
					Currently, most telemetry and reports created in the gateway will be issues as topics in Kafka. You should configure 
 | 
				
			||||||
your Kafka service with the following topics:
 | 
					your Kafka service with the following topics:
 | 
				
			||||||
 | 
					 | 
				
			||||||
- `connection` : This is emitted whenever a device connects to the gateway. The report contains all ths information about the connection. 
 | 
					 | 
				
			||||||
- `state` : This is emitted for every `state` report coming from the AP. This state report contains all the information of state reports.  
 | 
					 | 
				
			||||||
- `healthcheck` : These are the `healthcheck` report sent from the AP.
 | 
					- `healthcheck` : These are the `healthcheck` report sent from the AP.
 | 
				
			||||||
 | 
					- `state` : This is emitted for every `state` report coming from the AP. This state report contains all the information of state reports.
 | 
				
			||||||
 | 
					- `connection` : This is emitted whenever a device connects to the gateway. The report contains all ths information about the connection. 
 | 
				
			||||||
- `wifiscan` : Whenever a `wifiscan` report is generated, it will be submitted here.
 | 
					- `wifiscan` : Whenever a `wifiscan` report is generated, it will be submitted here.
 | 
				
			||||||
- `service_events` : Inter-service traffic.
 | 
					 | 
				
			||||||
- `security` : This will have application information (future use).
 | 
					 | 
				
			||||||
- `command` : Allow to send commands (future use).
 | 
					 | 
				
			||||||
- `alerts` : Alerts originating from devices (future use).
 | 
					- `alerts` : Alerts originating from devices (future use).
 | 
				
			||||||
 | 
					- `command` : Allow to send commands (future use).
 | 
				
			||||||
 | 
					- `service_events` : Inter-service traffic.
 | 
				
			||||||
 | 
					- `device_event_queue` : device events
 | 
				
			||||||
 | 
					- `device_telemetry` : device telemetry. Telemetry must be started manually or through the device configuration.
 | 
				
			||||||
 | 
					- `provisioning_change` : venue, configuration, entity changes from provisioning.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Structure of `kafka` messages
 | 
					## Structure of `kafka` messages
 | 
				
			||||||
Messages use 2 formats
 | 
					Messages use 2 formats
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,11 @@ This document will describe how the API is built and how to use it.
 | 
				
			|||||||
This uses OpenAPI definition 3.0 and can be found [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/openapi/ucentral/owgw.yaml).
 | 
					This uses OpenAPI definition 3.0 and can be found [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/openapi/ucentral/owgw.yaml).
 | 
				
			||||||
All endpoints begin with `/api/v1`.
 | 
					All endpoints begin with `/api/v1`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## OpenAPI docs
 | 
				
			||||||
 | 
					You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralgw).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml)) to get interactive docs page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## The flow
 | 
					## The flow
 | 
				
			||||||
In order to use any of the API calls, you must obtain a token (I know - shocking). You do so by calling the end-point
 | 
					In order to use any of the API calls, you must obtain a token (I know - shocking). You do so by calling the end-point
 | 
				
			||||||
`/oauth2`. Once you obtain that `access-token`, you will need to pass it in the headers under `Authorization: Bearer <place your token here>`.
 | 
					`/oauth2`. Once you obtain that `access-token`, you will need to pass it in the headers under `Authorization: Bearer <place your token here>`.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										265
									
								
								PROTOCOL.md
									
									
									
									
									
								
							
							
						
						
									
										265
									
								
								PROTOCOL.md
									
									
									
									
									
								
							@@ -89,6 +89,54 @@ Device sends a log message whenever necessary. The controller will log this mess
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Events Channel
 | 
				
			||||||
 | 
					Device sends unsolicited events to the controller.
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					    "method" : "event" , 
 | 
				
			||||||
 | 
					    "params" : {
 | 
				
			||||||
 | 
					        "serial" : "001122334455" ,
 | 
				
			||||||
 | 
					        "data" : { 
 | 
				
			||||||
 | 
					          "event" : [
 | 
				
			||||||
 | 
					            1871263817263,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "type" : "the event type",
 | 
				
			||||||
 | 
					              "payload" : {
 | 
				
			||||||
 | 
					                "field1" : "value1"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The first element of the `event` array is always the `timestamp` of the event. The `payload` is a JSON document contains addition information about the event. This _may not_ be empty.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Alarms Channel
 | 
				
			||||||
 | 
					Device sends unsolicited alarms to the controller.
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					    "method" : "alarm" , 
 | 
				
			||||||
 | 
					    "params" : {
 | 
				
			||||||
 | 
					        "serial" : <serial number> ,
 | 
				
			||||||
 | 
					        "data" : <Optiona/may be empty: JSON Document providing additional information related to this event message>
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Wifiscan Channel
 | 
				
			||||||
 | 
					Device sends unsolicited wifiscans to the controller.
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					    "method" : "wifiscan" , 
 | 
				
			||||||
 | 
					    "params" : {
 | 
				
			||||||
 | 
					        "serial" : <serial number> ,
 | 
				
			||||||
 | 
					        "data" : <Optiona/may be empty: JSON Document providing additional information related to this wifiscan message>
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##### `severity`
 | 
					##### `severity`
 | 
				
			||||||
The `severity` matches the `syslog` levels. Here are the details:
 | 
					The `severity` matches the `syslog` levels. Here are the details:
 | 
				
			||||||
- 0 : LOG_EMERG       0       /* system is unusable */
 | 
					- 0 : LOG_EMERG       0       /* system is unusable */
 | 
				
			||||||
@@ -101,7 +149,7 @@ The `severity` matches the `syslog` levels. Here are the details:
 | 
				
			|||||||
- 7 : LOG_DEBUG       7       /* debug-level messages */
 | 
					- 7 : LOG_DEBUG       7       /* debug-level messages */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Crash Log event
 | 
					#### Crash Log event
 | 
				
			||||||
Device may send a crash log event after rebooting after a crash. The event cannot be sent until a connection event has been sent.
 | 
					Device may send a `crash log event` during rebooting after a crash. The event cannot be sent until a connection event has been established.
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
{   "jsonrpc" : "2.0" , 
 | 
					{   "jsonrpc" : "2.0" , 
 | 
				
			||||||
    "method" : "crashlog" , 
 | 
					    "method" : "crashlog" , 
 | 
				
			||||||
@@ -113,6 +161,23 @@ Device may send a crash log event after rebooting after a crash. The event canno
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Reboot Log event
 | 
				
			||||||
 | 
					The device may send a `reboot log event` after a reboot. This maybe a scheduled reboot or caused in some other way.
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					    "method" : "rebootLog" , 
 | 
				
			||||||
 | 
					    "params" : {
 | 
				
			||||||
 | 
					        "serial"  : <serial number> ,
 | 
				
			||||||
 | 
					        "uuid"    : <the UUID of the configuration that generated the reboot log>,
 | 
				
			||||||
 | 
					        "date"    : <Unix time when this reboot occurred>,
 | 
				
			||||||
 | 
					        "type"    : <string>,
 | 
				
			||||||
 | 
					        "info"    : [ "info 1", "info 2"]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is a possible list of reboot reasons:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Config change pending event
 | 
					#### Config change pending event
 | 
				
			||||||
Device sends this message to tell the controller that the device 
 | 
					Device sends this message to tell the controller that the device 
 | 
				
			||||||
has received a configuration but is still running an older configuration. The controller will not
 | 
					has received a configuration but is still running an older configuration. The controller will not
 | 
				
			||||||
@@ -193,7 +258,7 @@ venue where this device belongs and resend the same message to all other devices
 | 
				
			|||||||
    "params" : {
 | 
					    "params" : {
 | 
				
			||||||
        "serial" : <serial number> ,
 | 
					        "serial" : <serial number> ,
 | 
				
			||||||
        "timestamp" : <the UTC timestamp when the message was sent>,
 | 
					        "timestamp" : <the UTC timestamp when the message was sent>,
 | 
				
			||||||
        "data" : <an opaque string from the AP. This could be Zipped and so on and most likely base64 encoded>
 | 
					        "data" : <JSON document to broadcast>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@@ -298,7 +363,8 @@ Controller sends this command when it believes the device should upgrade its fir
 | 
				
			|||||||
     "params" : {
 | 
					     "params" : {
 | 
				
			||||||
	        "serial" : <serial number> ,
 | 
						        "serial" : <serial number> ,
 | 
				
			||||||
	        "when"  : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
 | 
						        "when"  : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
 | 
				
			||||||
		    "uri"   : <URI to download the firmware>
 | 
							    "uri"   : <URI to download the firmware>,
 | 
				
			||||||
 | 
					            "FWsignature" : <string representation of the signature for the FW> (optional)
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
     "id" : <some number>
 | 
					     "id" : <some number>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -318,6 +384,13 @@ The device should answer:
 | 
				
			|||||||
      "id" : <same number>
 | 
					      "id" : <same number>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					Here are the error values
 | 
				
			||||||
 | 
					```text
 | 
				
			||||||
 | 
					0:  No error
 | 
				
			||||||
 | 
					1:  Bad firmware
 | 
				
			||||||
 | 
					2:  Missing signature
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Controller wants the device to perform a factory reset
 | 
					#### Controller wants the device to perform a factory reset
 | 
				
			||||||
Controller sends this command when it believes the device should upgrade its firmware.
 | 
					Controller sends this command when it believes the device should upgrade its firmware.
 | 
				
			||||||
@@ -423,44 +496,6 @@ The device should answer:
 | 
				
			|||||||
- 1 : device cannot flash LEDs because it does not have any.
 | 
					- 1 : device cannot flash LEDs because it does not have any.
 | 
				
			||||||
- 2 : device rejects the request. `text` should include information as to why.
 | 
					- 2 : device rejects the request. `text` should include information as to why.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Controller sends a device specific command
 | 
					 | 
				
			||||||
Controller sends this command specific to this device. The command is proprietary and must be agreed upon by the device 
 | 
					 | 
				
			||||||
and the controller.
 | 
					 | 
				
			||||||
```json
 | 
					 | 
				
			||||||
{     "jsonrpc" : "2.0" , 
 | 
					 | 
				
			||||||
      "method" : "perform" , 
 | 
					 | 
				
			||||||
      "params" : {
 | 
					 | 
				
			||||||
          "serial" : <serial number> ,
 | 
					 | 
				
			||||||
          "when" : Optional - <UTC time when to perform this command, 0 mean immediate, this is a suggestion>,
 | 
					 | 
				
			||||||
          "command" : <this is device specific and is TEXT only>,
 | 
					 | 
				
			||||||
          "payload" : <JSON Document: containing additional information about the command>
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "id" : <some number>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The device should answer:
 | 
					 | 
				
			||||||
```json
 | 
					 | 
				
			||||||
{     "jsonrpc" : "2.0" , 
 | 
					 | 
				
			||||||
      "result" : {
 | 
					 | 
				
			||||||
          "serial" : <serial number> ,
 | 
					 | 
				
			||||||
          "status" : {
 | 
					 | 
				
			||||||
            "error" : 0 or an error number,
 | 
					 | 
				
			||||||
            "text" : <description of the error or success>,
 | 
					 | 
				
			||||||
            "when" : <in UTC time in seconds>,
 | 
					 | 
				
			||||||
            "resultCode" : <0 or an appropriate error code>,
 | 
					 | 
				
			||||||
            "resultText" : <any text resulting from the command. This is propietary to each command>
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "id" : <same number>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
##### The device answer
 | 
					 | 
				
			||||||
The device should answer with teh above message. The `error` value should be interpreted the following way:
 | 
					 | 
				
			||||||
- 0 : the command was performed as requested and the reults of the command is available in the `resultCode` and `resultText` parameters.
 | 
					 | 
				
			||||||
- 1 : the command will be performed in the future and `when` shows that time. The `resultCode` and `resultText` dod not contain anything relevant.
 | 
					 | 
				
			||||||
- 2 : the command cannot be performed as indicated. `resultCode` and `resultText` may contain some indication as to why.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Controller wants the device to perform a trace
 | 
					#### Controller wants the device to perform a trace
 | 
				
			||||||
Controller sends this command when it needs the device to perform a trace (i.e. tcpdump).
 | 
					Controller sends this command when it needs the device to perform a trace (i.e. tcpdump).
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
@@ -711,9 +746,11 @@ Controller sends this command to run a predefined script. Extreme care must be t
 | 
				
			|||||||
     "method" : "script" , 
 | 
					     "method" : "script" , 
 | 
				
			||||||
     "params" : {
 | 
					     "params" : {
 | 
				
			||||||
        "serial" : <serial number>,
 | 
					        "serial" : <serial number>,
 | 
				
			||||||
        "type" : <one of "shell", "ucode">,
 | 
					        "type" : <one of "shell", "ucode", "bundle">,
 | 
				
			||||||
        "script" : <text blob containing the script>,
 | 
					        "script" : <text blob containing the script, This must be vase64 encoded>,
 | 
				
			||||||
        "timeout" : <max timeout in seconds, default is 30>,
 | 
					        "timeout" : <max timeout in seconds, default is 30, unused if URI is supplied>,
 | 
				
			||||||
 | 
					        "uri":  "<upload script results using this URI>",
 | 
				
			||||||
 | 
					        "signature" : "<signature for script>: must be supplied to restricted devices",
 | 
				
			||||||
        "when" : <time when this will be performed as UTC seconds>
 | 
					        "when" : <time when this will be performed as UTC seconds>
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
     "id" : <some number>
 | 
					     "id" : <some number>
 | 
				
			||||||
@@ -738,6 +775,146 @@ The device should answer:
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Controller wants the device to replace its certificates
 | 
				
			||||||
 | 
					Controller sends this command to run a predefined script. Extreme care must be taken.
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{    "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					     "method" : "certupdate" , 
 | 
				
			||||||
 | 
					     "params" : {
 | 
				
			||||||
 | 
					        "serial" : <serial number>,
 | 
				
			||||||
 | 
					        "certificates" : <BASE64 encoded tar file of the cert package from the certificate portal>
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "id" : <some number>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The device should answer:
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{     "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					      "result" : {
 | 
				
			||||||
 | 
					          "serial" : <serial number> ,
 | 
				
			||||||
 | 
					          "status" : {
 | 
				
			||||||
 | 
					            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
 | 
				
			||||||
 | 
					            "txt" : <text describing the error or success>
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					  "id" : <same number as request>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Controller wants the device to switch to another controller
 | 
				
			||||||
 | 
					Controller sends this when the device should change the controller it connects to without looking up a new redirector.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{    "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					     "method" : "transfer" , 
 | 
				
			||||||
 | 
					     "params" : {
 | 
				
			||||||
 | 
					        "serial" : <serial number>,
 | 
				
			||||||
 | 
					        "server" : <controller hostname>,
 | 
				
			||||||
 | 
					        "port" : <controller port number (integer)>,
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "id" : <some number>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The device should answer:
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{     "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					      "result" : {
 | 
				
			||||||
 | 
					          "serial" : <serial number> ,
 | 
				
			||||||
 | 
					          "status" : {
 | 
				
			||||||
 | 
					            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
 | 
				
			||||||
 | 
					            "txt" : <text describing the error or success>
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					  "id" : <same number as request>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### RRM AP device commands
 | 
				
			||||||
 | 
					The following command is used to send RRM commands to an AP. RRM commands are send to an AP, however the 
 | 
				
			||||||
 | 
					controller will not or cannot verify if they have been sent or the action was performed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{    "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					     "method" : "rrm" , 
 | 
				
			||||||
 | 
					     "params" : {
 | 
				
			||||||
 | 
					        "serial" : <serial number>,
 | 
				
			||||||
 | 
					        "actions" : [ array of actions. Each possible action is defined next]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "id" : <some number>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The device should answer:
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{     "jsonrpc" : "2.0" , 
 | 
				
			||||||
 | 
					      "result" : {
 | 
				
			||||||
 | 
					          "serial" : <serial number> ,
 | 
				
			||||||
 | 
					          "status" : {
 | 
				
			||||||
 | 
					            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
 | 
				
			||||||
 | 
					            "txt" : <text describing the error or success>
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					  "id" : <same number as request>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### RRM Roam action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Kick
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{     
 | 
				
			||||||
 | 
					      "action" : "kick" ,
 | 
				
			||||||
 | 
					      "addr" : <mac if the client that shall be kicked> ,
 | 
				
			||||||
 | 
					      "reason": <number>, (default: 5, https://www.cisco.com/assets/sol/sb/WAP371_Emulators/WAP371_Emulator_v1-0-1-5/help/Apx_ReasonCodes2.html)
 | 
				
			||||||
 | 
					      "ban_time": <number> (seconds, optional)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Channel Switch Announcement
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   
 | 
				
			||||||
 | 
					    "action" : "channel_switch" ,
 | 
				
			||||||
 | 
					    "bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
 | 
				
			||||||
 | 
					    "channel" : <number> (HT/HW mode will be retained upon issuing the CSA)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Change TX-Power
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   
 | 
				
			||||||
 | 
					    "action" : "tx_power" ,
 | 
				
			||||||
 | 
					    "bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
 | 
				
			||||||
 | 
					    "level" : <number> (DBm inside the positive number space)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Beacon Scan
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   
 | 
				
			||||||
 | 
					    "action" : "beacon_request" ,
 | 
				
			||||||
 | 
					    "addr" : <mac if the client that shall perform the scan> ,
 | 
				
			||||||
 | 
					    "ssid": <string>, (the SSID the client shall scan for on all frequencies),
 | 
				
			||||||
 | 
					    "channel": <number> (the channel that shall be scanned)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### BSS Transition
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   
 | 
				
			||||||
 | 
					    "action" : "bss_transition" ,
 | 
				
			||||||
 | 
					    "addr" : <mac if the client that shall perform the roam> ,
 | 
				
			||||||
 | 
					    "neighbors": [ <string> ], (an array of BSSIDs the client shall consider as roamin candidates)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Update neighbours
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{   
 | 
				
			||||||
 | 
					    "action" : "neighbors" ,
 | 
				
			||||||
 | 
					    "bssid" : <mac of the SSID> , (the SSID of the specific VAP)
 | 
				
			||||||
 | 
					    "neighbors": [ [ <BSS>, <ssid>, <neighbor report> ] ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### `rtty server`
 | 
					### `rtty server`
 | 
				
			||||||
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
 | 
					More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										603
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										603
									
								
								README.md
									
									
									
									
									
								
							@@ -1,220 +1,36 @@
 | 
				
			|||||||
# uCentralGW
 | 
					<p align="center">
 | 
				
			||||||
 | 
					    <img src="images/project/logo.svg" width="200" alt="OpenWiFi Project"/>
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## What is this?
 | 
					# OpenWiFI Gateway (OWGW)
 | 
				
			||||||
The uCentralGW is an added service for the TIP controller that allows integration with the 
 | 
					
 | 
				
			||||||
uCentral protocol. It supports a complete OpenAPI definition and uses the ucentral communication protocol. To use the uCentralGW,
 | 
					## What is it?
 | 
				
			||||||
you either need to [build it](#building) or use the [Docker version](#docker).
 | 
					The OpenWiFi Gateway is a service for the TIP OpenWiFi CloudSDK (OWSDK). 
 | 
				
			||||||
 | 
					OWGW manages Access Points that implement the OpenWiFi uCentral protocol. OWGW, like all other OWSDK microservices, is
 | 
				
			||||||
 | 
					defined using an OpenAPI definition and uses the ucentral communication protocol to interact with Access Points. To use 
 | 
				
			||||||
 | 
					the OWGW, you either need to [build it](#building) or use the [Docker version](#docker).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Building
 | 
					## Building
 | 
				
			||||||
In order to build the uCentralGW, you will need to install its dependencies, which includes the following:
 | 
					To build the microservice from source, please follow the instructions in [here](./BUILDING.md)
 | 
				
			||||||
- cmake
 | 
					 | 
				
			||||||
- boost
 | 
					 | 
				
			||||||
- POCO 1.10.1 or later
 | 
					 | 
				
			||||||
- a C++17 compiler
 | 
					 | 
				
			||||||
- openssl
 | 
					 | 
				
			||||||
- libpq-dev (PortgreSQL development libraries)
 | 
					 | 
				
			||||||
- mysql-client (MySQL client)
 | 
					 | 
				
			||||||
- librdkafka
 | 
					 | 
				
			||||||
- cppkafka
 | 
					 | 
				
			||||||
- 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This 
 | 
					## Docker
 | 
				
			||||||
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
 | 
					To use the CLoudSDK deployment please follow [here](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy)
 | 
				
			||||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/AriliaWireless/poco). Building 
 | 
					 | 
				
			||||||
Poco may take several minutes depending on the platform you are building on.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Ubuntu
 | 
					 | 
				
			||||||
These instructions have proven to work on Ubuntu 20.4.
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev 
 | 
					 | 
				
			||||||
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
 | 
					 | 
				
			||||||
sudo apt install librdkafka-dev // default-libmysqlclient-dev
 | 
					 | 
				
			||||||
sudo apt install nlohmann-json-dev
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
 | 
					 | 
				
			||||||
cd poco
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
					 | 
				
			||||||
cd cppkafka
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
 | 
					 | 
				
			||||||
cd json-schema-validator
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make -j
 | 
					 | 
				
			||||||
sudo make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
 | 
					 | 
				
			||||||
cd fmtlib
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make
 | 
					 | 
				
			||||||
make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
cd wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make -j 8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Fedora
 | 
					 | 
				
			||||||
The following instructions have proven to work on Fedora 33
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel
 | 
					 | 
				
			||||||
sudo yum install yaml-cpp-devel lua-devel 
 | 
					 | 
				
			||||||
sudo dnf install postgresql.x86_64 librdkafka-devel
 | 
					 | 
				
			||||||
sudo dnf install postgresql-devel json-devel
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
 | 
					 | 
				
			||||||
cd poco
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
					 | 
				
			||||||
cd cppkafka
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
 | 
					 | 
				
			||||||
cd json-schema-validator
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make -j
 | 
					 | 
				
			||||||
sudo make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
cd wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
### OSX Build
 | 
					 | 
				
			||||||
The following instructions have proven to work on OSX Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
brew install openssl
 | 
					 | 
				
			||||||
brew install cmake
 | 
					 | 
				
			||||||
brew install libpq
 | 
					 | 
				
			||||||
brew install mysql-client
 | 
					 | 
				
			||||||
brew install apr
 | 
					 | 
				
			||||||
brew install apr-util
 | 
					 | 
				
			||||||
brew install boost
 | 
					 | 
				
			||||||
brew install yaml-cpp
 | 
					 | 
				
			||||||
brew install postgresql
 | 
					 | 
				
			||||||
brew install librdkafka
 | 
					 | 
				
			||||||
brew install nlohmann-json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
 | 
					 | 
				
			||||||
cd poco
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
					 | 
				
			||||||
cd cppkafka
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/pboettch/json-schema-validator.git --branch 2.1.0
 | 
					 | 
				
			||||||
cd json-schema-validator
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make -j
 | 
					 | 
				
			||||||
sudo make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
cd wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
make -j
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Raspberry
 | 
					 | 
				
			||||||
The build on a rPI takes a while. You can shorten that build time and requirements by disabling all the larger database 
 | 
					 | 
				
			||||||
support. You can build with only SQLite support by not installing the packages for ODBC, PostgreSQL, and MySQL by 
 | 
					 | 
				
			||||||
adding -DSMALL_BUILD=1 on the cmake build line.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev libboost-all-dev libyaml-cpp-dev
 | 
					 | 
				
			||||||
git clone https://github.com/stephb9959/poco
 | 
					 | 
				
			||||||
cd poco
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake ..
 | 
					 | 
				
			||||||
cmake --build . --config Release
 | 
					 | 
				
			||||||
sudo cmake --build . --target install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd ~
 | 
					 | 
				
			||||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
cd wlan-cloud-ucentralgw
 | 
					 | 
				
			||||||
mkdir cmake-build
 | 
					 | 
				
			||||||
cd cmake-build
 | 
					 | 
				
			||||||
cmake -DSMALL_BUILD=1 ..
 | 
					 | 
				
			||||||
make
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### After completing the build
 | 
					 | 
				
			||||||
After completing the build, you can remove the Poco source as it is no longer needed. 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Expected directory layout
 | 
					#### Expected directory layout
 | 
				
			||||||
From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories.
 | 
					From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories.
 | 
				
			||||||
```shell
 | 
					```bash
 | 
				
			||||||
mkdir certs
 | 
					mkdir certs
 | 
				
			||||||
mkdir certs/cas
 | 
					mkdir certs/cas
 | 
				
			||||||
mkdir logs
 | 
					mkdir logs
 | 
				
			||||||
mkdir uploads
 | 
					mkdir uploads
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					 | 
				
			||||||
You should now have the following:
 | 
					You should now have the following:
 | 
				
			||||||
 | 
					```text
 | 
				
			||||||
```
 | 
					--+-- certs
 | 
				
			||||||
-- cert_scripts
 | 
					 | 
				
			||||||
  |
 | 
					 | 
				
			||||||
  +-- certs
 | 
					 | 
				
			||||||
  |   +--- cas
 | 
					  |   +--- cas
 | 
				
			||||||
  +-- cmake
 | 
					  +-- cmake
 | 
				
			||||||
  +-- cmake-build
 | 
					  +-- cmake-build
 | 
				
			||||||
  +-- logs (dir)
 | 
					  +-- logs
 | 
				
			||||||
  +-- src
 | 
					  +-- src
 | 
				
			||||||
  +-- test_scripts
 | 
					  +-- test_scripts
 | 
				
			||||||
  +-- openapi
 | 
					  +-- openapi
 | 
				
			||||||
@@ -223,12 +39,16 @@ You should now have the following:
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Certificates
 | 
					### Certificates
 | 
				
			||||||
Love'em of hate'em, we gotta use'em. So we tried to make this as easy as possible for you. 
 | 
					The OWGW uses a number of certificates to provide security. There are 2 types of certificates required for 
 | 
				
			||||||
 | 
					a normal deployment:
 | 
				
			||||||
 | 
					- A Server Certificate to secure the OWGW<->AP channel
 | 
				
			||||||
 | 
					- A REST API Certificate to secure the Northbound API
 | 
				
			||||||
 | 
					- Device Certificates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### The `certs` directory
 | 
					#### The `certs` directory
 | 
				
			||||||
For all deployments, you will need the following certs directory, populated with the proper files.
 | 
					For all deployments, you will need the following certs directory, populated with the proper files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```asm
 | 
					```text
 | 
				
			||||||
certs ---+--- root.pem
 | 
					certs ---+--- root.pem
 | 
				
			||||||
         +--- issuer.pem
 | 
					         +--- issuer.pem
 | 
				
			||||||
         +--- websocket-cert.pem
 | 
					         +--- websocket-cert.pem
 | 
				
			||||||
@@ -243,155 +63,22 @@ certs ---+--- root.pem
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### DigiCert files
 | 
					#### DigiCert files
 | 
				
			||||||
These are the files you should install on your gateway and devices. For your gateway, you will need to provide tge following files in the directory above
 | 
					These are the files you should install on your OWGW and devices. For your OWGW, you will need to provide tge following files in the directory above
 | 
				
			||||||
- `root.pem` is [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/root.pem).
 | 
					- `root.pem` is [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/root.pem).
 | 
				
			||||||
- `issuer.pem` is [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/issuer.pem).
 | 
					- `issuer.pem` is [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/issuer.pem).
 | 
				
			||||||
- `clientcas.pem` is [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/clientcas.pem).
 | 
					- `clientcas.pem` is [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/clientcas.pem).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Gateway certificates: TIP portion (* must be obtained from TIP)
 | 
					#### OWGW Server certificate (must be obtained from TIP)
 | 
				
			||||||
The gateway requires its own DigiCert certificate. Once obtained, you need to identify the `key` and the `certificate` rename
 | 
					The gateway requires its own DigiCert certificate. Once obtained, you need to identify the `key` and the `certificate` rename
 | 
				
			||||||
them `websocket-key.pem` and `websocket-cert.pem`, and copy them in your `certs` directory. These files mus be obtained from TIP.
 | 
					them `websocket-key.pem` and `websocket-cert.pem`, and copy them in your `certs` directory. These files mus be obtained from TIP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Gateway certificates: for REST API
 | 
					#### OWGW for certificate: for REST API (from your favourite Certificate Provider)
 | 
				
			||||||
The gateway requires a key/vertificate/ca for the REST interface. These files you need to obtain on your own of generate them. This is beyond the scope of this 
 | 
					The gateway requires a key/certificate/ca for the REST interface. These files you need to obtain on your own or generate them. This is beyond the scope of this 
 | 
				
			||||||
document. Once you have these files, you need to renamed them `restapi-key.pem`, `restapi-cert.pem`, and `restapi-ca.pem`. This will guarantee proper HTTPS
 | 
					document. You, may choose to select LestEncrypt or any other Certificate Authority. Once you have these files, you need to renamed them `restapi-key.pem`, `restapi-cert.pem`, and `restapi-ca.pem`. 
 | 
				
			||||||
in your browner 
 | 
					This will guarantee proper HTTPS in your browser and RESTAPI. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Configuration
 | 
					### OpenWiFi Device certificates
 | 
				
			||||||
The configuration for this service is kept in a properties file. This file is called `owgw.properties` and you can 
 | 
					This may have already done at the factory. If not, you will need to get the following in order to point your devices to use the OWGW:
 | 
				
			||||||
see the latest version [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/owgw.properties). The file will be loaded from
 | 
					 | 
				
			||||||
the directory set by the environment variable `UCENTRALGW_CONFIG`. To use environment variables in the configuration,
 | 
					 | 
				
			||||||
you must use `$<varname>`. Only `path names` support the use of environment variables. The sample configuration requires very 
 | 
					 | 
				
			||||||
little changes if you keep the suggested directory structure. For the sample configuration to work, you need to define 2 
 | 
					 | 
				
			||||||
environment variables. 
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
export OWGW_ROOT=`pwd`
 | 
					 | 
				
			||||||
export OWGW_CONFIG=`pwd`
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
If you current working directory is the root of the project, this will set the variables properly. Otherwise, you can set the variables 
 | 
					 | 
				
			||||||
to point to wherever is necessary.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
##### Important config entries
 | 
					 | 
				
			||||||
###### This is the logging directory
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
logging.channels.c2.path = $OWGW_ROOT/logs/sample.log
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### This is the type of storage in use
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
storage.type = sqlite
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### Autoprovisioning settings
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
openwifi.autoprovisioning = true
 | 
					 | 
				
			||||||
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
 | 
					 | 
				
			||||||
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
 | 
					 | 
				
			||||||
openwifi.devicetypes.2 = IOT:esp32
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### This is the RESTAPI endpoint
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.backlog = 100
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.security = relaxed
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.address = *
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.port = 16002
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.key.password = mypassword
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
##### This is the end point for the devices to connect with
 | 
					 | 
				
			||||||
This is the crucial section. I bet that 97.4% of all your problems will come from here, and it's boring. So put some good music on, 
 | 
					 | 
				
			||||||
give the kids the iPad, get a cup of coffee, and pay attention. Every field will be explained.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.backlog
 | 
					 | 
				
			||||||
This is the number of concurrent devices you are expecting to call all at once. Not the current number of devices. This is how many will connect in the same exact second. 
 | 
					 | 
				
			||||||
Take the total number of devices you have and divide by 100. That's a good rule of thumb. Never go above 500.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.rootca
 | 
					 | 
				
			||||||
This is the root file as supplied by Digicert. You can find it [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/root.pem) 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.issuer
 | 
					 | 
				
			||||||
This is the issuer file as supplied by Digicert. You can find it [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/issuer.pem)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.cert
 | 
					 | 
				
			||||||
This is a `pem` file that you will receive from Digicert for the gateway itself. This is the certificate for the gateway. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.key
 | 
					 | 
				
			||||||
This is a `pem` file that you will receive from Digicert for the gateway itself. The is the private key for the gateway.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.clientcas
 | 
					 | 
				
			||||||
This is a `pem` file that contains both the issuer and the root CA certificates. You can find it You can find it [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/clientcas.pem)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.cas
 | 
					 | 
				
			||||||
This is a directory where you will copy your own `cert.pem`, the `root.pem`, and the `issuer.pem` files.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.address
 | 
					 | 
				
			||||||
Leve this a `*` in teh case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.port
 | 
					 | 
				
			||||||
Leave to 15002 for now. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.security
 | 
					 | 
				
			||||||
Leave this as strict for now for devices.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.host.0.key.password
 | 
					 | 
				
			||||||
If you key file uses a password, please enter it here.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### ucentral.websocket.maxreactors
 | 
					 | 
				
			||||||
A single reactor can handle between 1000-2000 devices. Never leave this smaller than 5 or larger than 50.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Conclusion 
 | 
					 | 
				
			||||||
You will need to get the `cert.pem` and `key.pem` from Digicert. The rest is here.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.backlog = 500
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.rootca = $OWGW_ROOT/certs/root.pem
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.issuer = $OWGW_ROOT/certs/issuer.pem
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.cert = $OWGW_ROOT/certs/websocket-cert.pem
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.key = $OWGW_ROOT/certs/websocket-key.pem
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.clientcas = $OWGW_ROOT/certs/clientcas.pem
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.cas = $OWGW_ROOT/certs/cas
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.address = *
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.port = 15002
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.security = strict
 | 
					 | 
				
			||||||
ucentral.websocket.host.0.key.password = mypassword
 | 
					 | 
				
			||||||
ucentral.websocket.maxreactors = 20
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### This is the end point for the devices when uploading files
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.backlog = 100
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.security = relaxed
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.address = *
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.name = 192.168.1.176
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.port = 16003
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.key.password = mypassword
 | 
					 | 
				
			||||||
openwifi.fileuploader.path = $OWGW_ROOT/uploads
 | 
					 | 
				
			||||||
openwifi.fileuploader.maxsize = 10000
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### host.0.address entries
 | 
					 | 
				
			||||||
If you want to limit traffic to a specific interface, you should specify the IP address of that interface instead of 
 | 
					 | 
				
			||||||
the `*`. Using the `*` means all interfaces will be able to accept connections. You can add multiple interfaces 
 | 
					 | 
				
			||||||
by changing the `0` to another index. You need to repeat the whole configuration block for each index. Indexes must be sequential
 | 
					 | 
				
			||||||
start at `0`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
###### openwifi.fileuploader.host.0.name
 | 
					 | 
				
			||||||
This must point to the IP or FQDN of your uCentralGW.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Running the gateway
 | 
					 | 
				
			||||||
Tu run the gateway, you must run the executable `ucentralgw`. You can use several command line options to run as a daemon or specify the configuration file location. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Device configuration
 | 
					 | 
				
			||||||
Once you have the gateway configured, you will need to have some devices coming to it. For now, you will need to get
 | 
					 | 
				
			||||||
the following in order to use the gateway:
 | 
					 | 
				
			||||||
- A DigiCert certificate that you will call `cert.pem`
 | 
					- A DigiCert certificate that you will call `cert.pem`
 | 
				
			||||||
- A DigiCert key that goes with that certificate. Please call this `key.pem`
 | 
					- A DigiCert key that goes with that certificate. Please call this `key.pem`
 | 
				
			||||||
- The Digicert root certificate that you will find [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/root.pem). You must copy `root.pem`
 | 
					- The Digicert root certificate that you will find [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/certificates/root.pem). You must copy `root.pem`
 | 
				
			||||||
@@ -403,23 +90,42 @@ You will need to upgrade your device to the latest firmware. Once updated, you w
 | 
				
			|||||||
the `/certificates` directory. Please remove all old keys or certificates from the `/etc/ucentral` directory
 | 
					the `/certificates` directory. Please remove all old keys or certificates from the `/etc/ucentral` directory
 | 
				
			||||||
(anything ending in `.pem`).
 | 
					(anything ending in `.pem`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Server key entry
 | 
					### Environment variables
 | 
				
			||||||
The gateway needs to encrypt information from time to time. In order to do so, it must have a crypto key. This key
 | 
					The following environment variables should be set from the root directory of the service. They tell the OWGW process where to find 
 | 
				
			||||||
can be any of the keys you are already using. You must keep that keep secret and always use it. In the configutation,
 | 
					the configuration and the root directory.
 | 
				
			||||||
this is the entry
 | 
					```bash
 | 
				
			||||||
 | 
					export OWGW_ROOT=`pwd`
 | 
				
			||||||
```asm
 | 
					export OWGW_CONFIG=`pwd`
 | 
				
			||||||
openwifi.service.key = $OWGW_ROOT/certs/websocket-key.pem
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					You can run the shell script `set_env.sh` from the microservice root.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Command line options
 | 
					### OWGW Service Configuration
 | 
				
			||||||
 | 
					The configuration is kept in a file called `owgw.properties`. To understand the content of this file, 
 | 
				
			||||||
 | 
					please look [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONFIGURATION.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Running the OWGW
 | 
				
			||||||
 | 
					Tu run the OWGW, you must run the executable `owgw`. You can use several command line options to run as a daemon or 
 | 
				
			||||||
 | 
					specify the configuration file location.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### systemd: owgw.service
 | 
				
			||||||
 | 
					`owgw.service` is a skeleton to allow to run the OWGW in a systemd based operating system (i.e. Debian). You will need 
 | 
				
			||||||
 | 
					to modify slightly to reflect your environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Default device configuration
 | 
				
			||||||
 | 
					By default, the devices will receive a built-in default configuration. This built-in default configuration is probably not what you need. 
 | 
				
			||||||
 | 
					So there are 2 options in order to specify your own default configuration:
 | 
				
			||||||
 | 
					- In the OWGW data directory, you can create a `default_config.json` file that contains your own personal configuration
 | 
				
			||||||
 | 
					- Using the OWGW UI, on the left hand pane, there is a `configurations` choice. There you can do the same but apply it with more granularity ot each device type 
 | 
				
			||||||
 | 
					you may be deploying.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Command line options
 | 
				
			||||||
The current implementation supports the following. If you use the built-in configuration file, you do not need to use any command-line
 | 
					The current implementation supports the following. If you use the built-in configuration file, you do not need to use any command-line
 | 
				
			||||||
options. However, you may decide to use the `--daemon` or `umask` options. 
 | 
					options. However, you may decide to use the `--daemon` or `umask` options. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
./ucentralgw --help
 | 
					./owgw --help
 | 
				
			||||||
usage: ucentralgw OPTIONS
 | 
					usage: owgw OPTIONS
 | 
				
			||||||
A uCentral gateway implementation for TIP.
 | 
					A owgw gateway implementation for TIP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--daemon        Run application as a daemon.
 | 
					--daemon        Run application as a daemon.
 | 
				
			||||||
--umask=mask    Set the daemon's umask (octal, e.g. 027).
 | 
					--umask=mask    Set the daemon's umask (octal, e.g. 027).
 | 
				
			||||||
@@ -430,119 +136,27 @@ A uCentral gateway implementation for TIP.
 | 
				
			|||||||
--logs=dir      specify the log directory and file (i.e. dir/file.log)
 | 
					--logs=dir      specify the log directory and file (i.e. dir/file.log)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##### file
 | 
					#### file
 | 
				
			||||||
This allows you to point to another file without specifying the UCENTRALGW_CONFIG variable. The file name must end in `.properties`.
 | 
					This allows you to point to another file without specifying the OWGW_CONFIG variable. The file name must end in `.properties`.
 | 
				
			||||||
##### daemon
 | 
					#### daemon
 | 
				
			||||||
Run this as a UNIX service
 | 
					Run this as a UNIX service
 | 
				
			||||||
##### pidfile
 | 
					#### pidfile
 | 
				
			||||||
When running as a daemon, the pid of the running service will be set in the speficied file
 | 
					When running as a daemon, the pid of the running service will be set in the speficied file
 | 
				
			||||||
##### debug
 | 
					#### debug
 | 
				
			||||||
Run the service in debug mode.
 | 
					Run the service in debug mode.
 | 
				
			||||||
##### logs
 | 
					#### logs
 | 
				
			||||||
Speficy where logs should be kept. You must include an existing directory and a file name. For example `/var/ucentral/logs/log.0`.
 | 
					Speficy where logs should be kept. You must include an existing directory and a file name. For example `/var/ucentral/logs/log.0`.
 | 
				
			||||||
##### umask
 | 
					#### umask
 | 
				
			||||||
Seet the umask for the running service.
 | 
					Seet the umask for the running service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### ALB Support
 | 
					## Docker
 | 
				
			||||||
Support for AWS ALB is provided through the following configuration elements
 | 
					If you would rather launch the docker-compose or helm for the controller, please click [here](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy).
 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
alb.enable = true
 | 
					 | 
				
			||||||
alb.port = 16102
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Docker
 | 
					 | 
				
			||||||
So building this thing from scratch is not your thing? I can't blame you. It takes some patience and 
 | 
					 | 
				
			||||||
in the end, there's still more work. Here comes `docker` to the rescue. You can run a docker version following
 | 
					 | 
				
			||||||
these instructions. The following is the content of the `docker_run.sh` script you can find
 | 
					 | 
				
			||||||
[here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/docker_run.sh):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
#!/bin/sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					 | 
				
			||||||
IMAGE_NAME=ucentralgw
 | 
					 | 
				
			||||||
DOCKER_NAME=$HUBNAME/$IMAGE_NAME
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CONTAINER_NAME=ucentralgw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#stop previously running images
 | 
					 | 
				
			||||||
docker container stop $CONTAINER_NAME
 | 
					 | 
				
			||||||
docker container rm $CONTAINER_NAME --force
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -d logs ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
    mkdir logs
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -d certs ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
  echo "certs directory does not exist. Please create and add the proper certificates."
 | 
					 | 
				
			||||||
  exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -f owgw.properties ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
  echo "Configuration file owgw.properties is missing in the current directory"
 | 
					 | 
				
			||||||
  exit 2
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
docker run -d -p 15002:15002 \
 | 
					 | 
				
			||||||
              -p 16002:16002 \
 | 
					 | 
				
			||||||
              -p 16003:16003 \
 | 
					 | 
				
			||||||
              --init \
 | 
					 | 
				
			||||||
              --volume="$PWD:/ucentral-data" \
 | 
					 | 
				
			||||||
              -e UCENTRAL_ROOT="/ucentral-data" \
 | 
					 | 
				
			||||||
              -e UCENTRALGW_CONFIG="/ucentral-data" \
 | 
					 | 
				
			||||||
              --name="ucentralgw" $DOCKER_NAME
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Create yourself a directory and copy that script which you can also get from [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/docker_run.sh).
 | 
					 | 
				
			||||||
You must have the basic configuration file copied in the directory. This file must be called `owgw.properties`. You can bring your own or
 | 
					 | 
				
			||||||
copy it from [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/owgw.properties). Please look at [this](#certificates-with-docker) to have the right 
 | 
					 | 
				
			||||||
certificates. You need to make sure that the names match the content of the `owgw.properties`
 | 
					 | 
				
			||||||
file. Once all this is done, you can simply run `docker_run.sh`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Docker installation directory layout
 | 
					 | 
				
			||||||
Here is the layout expected for your Docker installation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
Run-time root
 | 
					 | 
				
			||||||
    |
 | 
					 | 
				
			||||||
    ----- certs (same as above)
 | 
					 | 
				
			||||||
    +---- logs  (dir)
 | 
					 | 
				
			||||||
    +---- uploads  (dir)
 | 
					 | 
				
			||||||
    +---- owgw.properties (file)
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `owgw.properties` for Docker
 | 
					 | 
				
			||||||
If you use the pre-made configuration file, and you follow the directory layout, the only line you must change 
 | 
					 | 
				
			||||||
is the following line:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
openwifi.fileuploader.host.0.name = 192.168.1.176
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This line should reflect the IP of your gateway or its FQDN. You must make sure that this name or IP is accessible
 | 
					 | 
				
			||||||
from your devices. This is used during file uploads from the devices.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Certificates with Docker
 | 
					 | 
				
			||||||
Please refer to the `certs` directory from the sections above.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Configuration with Docker
 | 
					 | 
				
			||||||
The configuration for this service is kept in a properties file. Currently, this configuration file must be kept in the 
 | 
					 | 
				
			||||||
current directory of uCentral or one level up. This file is called `owgw.properties` and you can see the latest version
 | 
					 | 
				
			||||||
[here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/owgw.properties). The file will be loaded from 
 | 
					 | 
				
			||||||
the directory set by the environment variable `UCENTRALGW_CONFIG`. To use environment variables in the configuration,
 | 
					 | 
				
			||||||
you must use `$<varname>`. The path for the logs for the service must exist prior to starting the 
 | 
					 | 
				
			||||||
service. The path is defined under `logging.channels.c2.path`. Only `path names` support the use of 
 | 
					 | 
				
			||||||
environment variables. Here is a sample configuration:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## uCentral communication protocol
 | 
					## uCentral communication protocol
 | 
				
			||||||
The communication protocol between the device and the controller is detailed in this [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/PROTOCOL.md).
 | 
					The communication protocol between the device and the OGWG is detailed in this [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/PROTOCOL.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## OpenAPI
 | 
					## OpenAPI
 | 
				
			||||||
The service supports an OpenAPI REST based interface for management. You can find the [definition here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/openapi/ucentral/owgw.yaml).
 | 
					The OWGW supports an OpenAPI REST based interface for management. You can find the [definition here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/openapi/ucentral/owgw.yaml).
 | 
				
			||||||
And here is [how to use it](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/OPENAPI.md)
 | 
					And here is [how to use it](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/OPENAPI.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Using the API
 | 
					## Using the API
 | 
				
			||||||
@@ -552,58 +166,31 @@ or [python](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/ma
 | 
				
			|||||||
More scripts will be added in the future.
 | 
					More scripts will be added in the future.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Firewall Considerations
 | 
					## Firewall Considerations
 | 
				
			||||||
- The protocol uses TCP port 15002 between the devices and the gateway. This port must be opened.
 | 
					| Port | Description | Configurable |
 | 
				
			||||||
- Devices use the TCP port 16003 to upload files. This port is configurable in the `owgw.properties` file. Look for `openwifi.fileuploader.host.0.port`.
 | 
					| :--- | :--- |:------------:|
 | 
				
			||||||
- The RESTAPI is accessed through TCP port 16002 by default. This port is configurable in the `owgw.properties` file. Look for the entry `openwifi.restapi.host.0.port`.
 | 
					| 15002 | Default port from the devices to the OWGW |     yes      |
 | 
				
			||||||
 | 
					| 16002 | Default port for REST API Access to the OWGW |     yes      |
 | 
				
			||||||
 | 
					| 5912 | Default port for RTTY connection |     yes      |
 | 
				
			||||||
 | 
					| 5913 | Defailt port for RTTY connection |     yes      |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Kafka integration
 | 
					## Kafka topics
 | 
				
			||||||
So what about Kafka? Well, the gateway has basic integration with Kafka. It is turned off by default, to turn it on, in the configuration:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```asm
 | 
					 | 
				
			||||||
openwifi.kafka.enable = false
 | 
					 | 
				
			||||||
openwifi.kafka.brokerlist = 127.0.0.1:9092
 | 
					 | 
				
			||||||
openwifi.kafka.commit = false
 | 
					 | 
				
			||||||
openwifi.kafka.queue.buffering.max.ms = 50
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `openwifi.kafka.enable`
 | 
					 | 
				
			||||||
Kind of obvious but hey, set `true` or `false`. Default is `false`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `openwifi.kafka.brokerlist`
 | 
					 | 
				
			||||||
This is a comma separator list of the brokers in your `kafka` deployment. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Kafka topics
 | 
					 | 
				
			||||||
Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md)
 | 
					Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Securing `kafka`
 | 
					## Contributions
 | 
				
			||||||
This is beyond the scope of this document. As it stands today, the communication between the gateway and `kafka` is expected to be behind a firewall.
 | 
					We need more contributors. Should you wish to contribute, 
 | 
				
			||||||
 | 
					please follow the [contributions](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONTRIBUTING.md) document.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### `iptocountry` feature
 | 
					## Pull Requests
 | 
				
			||||||
In the UI, you will notice the presence of small flags showing where the device connections are from. This feature is 
 | 
					Please create a branch with the Jira addressing the issue you are fixing or the feature you are implementing. 
 | 
				
			||||||
available through the `iptocountry` settings in the configuration. This feature is then also available through the `OpenAPI` for the CLI 
 | 
					Create a pull-request from the branch into master. 
 | 
				
			||||||
and other applications.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
##### Config file entries
 | 
					## Additional OWSDK Microservices
 | 
				
			||||||
In the configuration file, you must include the following lines:
 | 
					Here is a list of additional OWSDK microservices
 | 
				
			||||||
 | 
					| Name | Description | Link | OpenAPI |
 | 
				
			||||||
```asm
 | 
					| :--- | :--- | :---: | :---: |
 | 
				
			||||||
iptocountry.default = US
 | 
					| OWSEC | Security Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml) |
 | 
				
			||||||
iptocountry.provider = ipinfo
 | 
					| OWGW | Controller Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/openapi/owgw.yaml) |
 | 
				
			||||||
#iptocountry.provider = ipdata
 | 
					| OWFMS | Firmware Management Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms/blob/main/openapi/owfms.yaml) |
 | 
				
			||||||
#iptocountry.provider = ipdata
 | 
					| OWPROV | Provisioning Service | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov) | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/owprov.yaml) |
 | 
				
			||||||
iptocountry.ipinfo.token = 
 | 
					| OWANALYTICS | Analytics Service | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics) | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics/blob/main/openapi/owanalytics.yaml) |
 | 
				
			||||||
#ip2location.ipinfo.token =
 | 
					| OWSUB | Subscriber Service | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal) | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal/blob/main/openapi/userportal.yaml) |
 | 
				
			||||||
#iptocountry.ipdata.apikey =
 | 
					 | 
				
			||||||
#iptocountry.ip2location.apikey =
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
So you select your provider with the `iptocountry.provider` be specifying ipinfo, or ipdata, or ip2location. 
 | 
					 | 
				
			||||||
And then you provide the corresponding api key or token.
 | 
					 | 
				
			||||||
Only select one. If you select 2, undefined behaviour. All the line you do not need, just put a `#` before to comment it 
 | 
					 | 
				
			||||||
out.
 | 
					 | 
				
			||||||
You will find the supported providers at: `ip2location.com`, `ipinfo.io`, or `ipdata.co`. You MUST supply a valid default 
 | 
					 | 
				
			||||||
country code in `iptocountry.default`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Contributors
 | 
					 | 
				
			||||||
We love ya! We need more of ya! If you want to contribute, make sure you review 
 | 
					 | 
				
			||||||
the [coding style](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CODING_STYLE.md) document. 
 | 
					 | 
				
			||||||
Feel free to ask questions and post issues. 
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										82
									
								
								RESTRICTED_DEVICES.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								RESTRICTED_DEVICES.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					# Restricted devices
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What is a restricted device?
 | 
				
			||||||
 | 
					A restricted device is one that because of regulations or a desire for utmost security, requires signatures to access restricted or blocked 
 | 
				
			||||||
 | 
					features. The restriction process is burnt in the device at manufacturing or later by running a specific command on the device. Once a device
 | 
				
			||||||
 | 
					is restricted, it cannot be unlocked. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Current restrictions
 | 
				
			||||||
 | 
					Restrictions are stored on the AP in a protected partition. They are contained in a file called `restrictions.json`. Here is a sample:
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					        "country": [
 | 
				
			||||||
 | 
					                "US", "CA"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "dfs": true,
 | 
				
			||||||
 | 
					        "rtty": true,
 | 
				
			||||||
 | 
					        "tty": true,
 | 
				
			||||||
 | 
					        "developer": true,
 | 
				
			||||||
 | 
					        "sysupgrade": true,
 | 
				
			||||||
 | 
					        "commands": true,
 | 
				
			||||||
 | 
					        "key_info": {
 | 
				
			||||||
 | 
					                "vendor": "dummy",
 | 
				
			||||||
 | 
					                "algo": "static"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					- country
 | 
				
			||||||
 | 
					  - List of countries where this device may be used
 | 
				
			||||||
 | 
					- dfs
 | 
				
			||||||
 | 
					  - Disallow DFS Override during wifi-scan. If set to `true`, device will not allow to override DFS channels
 | 
				
			||||||
 | 
					- rtty
 | 
				
			||||||
 | 
					  - Disallow the use of the RTTY command for this device
 | 
				
			||||||
 | 
					- tty
 | 
				
			||||||
 | 
					  - Do not allow the AP to accept `tty` connection
 | 
				
			||||||
 | 
					- developer
 | 
				
			||||||
 | 
					  - Internal use only.
 | 
				
			||||||
 | 
					- sysupgrade
 | 
				
			||||||
 | 
					  - If set to `true`, only signed firmware upgrade command will be allowed.
 | 
				
			||||||
 | 
					- commands
 | 
				
			||||||
 | 
					  - If set to `true`, do not allow commands.
 | 
				
			||||||
 | 
					- key_info
 | 
				
			||||||
 | 
					  - This structure defines how signatures should be generated and verified in a secure system
 | 
				
			||||||
 | 
					    - vendor
 | 
				
			||||||
 | 
					      - An identified that must match the vendor name provided in the controller
 | 
				
			||||||
 | 
					    - algo
 | 
				
			||||||
 | 
					      - The signature algorithm. Here are the supported algorithms
 | 
				
			||||||
 | 
					        - `static`
 | 
				
			||||||
 | 
					          - A test algorithm that always returns and uses a value of `aaaaaaaaaa`. This should never be used in the field.
 | 
				
			||||||
 | 
					        - `dgst-sha256`
 | 
				
			||||||
 | 
					          - The default OpenSSL RSA signature generation and verification. The controller will use the following command to generate the signature
 | 
				
			||||||
 | 
					          ```sh
 | 
				
			||||||
 | 
					          openssl dgst -sha256 -sign private-key.pem -out signature.txt myfile
 | 
				
			||||||
 | 
					          ```
 | 
				
			||||||
 | 
					          - The AP will be using the following to verify the signature
 | 
				
			||||||
 | 
					          ```sh
 | 
				
			||||||
 | 
					          openssl dgst -sha256 -verify public-key.pem -signature signature.txt myfile
 | 
				
			||||||
 | 
					          ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Creating signatures on the controller
 | 
				
			||||||
 | 
					When a device is restricted and a signature is required, the controller can generate the signature 
 | 
				
			||||||
 | 
					for the specified `vendor`. However, on the controlelr side, you must configure the vendors. In
 | 
				
			||||||
 | 
					order to do so we suggest the following.
 | 
				
			||||||
 | 
					- Create a directory called `signatures` under your `certs` directory
 | 
				
			||||||
 | 
					- Copy the public and private keys for each `vendor` name. We suggest naming them accordingly
 | 
				
			||||||
 | 
					  - `vendor`-private-key.pem
 | 
				
			||||||
 | 
					  - `vendor`-public-key.pem
 | 
				
			||||||
 | 
					- In the `owgw.properties` file, you need to declare these signatures the following way
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					    signature.manager.0.key.public = $OWGW_ROOT/certs/signatures/test1-public-key.pem
 | 
				
			||||||
 | 
					    signature.manager.0.key.private = $OWGW_ROOT/certs/signatures/test1-private-key.pem
 | 
				
			||||||
 | 
					    signature.manager.0.vendor = test1
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    signature.manager.1.key.public = $OWGW_ROOT/certs/signatures/test2-public-key.pem
 | 
				
			||||||
 | 
					    signature.manager.1.key.private = $OWGW_ROOT/certs/signatures/test2-private-key.pem
 | 
				
			||||||
 | 
					    signature.manager.1.vendor = test2
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## How do you use the signatures?
 | 
				
			||||||
 | 
					There is nothing to do really. Now the controller will use the proper key to create the signatures 
 | 
				
			||||||
 | 
					when it sends commands to the AP. It will use the algorithm that the device understands too. This is transparent 
 | 
				
			||||||
 | 
					to the user. The `vendor` name used in the controller configuration must match the `vendor` name provided in the 
 | 
				
			||||||
 | 
					`restrictions.json` file.
 | 
				
			||||||
							
								
								
									
										0
									
								
								ap_scripts/Author 1/AUTHORS.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/AUTHORS.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								ap_scripts/Author 1/LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								ap_scripts/Author 1/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/README.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										36
									
								
								ap_scripts/Author 1/content.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								ap_scripts/Author 1/content.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					scripts:
 | 
				
			||||||
 | 
					  - name: List Antennas
 | 
				
			||||||
 | 
					    description: A script to list all antennas on a device
 | 
				
			||||||
 | 
					    type: shell
 | 
				
			||||||
 | 
					    runtype:
 | 
				
			||||||
 | 
					      timeout: 30
 | 
				
			||||||
 | 
					    filename: listantennas.sh
 | 
				
			||||||
 | 
					    readme: listantennas.md
 | 
				
			||||||
 | 
					    help: https://authors.com/scripts/index.html
 | 
				
			||||||
 | 
					  - name: List AP Noise
 | 
				
			||||||
 | 
					    description: A script to list all noise values on all APs
 | 
				
			||||||
 | 
					    type: shell
 | 
				
			||||||
 | 
					    runtype:
 | 
				
			||||||
 | 
					      deferred: true
 | 
				
			||||||
 | 
					    filename: listnoise.sh
 | 
				
			||||||
 | 
					    readme: listnoise.md
 | 
				
			||||||
 | 
					    help: https://authors.com/scripts/index.html
 | 
				
			||||||
 | 
					  - name: Reset AP Statistics
 | 
				
			||||||
 | 
					    description: A script to reset the statistics on a given AP
 | 
				
			||||||
 | 
					    type: shell
 | 
				
			||||||
 | 
					    runtype:
 | 
				
			||||||
 | 
					      timeout: 30
 | 
				
			||||||
 | 
					    filename: resetstats.sh
 | 
				
			||||||
 | 
					    readme: resetstats.md
 | 
				
			||||||
 | 
					    help: https://authors.com/scripts/index.html
 | 
				
			||||||
 | 
					  - name: Gather kernel stats
 | 
				
			||||||
 | 
					    description: A script to all the kernel stats for an AP
 | 
				
			||||||
 | 
					    type: bundle
 | 
				
			||||||
 | 
					    runtype:
 | 
				
			||||||
 | 
					      deferred: true
 | 
				
			||||||
 | 
					    filename: kstats.uci
 | 
				
			||||||
 | 
					    readme: kstats.md
 | 
				
			||||||
 | 
					    help: https://authors.com/scripts/index.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								ap_scripts/Author 1/kstats.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/kstats.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								ap_scripts/Author 1/kstats.uci
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/kstats.uci
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								ap_scripts/Author 1/listantennas.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/listantennas.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								ap_scripts/Author 1/listantennas.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ap_scripts/Author 1/listantennas.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
							
								
								
									
										0
									
								
								ap_scripts/Author 1/listnoise.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/listnoise.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										2
									
								
								ap_scripts/Author 1/listnoise.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								ap_scripts/Author 1/listnoise.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								ap_scripts/Author 1/resetstats.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ap_scripts/Author 1/resetstats.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										2
									
								
								ap_scripts/Author 1/resetstats.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								ap_scripts/Author 1/resetstats.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								ap_scripts/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ap_scripts/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					# Repo for scripts
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,4 +0,0 @@
 | 
				
			|||||||
#include <librdkafka/rdkafka.h>
 | 
					 | 
				
			||||||
 #if RD_KAFKA_VERSION >= 0x00090400
 | 
					 | 
				
			||||||
 int main() { }
 | 
					 | 
				
			||||||
 #endif
 | 
					 | 
				
			||||||
							
								
								
									
										26
									
								
								config.yaml
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								config.yaml
									
									
									
									
									
								
							@@ -1,26 +0,0 @@
 | 
				
			|||||||
tip:
 | 
					 | 
				
			||||||
  port: 6051
 | 
					 | 
				
			||||||
  server: ssc.wlan.local
 | 
					 | 
				
			||||||
  username: support@example.com
 | 
					 | 
				
			||||||
  password: support
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
certificates:
 | 
					 | 
				
			||||||
  keyfile: keyfile.pem
 | 
					 | 
				
			||||||
  certfile: certfile.pem
 | 
					 | 
				
			||||||
  password: mypassword
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ucentral:
 | 
					 | 
				
			||||||
  port: 1991
 | 
					 | 
				
			||||||
  listeners: 100
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
logger:
 | 
					 | 
				
			||||||
  size: 10
 | 
					 | 
				
			||||||
  days: 31
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ui:
 | 
					 | 
				
			||||||
  port: 9771
 | 
					 | 
				
			||||||
  username: support@example.com
 | 
					 | 
				
			||||||
  password: support
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -6,35 +6,35 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
 | 
				
			|||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
					if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
				
			||||||
    WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
 | 
					    WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\${APP_ROOT}/certs/root.pem"} \
 | 
				
			||||||
    WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
 | 
					    WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\${APP_ROOT}/certs/issuer.pem"} \
 | 
				
			||||||
    WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
 | 
					    WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\${APP_ROOT}/certs/websocket-cert.pem"} \
 | 
				
			||||||
    WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
 | 
					    WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\${APP_ROOT}/certs/websocket-key.pem"} \
 | 
				
			||||||
    WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
 | 
					    WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\${APP_ROOT}/certs/clientcas.pem"} \
 | 
				
			||||||
    WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
 | 
					    WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\${APP_ROOT}/certs/cas"} \
 | 
				
			||||||
    WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
 | 
					    WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
 | 
				
			||||||
    WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
					    WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
 | 
					    RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
 | 
				
			||||||
    RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
 | 
					    RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
 | 
				
			||||||
    RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
 | 
					    RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
 | 
				
			||||||
    RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
 | 
					    RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
 | 
				
			||||||
    RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
					    RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
 | 
					    INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
 | 
				
			||||||
    INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
 | 
					    INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
 | 
				
			||||||
    INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
 | 
					    INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
 | 
				
			||||||
    INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
 | 
					    INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
 | 
				
			||||||
    INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
					    INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
 | 
					    FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
 | 
				
			||||||
    FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
 | 
					    FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
 | 
				
			||||||
    FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
 | 
					    FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
 | 
				
			||||||
    FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
 | 
					    FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
 | 
				
			||||||
    FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
 | 
					    FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
 | 
				
			||||||
    FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
					    FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\$OWGW_ROOT/uploads"} \
 | 
					    FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
 | 
				
			||||||
    FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
 | 
					    FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
 | 
				
			||||||
    SERVICE_KEY=${SERVICE_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
 | 
					    SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
 | 
				
			||||||
    SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
 | 
					    SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    SYSTEM_DATA=${SYSTEM_DATA:-"\$OWGW_ROOT/data"} \
 | 
					    SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
 | 
				
			||||||
    SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
 | 
					    SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
 | 
				
			||||||
    SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
 | 
					    SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
 | 
				
			||||||
    SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
 | 
					    SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
 | 
				
			||||||
@@ -51,7 +51,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
				
			|||||||
    RTTY_TOKEN=${RTTY_TOKEN:-""} \
 | 
					    RTTY_TOKEN=${RTTY_TOKEN:-""} \
 | 
				
			||||||
    RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
 | 
					    RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
 | 
				
			||||||
    RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
 | 
					    RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
 | 
				
			||||||
    RTTY_ASSETS=${RTTY_ASSETS:-"\$OWGW_ROOT/rtty_ui"} \
 | 
					    RTTY_ASSETS=${RTTY_ASSETS:-"\${APP_ROOT}/rtty_ui"} \
 | 
				
			||||||
    RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
 | 
					    RADIUS_PROXY_ENABLE=${RADIUS_PROXY_ENABLE:-"false"} \
 | 
				
			||||||
    RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
 | 
					    RADIUS_PROXY_ACCOUNTING_PORT=${RADIUS_PROXY_ACCOUNTING_PORT:-"1813"} \
 | 
				
			||||||
    RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
 | 
					    RADIUS_PROXY_AUTHENTICATION_PORT=${RADIUS_PROXY_AUTHENTICATION_PORT:-"1812"} \
 | 
				
			||||||
@@ -64,38 +64,41 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
				
			|||||||
    KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
 | 
					    KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
 | 
				
			||||||
    STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
 | 
					    STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
 | 
				
			||||||
    STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
 | 
					    STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
 | 
				
			||||||
    STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
 | 
					    STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"${APP_USER}"} \
 | 
				
			||||||
    STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
 | 
					    STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"${APP_USER}"} \
 | 
				
			||||||
    STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
 | 
					    STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"${APP_NAME}"} \
 | 
				
			||||||
    STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
 | 
					    STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
 | 
				
			||||||
    STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
 | 
					    STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
 | 
				
			||||||
    STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
 | 
					    STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"${APP_USER}"} \
 | 
				
			||||||
    STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
 | 
					    STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"${APP_USER}"} \
 | 
				
			||||||
    STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
 | 
					    STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"${APP_NAME}"} \
 | 
				
			||||||
    STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
 | 
					    STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
 | 
				
			||||||
    envsubst < /owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
 | 
					    CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
 | 
				
			||||||
 | 
					    IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
 | 
				
			||||||
 | 
					    DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
 | 
				
			||||||
 | 
					    envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check if rtty_ui directory exists
 | 
					# Check if rtty_ui directory exists
 | 
				
			||||||
export RTTY_ASSETS=$(grep 'rtty.assets' $OWGW_CONFIG/owgw.properties | awk -F '=' '{print $2}' | xargs | envsubst)
 | 
					export RTTY_ASSETS=$(grep 'rtty.assets' "${APP_CONFIG}"/"${APP_NAME}".properties | awk -F '=' '{print $2}' | xargs | envsubst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ -z "$RTTY_ASSETS" ]; then
 | 
					if [ -z "$RTTY_ASSETS" ]; then
 | 
				
			||||||
    export RTTY_ASSETS="$OWGW_ROOT/rtty_ui"
 | 
					    export RTTY_ASSETS="${APP_ROOT}/rtty_ui"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then
 | 
					if [[ ! -d "$(dirname $RTTY_ASSETS)" ]]; then
 | 
				
			||||||
  mkdir -p $(dirname $RTTY_ASSETS)
 | 
					  mkdir -p "$(dirname $RTTY_ASSETS)"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [[ ! -d "$RTTY_ASSETS" ]]; then
 | 
					if [[ ! -d "$RTTY_ASSETS" ]]; then
 | 
				
			||||||
    cp -r /dist/rtty_ui $RTTY_ASSETS
 | 
					    cp -r /dist/rtty_ui $RTTY_ASSETS
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ "$1" = '/openwifi/owgw' -a "$(id -u)" = '0' ]; then
 | 
					if [ "$1" = "${APP_HOME_DIR}/${APP_NAME}" -a "$(id -u)" = '0' ]; then
 | 
				
			||||||
    if [ "$RUN_CHOWN" = 'true' ]; then
 | 
					    if [ "$RUN_CHOWN" = 'true' ]; then
 | 
				
			||||||
        chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
 | 
					        chown -R "$APP_USER": "${APP_ROOT}" "$APP_CONFIG"
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    exec gosu "$OWGW_USER" "$@"
 | 
					    exec gosu "$APP_USER" "$@"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exec "$@"
 | 
					exec "$@"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +0,0 @@
 | 
				
			|||||||
USERNAME=arilia
 | 
					 | 
				
			||||||
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					 | 
				
			||||||
IMAGE_NAME=ucentralgw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo "Removing docker images before build..."
 | 
					 | 
				
			||||||
docker rmi -f $(docker images -a -q)
 | 
					 | 
				
			||||||
echo "Building $IMAGE_NAME image..."
 | 
					 | 
				
			||||||
docker build --no-cache --tag $IMAGE_NAME .
 | 
					 | 
				
			||||||
IMAGE_ID=`docker images -q $IMAGE_NAME`
 | 
					 | 
				
			||||||
docker login --username=$USERNAME $HUBNAME
 | 
					 | 
				
			||||||
docker tag $IMAGE_ID $HUBNAME/$IMAGE_NAME:latest
 | 
					 | 
				
			||||||
echo "Updating $HUBNAME with the latest $IMAGE_NAME image..."
 | 
					 | 
				
			||||||
docker push $HUBNAME/$IMAGE_NAME
 | 
					 | 
				
			||||||
docker logout $HUBNAME
 | 
					 | 
				
			||||||
@@ -1,5 +0,0 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Removes all local images. This is dangerous but good when debugging
 | 
					 | 
				
			||||||
docker rmi -f $(docker images -a -q)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,43 +0,0 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
HUBNAME=tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					 | 
				
			||||||
IMAGE_NAME=ucentralgw
 | 
					 | 
				
			||||||
DOCKER_NAME=$HUBNAME/$IMAGE_NAME:master
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CONTAINER_NAME=ucentralgw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#stop previously running images
 | 
					 | 
				
			||||||
docker container stop $CONTAINER_NAME
 | 
					 | 
				
			||||||
docker container rm $CONTAINER_NAME --force
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -d logs ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
    mkdir logs
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -d uploads ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
    mkdir uploads
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -d certs ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
  echo "certs directory does not exist. Please create and add the proper certificates."
 | 
					 | 
				
			||||||
  exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ ! -f owgw.properties ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
  echo "Configuration file ucentral.properties is missing in the current directory"
 | 
					 | 
				
			||||||
  exit 2
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
docker run -d -p 15002:15002 \
 | 
					 | 
				
			||||||
              -p 16001:16001 \
 | 
					 | 
				
			||||||
              -p 16003:16003 \
 | 
					 | 
				
			||||||
              --init \
 | 
					 | 
				
			||||||
              --volume="$PWD:/ucentral-data" \
 | 
					 | 
				
			||||||
              -e UCENTRALGW_ROOT="/ucentral-data" \
 | 
					 | 
				
			||||||
              -e UCENTRALGW_CONFIG="/ucentral-data" \
 | 
					 | 
				
			||||||
              --name="ucentralgw" $DOCKER_NAME
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
				
			|||||||
images:
 | 
					images:
 | 
				
			||||||
  owgw:
 | 
					  owgw:
 | 
				
			||||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
 | 
					    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
 | 
				
			||||||
    tag: master
 | 
					    tag: v3.0.0
 | 
				
			||||||
    pullPolicy: Always
 | 
					    pullPolicy: Always
 | 
				
			||||||
#    regcred:
 | 
					#    regcred:
 | 
				
			||||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
				
			||||||
@@ -43,6 +43,7 @@ services:
 | 
				
			|||||||
      rttys:
 | 
					      rttys:
 | 
				
			||||||
        servicePort: 5912
 | 
					        servicePort: 5912
 | 
				
			||||||
        targetPort: 5912
 | 
					        targetPort: 5912
 | 
				
			||||||
 | 
					        protocol: TCP
 | 
				
			||||||
      rttys-view:
 | 
					      rttys-view:
 | 
				
			||||||
        servicePort: 5913
 | 
					        servicePort: 5913
 | 
				
			||||||
        targetPort: 5913
 | 
					        targetPort: 5913
 | 
				
			||||||
@@ -230,6 +231,7 @@ configProperties:
 | 
				
			|||||||
  openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
 | 
					  openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
 | 
				
			||||||
  openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
 | 
					  openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
 | 
				
			||||||
  openwifi.devicetypes.2: IOT:esp32
 | 
					  openwifi.devicetypes.2: IOT:esp32
 | 
				
			||||||
 | 
					  openwifi.certificates.allowmismatch: "false"
 | 
				
			||||||
  oui.download.uri: https://standards-oui.ieee.org/oui/oui.txt
 | 
					  oui.download.uri: https://standards-oui.ieee.org/oui/oui.txt
 | 
				
			||||||
  firmware.autoupdate.policy.default: auto
 | 
					  firmware.autoupdate.policy.default: auto
 | 
				
			||||||
  iptocountry.provider: ipinfo
 | 
					  iptocountry.provider: ipinfo
 | 
				
			||||||
@@ -296,7 +298,7 @@ configProperties:
 | 
				
			|||||||
  # Logging
 | 
					  # Logging
 | 
				
			||||||
  logging.type: console
 | 
					  logging.type: console
 | 
				
			||||||
  logging.path: $OWGW_ROOT/logs
 | 
					  logging.path: $OWGW_ROOT/logs
 | 
				
			||||||
  logging.level: information
 | 
					  logging.level: debug
 | 
				
			||||||
  # Archiving
 | 
					  # Archiving
 | 
				
			||||||
  archiver.enabled: "true"
 | 
					  archiver.enabled: "true"
 | 
				
			||||||
  archiver.schedule: 03:00
 | 
					  archiver.schedule: 03:00
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								images/project/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								images/project/logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.8 KiB  | 
							
								
								
									
										165
									
								
								images/project/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								images/project/logo.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
				
			||||||
 | 
					<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
				
			||||||
 | 
						 viewBox="0 0 141.5 185.6" style="enable-background:new 0 0 141.5 185.6;" xml:space="preserve">
 | 
				
			||||||
 | 
					<style type="text/css">
 | 
				
			||||||
 | 
						.st0{fill:#414141;}
 | 
				
			||||||
 | 
						.st1{fill:#FFFFFF;}
 | 
				
			||||||
 | 
						.st2{fill:#FED206;}
 | 
				
			||||||
 | 
						.st3{fill:#EB6F53;}
 | 
				
			||||||
 | 
						.st4{fill:#3BA9B6;}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
						<g>
 | 
				
			||||||
 | 
							<path class="st0" d="M120.7,183.9H21.5c-10.8,0-19.5-8.7-19.5-19.5V20.5c0-10.8,8.7-19.5,19.5-19.5h99.2
 | 
				
			||||||
 | 
								c10.8,0,19.5,8.7,19.5,19.5v143.9C140.2,175.2,131.5,183.9,120.7,183.9z"/>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M46.3,166.2v-3.4h-1.2v-0.6h3.1v0.6H47v3.4H46.3z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M49,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H49z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M52.6,166.2v-4h0.7v3.4h1.8v0.6H52.6z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M55.7,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H55.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M59.1,164.2c0-1.2,0.9-2.1,2.1-2.1c0.8,0,1.3,0.4,1.6,0.9l-0.6,0.3c-0.2-0.3-0.6-0.6-1-0.6
 | 
				
			||||||
 | 
											c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.4,0,0.8-0.3,1-0.6l0.6,0.3c-0.3,0.5-0.8,0.9-1.6,0.9
 | 
				
			||||||
 | 
											C60,166.3,59.1,165.5,59.1,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M63.2,164.2c0-1.2,0.8-2.1,2-2.1c1.2,0,2,0.9,2,2.1c0,1.2-0.8,2.1-2,2.1C64,166.3,63.2,165.4,63.2,164.2z
 | 
				
			||||||
 | 
											 M66.5,164.2c0-0.8-0.5-1.4-1.3-1.4c-0.8,0-1.3,0.6-1.3,1.4c0,0.8,0.5,1.4,1.3,1.4C66,165.7,66.5,165,66.5,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M71.3,166.2v-3.1l-1.2,3.1h-0.3l-1.2-3.1v3.1h-0.7v-4h1l1.1,2.7l1.1-2.7h1v4H71.3z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M75.7,166.2v-4h0.7v4H75.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M80.4,166.2l-2.1-2.8v2.8h-0.7v-4h0.7l2,2.8v-2.8h0.7v4H80.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M82.3,166.2v-4H85v0.6h-2v1h2v0.6h-2v1.7H82.3z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M87.9,166.2l-0.9-1.5h-0.7v1.5h-0.7v-4h1.7c0.8,0,1.3,0.5,1.3,1.2c0,0.7-0.5,1.1-0.9,1.2l1,1.6H87.9z
 | 
				
			||||||
 | 
											 M88,163.5c0-0.4-0.3-0.6-0.7-0.6h-1v1.3h1C87.7,164.1,88,163.9,88,163.5z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M92.4,166.2l-0.3-0.8h-1.8l-0.3,0.8h-0.8l1.6-4h0.9l1.6,4H92.4z M91.2,162.9l-0.7,1.9h1.4L91.2,162.9z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M95.8,166.2v-4h1.5c0.8,0,1.2,0.5,1.2,1.2c0,0.6-0.4,1.2-1.2,1.2h-1.2v1.7H95.8z M98.2,163.4
 | 
				
			||||||
 | 
											c0-0.5-0.3-0.9-0.9-0.9h-1.1v1.7h1.1C97.8,164.3,98.2,163.9,98.2,163.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M101.5,166.2l-1.1-1.6h-0.9v1.6h-0.3v-4h1.5c0.7,0,1.2,0.4,1.2,1.2c0,0.7-0.5,1.1-1.1,1.1l1.2,1.7H101.5z
 | 
				
			||||||
 | 
											 M101.6,163.4c0-0.5-0.4-0.9-0.9-0.9h-1.1v1.7h1.1C101.2,164.3,101.6,163.9,101.6,163.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M102.8,164.2c0-1.2,0.8-2.1,1.9-2.1c1.2,0,1.9,0.9,1.9,2.1c0,1.2-0.8,2.1-1.9,2.1
 | 
				
			||||||
 | 
											C103.6,166.3,102.8,165.4,102.8,164.2z M106.3,164.2c0-1-0.6-1.7-1.6-1.7c-1,0-1.6,0.7-1.6,1.7c0,1,0.6,1.7,1.6,1.7
 | 
				
			||||||
 | 
											C105.7,166,106.3,165.2,106.3,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M106.9,165.8l0.2-0.3c0.2,0.2,0.4,0.4,0.8,0.4c0.5,0,0.9-0.4,0.9-0.9v-2.8h0.3v2.8c0,0.8-0.5,1.2-1.2,1.2
 | 
				
			||||||
 | 
											C107.5,166.3,107.2,166.1,106.9,165.8z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M110.4,166.2v-4h2.5v0.3h-2.2v1.5h2.1v0.3h-2.1v1.6h2.2v0.3H110.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M113.5,164.2c0-1.2,0.9-2.1,2-2.1c0.6,0,1.1,0.3,1.5,0.7l-0.3,0.2c-0.3-0.3-0.7-0.6-1.2-0.6
 | 
				
			||||||
 | 
											c-0.9,0-1.7,0.7-1.7,1.7c0,1,0.7,1.7,1.7,1.7c0.5,0,0.9-0.2,1.2-0.6l0.3,0.2c-0.4,0.4-0.8,0.7-1.5,0.7
 | 
				
			||||||
 | 
											C114.4,166.3,113.5,165.5,113.5,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M118.7,166.2v-3.7h-1.3v-0.3h2.9v0.3H119v3.7H118.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<polygon class="st1" points="26.3,163.8 31.6,158.5 36.9,163.8 37.7,163.8 31.6,157.6 25.5,163.8 				"/>
 | 
				
			||||||
 | 
									<polygon class="st1" points="36.9,164.7 31.6,170 26.3,164.7 25.5,164.7 31.6,170.8 37.7,164.7 				"/>
 | 
				
			||||||
 | 
									<polygon class="st1" points="31,163.8 36.3,158.5 41.6,163.8 42.5,163.8 36.3,157.6 30.2,163.8 				"/>
 | 
				
			||||||
 | 
									<polygon class="st1" points="41.6,164.7 36.3,170 31,164.7 30.2,164.7 36.3,170.8 42.5,164.7 				"/>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<path class="st1" d="M33.2,100.7c-4.6,0-8.3,3.7-8.3,8.3s3.7,8.3,8.3,8.3s8.3-3.7,8.3-8.3S37.8,100.7,33.2,100.7z"/>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st2" d="M33.2,35.2c40.7,0,73.8,33.1,73.8,73.8c0,0.7,0,1.4,0,2.1c0,1.7,0.6,3.3,1.7,4.6c1.2,1.2,2.8,1.9,4.5,2
 | 
				
			||||||
 | 
											l0.2,0c3.5,0,6.3-2.7,6.4-6.2c0-0.8,0-1.7,0-2.5c0-47.7-38.8-86.6-86.6-86.6c-0.8,0-1.7,0-2.5,0c-1.7,0-3.3,0.8-4.5,2
 | 
				
			||||||
 | 
											c-1.2,1.2-1.8,2.9-1.7,4.6c0.1,3.5,3,6.3,6.6,6.2C31.8,35.2,32.5,35.2,33.2,35.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st3" d="M33.2,60.5c26.7,0,48.5,21.7,48.5,48.5c0,0.6,0,1.3,0,2c-0.1,1.7,0.5,3.3,1.7,4.6c1.2,1.3,2.7,2,4.4,2.1
 | 
				
			||||||
 | 
											c1.7,0.1,3.3-0.5,4.6-1.7c1.2-1.2,2-2.7,2-4.4c0-0.9,0.1-1.8,0.1-2.6c0-33.8-27.5-61.2-61.2-61.2c-0.8,0-1.6,0-2.6,0.1
 | 
				
			||||||
 | 
											c-1.7,0.1-3.3,0.8-4.4,2.1c-1.2,1.3-1.8,2.9-1.7,4.6s0.8,3.3,2.1,4.4c1.3,1.2,2.9,1.8,4.6,1.7C31.9,60.5,32.6,60.5,33.2,60.5z"
 | 
				
			||||||
 | 
											/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st4" d="M33.2,86.7c12.3,0,22.3,10,22.3,22.3c0,0.5,0,1.1-0.1,1.8c-0.3,3.5,2.3,6.6,5.8,6.9
 | 
				
			||||||
 | 
											c3.5,0.3,6.6-2.3,6.9-5.8c0.1-1,0.1-1.9,0.1-2.8c0-19.3-15.7-35.1-35.1-35.1c-0.9,0-1.8,0-2.8,0.1c-1.7,0.1-3.2,0.9-4.3,2.2
 | 
				
			||||||
 | 
											c-1.1,1.3-1.6,2.9-1.5,4.6c0.1,1.7,0.9,3.2,2.2,4.3c1.3,1.1,2.9,1.6,4.6,1.5C32.1,86.7,32.7,86.7,33.2,86.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
						</g>
 | 
				
			||||||
 | 
						<g>
 | 
				
			||||||
 | 
							<path class="st1" d="M35.8,130.4c1.1,0.6,2.1,1.5,2.7,2.6c0.7,1.1,1,2.3,1,3.7s-0.3,2.6-1,3.7c-0.7,1.1-1.6,2-2.7,2.6
 | 
				
			||||||
 | 
								c-1.1,0.6-2.4,1-3.8,1s-2.7-0.3-3.8-1c-1.1-0.6-2.1-1.5-2.7-2.6c-0.7-1.1-1-2.3-1-3.7c0-1.3,0.3-2.6,1-3.7c0.7-1.1,1.6-2,2.7-2.6
 | 
				
			||||||
 | 
								c1.1-0.6,2.4-0.9,3.8-0.9C33.4,129.5,34.7,129.8,35.8,130.4z M29.9,132.9c-0.7,0.4-1.2,0.9-1.6,1.6s-0.6,1.4-0.6,2.2
 | 
				
			||||||
 | 
								c0,0.8,0.2,1.6,0.6,2.3c0.4,0.7,0.9,1.2,1.6,1.6c0.7,0.4,1.4,0.6,2.1,0.6c0.8,0,1.5-0.2,2.1-0.6c0.6-0.4,1.2-0.9,1.5-1.6
 | 
				
			||||||
 | 
								c0.4-0.7,0.6-1.4,0.6-2.3c0-0.8-0.2-1.6-0.6-2.2s-0.9-1.2-1.5-1.6c-0.6-0.4-1.4-0.6-2.1-0.6C31.3,132.3,30.6,132.5,29.9,132.9z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M50.6,133.6c0.8,0.5,1.4,1.1,1.8,2c0.4,0.8,0.6,1.8,0.6,2.9c0,1.1-0.2,2-0.6,2.8c-0.4,0.8-1,1.5-1.8,1.9
 | 
				
			||||||
 | 
								c-0.8,0.5-1.6,0.7-2.6,0.7c-0.7,0-1.4-0.1-2-0.4s-1.1-0.7-1.5-1.2v5.4h-3.1V133h3.1v1.6c0.4-0.5,0.9-1,1.4-1.2s1.2-0.4,2-0.4
 | 
				
			||||||
 | 
								C48.9,132.9,49.8,133.1,50.6,133.6z M49.1,140.5c0.5-0.6,0.7-1.3,0.7-2.2c0-0.9-0.2-1.6-0.7-2.1c-0.5-0.6-1.1-0.8-1.9-0.8
 | 
				
			||||||
 | 
								s-1.4,0.3-1.9,0.8c-0.5,0.6-0.8,1.3-0.8,2.1c0,0.9,0.2,1.6,0.8,2.2s1.1,0.8,1.9,0.8S48.6,141,49.1,140.5z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M63.4,134.4c0.9,1,1.4,2.4,1.4,4.2c0,0.3,0,0.6,0,0.7H57c0.2,0.7,0.5,1.2,1,1.6c0.5,0.4,1.1,0.6,1.8,0.6
 | 
				
			||||||
 | 
								c0.5,0,1-0.1,1.5-0.3s0.9-0.5,1.3-0.9l1.6,1.6c-0.5,0.6-1.2,1.1-2,1.4c-0.8,0.3-1.6,0.5-2.6,0.5c-1.1,0-2.1-0.2-3-0.7
 | 
				
			||||||
 | 
								s-1.5-1.1-2-1.9c-0.5-0.8-0.7-1.8-0.7-2.9c0-1.1,0.2-2.1,0.7-2.9s1.1-1.5,2-1.9c0.8-0.5,1.8-0.7,2.9-0.7
 | 
				
			||||||
 | 
								C61.2,132.9,62.5,133.4,63.4,134.4z M61.8,137.5c0-0.7-0.3-1.3-0.7-1.7s-1-0.6-1.7-0.6c-0.7,0-1.2,0.2-1.7,0.6
 | 
				
			||||||
 | 
								c-0.4,0.4-0.7,1-0.9,1.7H61.8z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M76.2,134c0.7,0.7,1.1,1.7,1.1,3v6.8h-3.1v-5.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.5-0.6
 | 
				
			||||||
 | 
								c-0.8,0-1.4,0.3-1.8,0.8c-0.4,0.5-0.7,1.2-0.7,2v5.3h-3.1V133h3.1v1.9c0.7-1.3,2-2,3.7-2C74.6,132.8,75.5,133.2,76.2,134z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M96,129.7h3.3l-4.7,14h-3.3l-2.9-10.1l-3,10.1h-3.2l-4.7-14h3.4l3,10.7l3-10.7H90l3.1,10.7L96,129.7z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M103.3,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
 | 
				
			||||||
 | 
								c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C102.6,128.2,103,128.3,103.3,128.7z M100.6,133h3.1
 | 
				
			||||||
 | 
								v10.8h-3.1V133z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M106.5,129.7h10.1l0,2.6h-6.9v3.4h6.3v2.6h-6.3v5.3h-3.2V129.7z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M120.9,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
 | 
				
			||||||
 | 
								c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C120.1,128.2,120.5,128.3,120.9,128.7z M118.1,133h3.1
 | 
				
			||||||
 | 
								v10.8h-3.1V133z"/>
 | 
				
			||||||
 | 
						</g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 8.0 KiB  | 
							
								
								
									
										22213
									
								
								issues/OWGW Logs.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22213
									
								
								issues/OWGW Logs.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2158
									
								
								issues/OWLS Logs.rtf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2158
									
								
								issues/OWLS Logs.rtf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2154
									
								
								issues/OWLS Logs.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2154
									
								
								issues/OWLS Logs.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										18
									
								
								issues/WIFI-11388.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								issues/WIFI-11388.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					Issue: https://telecominfraproject.atlassian.net/browse/WIFI-11388
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Problem:
 | 
				
			||||||
 | 
					If a configuration was accepted by the GW or Provisioning but is still not valid according to the firmware on teh device,
 | 
				
			||||||
 | 
					the device will reject the configuration, however, that configuration is known as the kast good configuration in the GW.
 | 
				
			||||||
 | 
					This mens that we will lock the device in a loop where it continuously wants to update the configuration to version X,
 | 
				
			||||||
 | 
					and the device will continuously reject it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Workaround:
 | 
				
			||||||
 | 
					Simply send a valid configuration to the GW and this will allow the device you update and stop the cycle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Fix:
 | 
				
			||||||
 | 
					When a new configuration is submitted, store is a "pending". If it is accepted, move it to the current configuration. If
 | 
				
			||||||
 | 
					not accepted, simply remove it. One corner case exists. For some configuration updates, the AP will never complete the
 | 
				
			||||||
 | 
					update cycle, even if it has updated the configuration. In that case, we can detect the configuration during a connect
 | 
				
			||||||
 | 
					later. At that moment, when we look for an upgrade, we must compare with the pending UUID and the current UUID. If it matches the pending,
 | 
				
			||||||
 | 
					we know the last update worked. If it does not, we know to revert.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1041
									
								
								openapi/owgw.yaml
									
									
									
									
									
								
							
							
						
						
									
										1041
									
								
								openapi/owgw.yaml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -75,6 +75,7 @@ openwifi.autoprovisioning = true
 | 
				
			|||||||
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
 | 
					openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
 | 
				
			||||||
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
 | 
					openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
 | 
				
			||||||
openwifi.devicetypes.2 = IOT:esp32
 | 
					openwifi.devicetypes.2 = IOT:esp32
 | 
				
			||||||
 | 
					openwifi.certificates.allowmismatch = ${CERTIFICATES_ALLOWMISMATCH}
 | 
				
			||||||
oui.download.uri = https://standards-oui.ieee.org/oui/oui.txt
 | 
					oui.download.uri = https://standards-oui.ieee.org/oui/oui.txt
 | 
				
			||||||
simulatorid = ${SIMULATORID}
 | 
					simulatorid = ${SIMULATORID}
 | 
				
			||||||
iptocountry.default = US
 | 
					iptocountry.default = US
 | 
				
			||||||
@@ -84,6 +85,7 @@ iptocountry.ipdata.apikey = ${IPTOCOUNTRY_IPDATA_APIKEY}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
 | 
					autoprovisioning.process = ${AUTOPROVISIONING_PROCESS}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					openwifi.session.timeout = ${DEVICE_SESSION_TIMEOUT}
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# rtty
 | 
					# rtty
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -102,6 +104,12 @@ radius.proxy.accounting.port = ${RADIUS_PROXY_ACCOUNTING_PORT}
 | 
				
			|||||||
radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
 | 
					radius.proxy.authentication.port = ${RADIUS_PROXY_AUTHENTICATION_PORT}
 | 
				
			||||||
radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
 | 
					radius.proxy.coa.port = ${RADIUS_PROXY_COA_PORT}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					iptocountry.default = ${IPINFO_DEFAULT_COUNTRY}
 | 
				
			||||||
 | 
					#iptocountry.provider = ipinfo
 | 
				
			||||||
 | 
					#iptocountry.provider = ipdata
 | 
				
			||||||
 | 
					#iptocountry.ipinfo.token =
 | 
				
			||||||
 | 
					#iptocountry.ipdata.apikey =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#############################
 | 
					#############################
 | 
				
			||||||
# Generic information for all micro services
 | 
					# Generic information for all micro services
 | 
				
			||||||
#############################
 | 
					#############################
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										41
									
								
								pcap/radius
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								pcap/radius
									
									
									
									
									
								
							@@ -1,41 +0,0 @@
 | 
				
			|||||||
/* Frame (255 bytes) */
 | 
					 | 
				
			||||||
static const unsigned char pkt41[255] = {
 | 
					 | 
				
			||||||
0x14, 0x98, 0x77, 0x71, 0xc6, 0xe7, 0x34, 0xef, /* ..wq..4. */
 | 
					 | 
				
			||||||
0xb6, 0xaf, 0x4a, 0x5c, 0x08, 0x00, 0x45, 0x00, /* ..J\..E. */
 | 
					 | 
				
			||||||
0x00, 0xf1, 0x87, 0x50, 0x00, 0x00, 0x40, 0x11, /* ...P..@. */
 | 
					 | 
				
			||||||
0x0c, 0xdf, 0xc0, 0xa8, 0xb2, 0x1b, 0xc0, 0xa8, /* ........ */
 | 
					 | 
				
			||||||
0xb2, 0x60, 0xc3, 0xfe, 0x07, 0x14, 0x00, 0xdd, /* .`...... */
 | 
					 | 
				
			||||||
0x26, 0x63, 0x01, 0x04, 0x00, 0xd5, 0xcc, 0x29, /* &c.....) */
 | 
					 | 
				
			||||||
0x82, 0x36, 0xd6, 0x57, 0x3d, 0xa7, 0xd5, 0x62, /* .6.W=..b */
 | 
					 | 
				
			||||||
0x70, 0x12, 0x00, 0xc0, 0xf2, 0x19, 0x01, 0x03, /* p....... */
 | 
					 | 
				
			||||||
0x61, 0x1e, 0x1c, 0x33, 0x34, 0x2d, 0x45, 0x46, /* a..34-EF */
 | 
					 | 
				
			||||||
0x2d, 0x42, 0x36, 0x2d, 0x41, 0x46, 0x2d, 0x34, /* -B6-AF-4 */
 | 
					 | 
				
			||||||
0x41, 0x2d, 0x36, 0x30, 0x3a, 0x4f, 0x70, 0x65, /* A-60:Ope */
 | 
					 | 
				
			||||||
0x6e, 0x57, 0x69, 0x66, 0x69, 0x3d, 0x06, 0x00, /* nWifi=.. */
 | 
					 | 
				
			||||||
0x00, 0x00, 0x13, 0x06, 0x06, 0x00, 0x00, 0x00, /* ........ */
 | 
					 | 
				
			||||||
0x02, 0x05, 0x06, 0x00, 0x00, 0x00, 0x01, 0x1f, /* ........ */
 | 
					 | 
				
			||||||
0x13, 0x42, 0x36, 0x2d, 0x43, 0x34, 0x2d, 0x30, /* .B6-C4-0 */
 | 
					 | 
				
			||||||
0x36, 0x2d, 0x30, 0x39, 0x2d, 0x31, 0x35, 0x2d, /* 6-09-15- */
 | 
					 | 
				
			||||||
0x42, 0x37, 0x4d, 0x18, 0x43, 0x4f, 0x4e, 0x4e, /* B7M.CONN */
 | 
					 | 
				
			||||||
0x45, 0x43, 0x54, 0x20, 0x35, 0x34, 0x4d, 0x62, /* ECT 54Mb */
 | 
					 | 
				
			||||||
0x70, 0x73, 0x20, 0x38, 0x30, 0x32, 0x2e, 0x31, /* ps 802.1 */
 | 
					 | 
				
			||||||
0x31, 0x61, 0x2c, 0x12, 0x33, 0x42, 0x45, 0x44, /* 1a,.3BED */
 | 
					 | 
				
			||||||
0x37, 0x32, 0x39, 0x30, 0x44, 0x30, 0x43, 0x38, /* 7290D0C8 */
 | 
					 | 
				
			||||||
0x35, 0x36, 0x44, 0x33, 0xba, 0x06, 0x00, 0x0f, /* 56D3.... */
 | 
					 | 
				
			||||||
0xac, 0x04, 0xbb, 0x06, 0x00, 0x0f, 0xac, 0x04, /* ........ */
 | 
					 | 
				
			||||||
0xbc, 0x06, 0x00, 0x0f, 0xac, 0x05, 0xbd, 0x06, /* ........ */
 | 
					 | 
				
			||||||
0x00, 0x0f, 0xac, 0x06, 0x1a, 0x1b, 0x00, 0x00, /* ........ */
 | 
					 | 
				
			||||||
0xe6, 0x08, 0x47, 0x15, 0x01, 0x13, 0x33, 0x34, /* ..G...34 */
 | 
					 | 
				
			||||||
0x2d, 0x65, 0x66, 0x2d, 0x62, 0x36, 0x2d, 0x61, /* -ef-b6-a */
 | 
					 | 
				
			||||||
0x66, 0x2d, 0x34, 0x61, 0x2d, 0x35, 0x63, 0x0c, /* f-4a-5c. */
 | 
					 | 
				
			||||||
0x06, 0x00, 0x00, 0x05, 0x78, 0x4f, 0x08, 0x02, /* ....xO.. */
 | 
					 | 
				
			||||||
0x01, 0x00, 0x06, 0x01, 0x61, 0x50, 0x12, 0x20, /* ....aP.  */
 | 
					 | 
				
			||||||
0x9c, 0xae, 0xe5, 0xe3, 0x77, 0xaf, 0x0b, 0x1b, /* ....w... */
 | 
					 | 
				
			||||||
0xaf, 0x0e, 0xb5, 0x08, 0x82, 0x9e, 0xeb        /* ....... */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Reassembled EAP (6 bytes) */
 | 
					 | 
				
			||||||
static const unsigned char pkt41_1[6] = {
 | 
					 | 
				
			||||||
0x02, 0x01, 0x00, 0x06, 0x01, 0x61              /* .....a */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
192.168.178.1
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							@@ -16,6 +16,7 @@
 | 
				
			|||||||
                        "weight" : 10,
 | 
					                        "weight" : 10,
 | 
				
			||||||
                        "radsec" : true,
 | 
					                        "radsec" : true,
 | 
				
			||||||
                        "radsecPort" : 2083,
 | 
					                        "radsecPort" : 2083,
 | 
				
			||||||
 | 
					                        "allowSelfSigned" : false,
 | 
				
			||||||
                        "radsecSecret" : "radsec",
 | 
					                        "radsecSecret" : "radsec",
 | 
				
			||||||
                        "radsecKey" : "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUR6RnpXeTZlYXg0QVoxTySG9VUURRZ0FFS3BnWVBHMktPTVd2S0w1Z3NMRXpUc09rREg1M3NHaEQyS3RsRXBDTXVnNDNIZlFnTFVpUgpTR1R2S1l0bDFmbmJaU1lnY0RJdncxdjNYRy9hVDhOY2JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=",
 | 
					                        "radsecKey" : "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUR6RnpXeTZlYXg0QVoxTySG9VUURRZ0FFS3BnWVBHMktPTVd2S0w1Z3NMRXpUc09rREg1M3NHaEQyS3RsRXBDTXVnNDNIZlFnTFVpUgpTR1R2S1l0bDFmbmJaU1lnY0RJdncxdjNYRy9hVDhOY2JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=",
 | 
				
			||||||
                        "radsecCert" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNRVENDQWVpZ0F3SUJBZ0lVY3BKS3pVM0Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa0oxZEhSdmJuZHZiMlF4SFRBYkJnTlZCQU1URkVKMQpkSFJ2Ym5kdmIyUWdVbUZrYzJWaklFTkJNQjRYRFRJeU1EY3dNekExTWpVeE5Gb1hEVEkzTURVeE9UQTFNalV4Ck5Gb3dkVEVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFvVENrSjFkSFJ2Ym5kdmIyUXhOakEwQmdOVkJBTVQKTFdGeWFXeHBZUzVqWWpFd2FtTnVjemgxYlhCbk9HWnBjRFowTUM1dmNtbHZiaTVoY21WaE1USXdMbU52YlRFWgpNQmNHQ2dtU0pvbVQ4aXhrQVFFVENVZHZiMmRzWlRwVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQ3FZR0R4dGlqakZyeWkrWUxDeE0wN0RwQXgrZDdCb1E5aXJaUktRakxvT054MzBJQzFJa1Voazd5bUwKWmRYNTIyVW1JSEF5TDhOYjkxeHYyay9EWEd5amdZa3dnWVl3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZApKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3T0FZRFZSMFJCREV3TDRJdFlYSnBiR2xoCkxtTmlNVEJxWTI1ek9IVnRjR2M0Wm1sd05uUXdMbTl5YVc5dUxtRnlaV0V4TWpBdVkyOXRNQmNHQTFVZElBUVEKTUE0d0RBWUtLd1lCQkFIdUtnRUJCVEFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFwTmM1dUNBSkp6KzVyakdqdwpCWGtOdHE3UU83bWU5dUg5bkNsTDZnSVE5Z0lnUHM2VkVKVW5CcEZ0RktXbFF4eWJ1YlBxYnpJNjBPSERHQ0ExCmhXUk1PS1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
 | 
					                        "radsecCert" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNRVENDQWVpZ0F3SUJBZ0lVY3BKS3pVM0Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa0oxZEhSdmJuZHZiMlF4SFRBYkJnTlZCQU1URkVKMQpkSFJ2Ym5kdmIyUWdVbUZrYzJWaklFTkJNQjRYRFRJeU1EY3dNekExTWpVeE5Gb1hEVEkzTURVeE9UQTFNalV4Ck5Gb3dkVEVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFvVENrSjFkSFJ2Ym5kdmIyUXhOakEwQmdOVkJBTVQKTFdGeWFXeHBZUzVqWWpFd2FtTnVjemgxYlhCbk9HWnBjRFowTUM1dmNtbHZiaTVoY21WaE1USXdMbU52YlRFWgpNQmNHQ2dtU0pvbVQ4aXhrQVFFVENVZHZiMmRzWlRwVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQ3FZR0R4dGlqakZyeWkrWUxDeE0wN0RwQXgrZDdCb1E5aXJaUktRakxvT054MzBJQzFJa1Voazd5bUwKWmRYNTIyVW1JSEF5TDhOYjkxeHYyay9EWEd5amdZa3dnWVl3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZApKUVFNTUFvR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3T0FZRFZSMFJCREV3TDRJdFlYSnBiR2xoCkxtTmlNVEJxWTI1ek9IVnRjR2M0Wm1sd05uUXdMbTl5YVc5dUxtRnlaV0V4TWpBdVkyOXRNQmNHQTFVZElBUVEKTUE0d0RBWUtLd1lCQkFIdUtnRUJCVEFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFwTmM1dUNBSkp6KzVyakdqdwpCWGtOdHE3UU83bWU5dUg5bkNsTDZnSVE5Z0lnUHM2VkVKVW5CcEZ0RktXbFF4eWJ1YlBxYnpJNjBPSERHQ0ExCmhXUk1PS1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1849
									
								
								regulatory/regulatory.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1849
									
								
								regulatory/regulatory.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										24
									
								
								run.sh
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								run.sh
									
									
									
									
									
								
							@@ -1,24 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
daemon=ucentralgw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ "$1" == "aws" ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
	cp ${daemon}.properties.aws ${daemon}.properties
 | 
					 | 
				
			||||||
	. ./set_env.sh
 | 
					 | 
				
			||||||
	cd cmake-build
 | 
					 | 
				
			||||||
	./${daemon} --daemon
 | 
					 | 
				
			||||||
	echo "Running AWS version as daemon..."
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ "$1" == "priv" ]]
 | 
					 | 
				
			||||||
then
 | 
					 | 
				
			||||||
  cp ${daemon}.properties.priv ${daemon}.properties
 | 
					 | 
				
			||||||
  . ./set_env.sh
 | 
					 | 
				
			||||||
  cd cmake-build
 | 
					 | 
				
			||||||
  ./${daemon} --daemon
 | 
					 | 
				
			||||||
  echo "Running private version as daemon..."
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										59
									
								
								src/AP_WS_ConfigAutoUpgrader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/AP_WS_ConfigAutoUpgrader.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-05-23.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "AP_WS_ConfigAutoUpgrader.h"
 | 
				
			||||||
 | 
					#include <framework/utils.h>
 | 
				
			||||||
 | 
					#include <RESTObjects/RESTAPI_GWobjects.h>
 | 
				
			||||||
 | 
					#include <StorageService.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int AP_WS_ConfigAutoUpgrader::Start() {
 | 
				
			||||||
 | 
							poco_notice(Logger(), "Starting...");
 | 
				
			||||||
 | 
							QueueManager_.start(*this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AP_WS_ConfigAutoUpgrader::Stop() {
 | 
				
			||||||
 | 
							poco_notice(Logger(), "Stopping...");
 | 
				
			||||||
 | 
							Running_ = false;
 | 
				
			||||||
 | 
							Queue_.wakeUpAll();
 | 
				
			||||||
 | 
							QueueManager_.join();
 | 
				
			||||||
 | 
							poco_notice(Logger(), "Stopped...");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AP_WS_ConfigAutoUpgrader::run() {
 | 
				
			||||||
 | 
							Utils::SetThreadName("auto:cfgmgr");
 | 
				
			||||||
 | 
							Running_ = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while (Running_) {
 | 
				
			||||||
 | 
								Poco::AutoPtr<Poco::Notification> NextMsg(Queue_.waitDequeueNotification());
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									auto Entry = dynamic_cast<CheckConfiguration *>(NextMsg.get());
 | 
				
			||||||
 | 
									if (Entry != nullptr) {
 | 
				
			||||||
 | 
										GWObjects::Device DeviceInfo;
 | 
				
			||||||
 | 
										std::string SerialNumber = Utils::IntToSerialNumber(Entry->serial_);
 | 
				
			||||||
 | 
										if (StorageService()->GetDevice(SerialNumber, DeviceInfo)) {
 | 
				
			||||||
 | 
											if(DeviceInfo.pendingUUID!=0 && Entry->uuid_==DeviceInfo.pendingUUID) {
 | 
				
			||||||
 | 
												StorageService()->CompleteDeviceConfigurationChange(SerialNumber);
 | 
				
			||||||
 | 
												SetDeviceCacheEntry(Entry->serial_, Utils::Now(), Entry->uuid_, 0);
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											if(DeviceInfo.UUID==Entry->uuid_) {
 | 
				
			||||||
 | 
												SetDeviceCacheEntry(Entry->serial_, Utils::Now(), Entry->uuid_, 0);
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								} catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
									Logger().log(E);
 | 
				
			||||||
 | 
								} catch (...) {
 | 
				
			||||||
 | 
									poco_warning(Logger(), "Exception occurred during run.");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										137
									
								
								src/AP_WS_ConfigAutoUpgrader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/AP_WS_ConfigAutoUpgrader.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-05-23.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/Notification.h"
 | 
				
			||||||
 | 
					#include "Poco/NotificationQueue.h"
 | 
				
			||||||
 | 
					#include "Poco/Timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <framework/SubSystemServer.h>
 | 
				
			||||||
 | 
					#include <framework/utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class CheckConfiguration : public Poco::Notification {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							explicit CheckConfiguration(std::uint64_t s, std::uint64_t c) :
 | 
				
			||||||
 | 
					 			serial_(s), uuid_(c) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							std::uint64_t serial_;
 | 
				
			||||||
 | 
							std::uint64_t uuid_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ConfigurationCacheEntry {
 | 
				
			||||||
 | 
							std::uint64_t last_check_=0;
 | 
				
			||||||
 | 
							std::uint64_t current_config_=0;
 | 
				
			||||||
 | 
							std::uint64_t pending_config_=0;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class AP_WS_ConfigAutoUpgrader : public SubSystemServer, Poco::Runnable {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							int Start() final;
 | 
				
			||||||
 | 
							void Stop() final;
 | 
				
			||||||
 | 
							void run() final;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static auto instance() {
 | 
				
			||||||
 | 
								static auto instance = new AP_WS_ConfigAutoUpgrader;
 | 
				
			||||||
 | 
								return instance;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void AddConfiguration(std::uint64_t serial, std::uint64_t config_uuid) {
 | 
				
			||||||
 | 
								std::lock_guard			Guard(CacheMutex_);
 | 
				
			||||||
 | 
								auto hint = Cache_.find(serial);
 | 
				
			||||||
 | 
								if(hint==end(Cache_)) {
 | 
				
			||||||
 | 
									Cache_[serial] = { Utils::Now(),config_uuid , 0 };
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if(hint->second.pending_config_==0) {
 | 
				
			||||||
 | 
									hint->second.last_check_ = Utils::Now();
 | 
				
			||||||
 | 
									hint->second.current_config_ = config_uuid;
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void AddConfiguration(std::uint64_t serial, std::uint64_t config_uuid, std::uint64_t pending_config_uuid) {
 | 
				
			||||||
 | 
								std::lock_guard			Guard(CacheMutex_);
 | 
				
			||||||
 | 
								auto hint = Cache_.find(serial);
 | 
				
			||||||
 | 
								if(hint==end(Cache_)) {
 | 
				
			||||||
 | 
									Cache_[serial] = { Utils::Now(), config_uuid , pending_config_uuid };
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if(hint->second.pending_config_==0) {
 | 
				
			||||||
 | 
									hint->second.last_check_ = Utils::Now();
 | 
				
			||||||
 | 
									hint->second.current_config_ = config_uuid;
 | 
				
			||||||
 | 
									hint->second.pending_config_ = pending_config_uuid;
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]] inline ConfigurationCacheEntry GetSerialInfo(std::uint64_t serial) const {
 | 
				
			||||||
 | 
								std::lock_guard			Guard(CacheMutex_);
 | 
				
			||||||
 | 
								auto hint = Cache_.find(serial);
 | 
				
			||||||
 | 
								if(hint==end(Cache_)) {
 | 
				
			||||||
 | 
									return {0,0,0};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return hint->second;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool UpdateConfiguration(std::uint64_t serial, std::uint64_t config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(serial==0)
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::lock_guard			Guard(CacheMutex_);
 | 
				
			||||||
 | 
								auto hint = Cache_.find(serial);
 | 
				
			||||||
 | 
								if(hint!=end(Cache_)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(hint->second.current_config_==config) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(config==hint->second.pending_config_) {
 | 
				
			||||||
 | 
										Queue_.enqueueNotification(new CheckConfiguration(serial,config));
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(config!=hint->second.current_config_ && hint->second.pending_config_==0) {
 | 
				
			||||||
 | 
										Queue_.enqueueNotification(new CheckConfiguration(serial,config));
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if((Utils::Now()-hint->second.last_check_)<60*5) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(hint->second.pending_config_!=0) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void SetDeviceCacheEntry(std::uint64_t serial, std::uint64_t t, std::uint64_t uuid, std::uint64_t pending_uuid) {
 | 
				
			||||||
 | 
								std::lock_guard			Guard(CacheMutex_);
 | 
				
			||||||
 | 
								Cache_[serial] = { t, uuid, pending_uuid };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							Poco::NotificationQueue		Queue_;
 | 
				
			||||||
 | 
							Poco::Thread				QueueManager_;
 | 
				
			||||||
 | 
							std::atomic_bool 			Running_=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mutable std::mutex			CacheMutex_;
 | 
				
			||||||
 | 
							std::map<std::uint64_t, ConfigurationCacheEntry> Cache_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							AP_WS_ConfigAutoUpgrader() noexcept
 | 
				
			||||||
 | 
								: SubSystemServer("AutoConfigUpgrade", "AUTO-CFG-MGR", "auto.config.updater") {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline auto AP_WS_ConfigAutoUpgrader() { return AP_WS_ConfigAutoUpgrader::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -4,14 +4,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/Net/SecureStreamSocketImpl.h"
 | 
					#include "Poco/Base64Decoder.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerResponseImpl.h"
 | 
					#include "Poco/Net/Context.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerRequestImpl.h"
 | 
					#include "Poco/Net/HTTPServerRequestImpl.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTTPServerResponseImpl.h"
 | 
				
			||||||
#include "Poco/Net/NetException.h"
 | 
					#include "Poco/Net/NetException.h"
 | 
				
			||||||
#include "Poco/Net/SSLException.h"
 | 
					#include "Poco/Net/SSLException.h"
 | 
				
			||||||
#include "Poco/Net/Context.h"
 | 
					#include "Poco/Net/SecureStreamSocketImpl.h"
 | 
				
			||||||
#include "Poco/Base64Decoder.h"
 | 
					#include "Poco/Net/WebSocketImpl.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/zlib.h"
 | 
					#include "Poco/zlib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					#include "AP_WS_Server.h"
 | 
				
			||||||
@@ -20,14 +20,27 @@
 | 
				
			|||||||
#include "ConfigurationCache.h"
 | 
					#include "ConfigurationCache.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "TelemetryStream.h"
 | 
					#include "TelemetryStream.h"
 | 
				
			||||||
#include "framework/WebSocketClientNotifications.h"
 | 
					 | 
				
			||||||
#include "Poco/Net/WebSocketImpl.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "GWKafkaEvents.h"
 | 
				
			||||||
 | 
					#include "UI_GW_WebSocketNotifications.h"
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "RADIUSSessionTracker.h"
 | 
				
			||||||
#include "RADIUS_proxy_server.h"
 | 
					#include "RADIUS_proxy_server.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DBL					{ std::cout << __LINE__ << "  ID: " << ConnectionId_ << "  Ser: " << SerialNumber_ << std::endl; }
 | 
					#define DBL                                                                                        \
 | 
				
			||||||
 | 
						{                                                                                              \
 | 
				
			||||||
 | 
							std::cout << __LINE__ << "  ID: " << ConnectionId_ << "  Ser: " << SerialNumber_           \
 | 
				
			||||||
 | 
									  << std::endl;                                                                    \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::LogException(const Poco::Exception &E) {
 | 
						void AP_WS_Connection::LogException(const Poco::Exception &E) {
 | 
				
			||||||
		poco_information(Logger_, fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
 | 
							poco_information(Logger_, fmt::format("EXCEPTION({}): {}", CId_, E.displayText()));
 | 
				
			||||||
@@ -35,12 +48,9 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
 | 
						AP_WS_Connection::AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
 | 
				
			||||||
									   Poco::Net::HTTPServerResponse &response,
 | 
														   Poco::Net::HTTPServerResponse &response,
 | 
				
			||||||
									   std::uint64_t connection_id,
 | 
														   uint64_t connection_id, Poco::Logger &L,
 | 
				
			||||||
									   Poco::Logger &L,
 | 
					 | 
				
			||||||
									   Poco::Net::SocketReactor &R)
 | 
														   Poco::Net::SocketReactor &R)
 | 
				
			||||||
		: Logger_(L) ,
 | 
							: Logger_(L), Reactor_(R) {
 | 
				
			||||||
		  Reactor_(R)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		State_.sessionId = connection_id;
 | 
							State_.sessionId = connection_id;
 | 
				
			||||||
		WS_ = std::make_unique<Poco::Net::WebSocket>(request, response);
 | 
							WS_ = std::make_unique<Poco::Net::WebSocket>(request, response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,44 +58,24 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		WS_->setMaxPayloadSize(BufSize);
 | 
							WS_->setMaxPayloadSize(BufSize);
 | 
				
			||||||
		WS_->setReceiveTimeout(TS);
 | 
							WS_->setReceiveTimeout(TS);
 | 
				
			||||||
		WS_->setNoDelay(true);
 | 
							WS_->setNoDelay(false);
 | 
				
			||||||
		WS_->setKeepAlive(true);
 | 
							WS_->setKeepAlive(true);
 | 
				
			||||||
		WS_->setBlocking(false);
 | 
							WS_->setBlocking(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reactor_.addEventHandler(
 | 
							Reactor_.addEventHandler(*WS_,
 | 
				
			||||||
			*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
 | 
													 Poco::NObserver<AP_WS_Connection, Poco::Net::ReadableNotification>(
 | 
				
			||||||
									 *this, &AP_WS_Connection::OnSocketReadable));
 | 
														 *this, &AP_WS_Connection::OnSocketReadable));
 | 
				
			||||||
		Reactor_.addEventHandler(
 | 
							Reactor_.addEventHandler(*WS_,
 | 
				
			||||||
			*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
 | 
													 Poco::NObserver<AP_WS_Connection, Poco::Net::ShutdownNotification>(
 | 
				
			||||||
									 *this, &AP_WS_Connection::OnSocketShutdown));
 | 
														 *this, &AP_WS_Connection::OnSocketShutdown));
 | 
				
			||||||
		Reactor_.addEventHandler(
 | 
							Reactor_.addEventHandler(*WS_,
 | 
				
			||||||
			*WS_, Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
 | 
													 Poco::NObserver<AP_WS_Connection, Poco::Net::ErrorNotification>(
 | 
				
			||||||
									 *this, &AP_WS_Connection::OnSocketError));
 | 
														 *this, &AP_WS_Connection::OnSocketError));
 | 
				
			||||||
		Registered_ = true;
 | 
							Registered_ = true;
 | 
				
			||||||
		Valid_ = true;
 | 
							Valid_ = true;
 | 
				
			||||||
 | 
							uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class ThreadedCounter {
 | 
					 | 
				
			||||||
	  public:
 | 
					 | 
				
			||||||
		ThreadedCounter(bool T, std::atomic_uint64_t &C) :
 | 
					 | 
				
			||||||
			C_(C),
 | 
					 | 
				
			||||||
			Threaded_(T) {
 | 
					 | 
				
			||||||
			if(Threaded_) {
 | 
					 | 
				
			||||||
				C_++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		~ThreadedCounter() {
 | 
					 | 
				
			||||||
			if(Threaded_ && C_>0) {
 | 
					 | 
				
			||||||
				C_--;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  private:
 | 
					 | 
				
			||||||
		std::atomic_uint64_t 	&C_;
 | 
					 | 
				
			||||||
		bool 					Threaded_;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool AP_WS_Connection::ValidatedDevice() {
 | 
						bool AP_WS_Connection::ValidatedDevice() {
 | 
				
			||||||
		if (DeviceValidated_)
 | 
							if (DeviceValidated_)
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
@@ -93,26 +83,34 @@ namespace OpenWifi {
 | 
				
			|||||||
		if (!Valid_)
 | 
							if (!Valid_)
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::lock_guard Lock(ConnectionMutex_);
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
 | 
								auto SockImpl = dynamic_cast<Poco::Net::WebSocketImpl *>(WS_->impl());
 | 
				
			||||||
			auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl*>(SockImpl->streamSocketImpl());
 | 
								auto SS =
 | 
				
			||||||
 | 
									dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(SockImpl->streamSocketImpl());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			PeerAddress_ = SS->peerAddress().host();
 | 
								PeerAddress_ = SS->peerAddress().host();
 | 
				
			||||||
			CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
 | 
								CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			State_.started = OpenWifi::Now();
 | 
								State_.started = Utils::Now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!SS->secure()) {
 | 
								if (!SS->secure()) {
 | 
				
			||||||
				poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is NOT secure. Device is not allowed.", CId_, State_.sessionId ));
 | 
									poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is "
 | 
				
			||||||
 | 
																	  "NOT secure. Device is not allowed.",
 | 
				
			||||||
 | 
																	  CId_, State_.sessionId));
 | 
				
			||||||
				EndConnection();
 | 
									EndConnection();
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			poco_debug(Logger_,fmt::format("TLS-CONNECTION({}): Session={} Connection is secure.", CId_, State_.sessionId ));
 | 
								poco_trace(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Connection is secure.",
 | 
				
			||||||
 | 
																CId_, State_.sessionId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!SS->havePeerCertificate()) {
 | 
								if (!SS->havePeerCertificate()) {
 | 
				
			||||||
				State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
 | 
									State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
 | 
				
			||||||
				poco_warning(Logger_,fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_, State_.sessionId ));
 | 
									poco_warning(
 | 
				
			||||||
 | 
										Logger_,
 | 
				
			||||||
 | 
										fmt::format("TLS-CONNECTION({}): Session={} No certificates available..", CId_,
 | 
				
			||||||
 | 
													State_.sessionId));
 | 
				
			||||||
				EndConnection();
 | 
									EndConnection();
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -120,7 +118,9 @@ namespace OpenWifi {
 | 
				
			|||||||
			Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
 | 
								Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
 | 
				
			||||||
			if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
 | 
								if (!AP_WS_Server()->ValidateCertificate(CId_, PeerCert)) {
 | 
				
			||||||
				State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
 | 
									State_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
 | 
				
			||||||
				poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not valid. Device is not allowed.",
 | 
									poco_warning(Logger_,
 | 
				
			||||||
 | 
												 fmt::format("TLS-CONNECTION({}): Session={} Device certificate is not "
 | 
				
			||||||
 | 
															 "valid. Device is not allowed.",
 | 
				
			||||||
										 CId_, State_.sessionId));
 | 
															 CId_, State_.sessionId));
 | 
				
			||||||
				EndConnection();
 | 
									EndConnection();
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
@@ -128,96 +128,135 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
 | 
								CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
 | 
				
			||||||
			State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
 | 
								State_.VerifiedCertificate = GWObjects::VALID_CERTIFICATE;
 | 
				
			||||||
			poco_debug(Logger_,
 | 
								poco_trace(Logger_,
 | 
				
			||||||
					   fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_, State_.sessionId , CN_));
 | 
										   fmt::format("TLS-CONNECTION({}): Session={} Valid certificate: CN={}", CId_,
 | 
				
			||||||
 | 
													   State_.sessionId, CN_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
 | 
								if (AP_WS_Server::IsSim(CN_) && !AP_WS_Server()->IsSimEnabled()) {
 | 
				
			||||||
				poco_warning(
 | 
									poco_warning(Logger_, fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is "
 | 
				
			||||||
					Logger_,
 | 
																	  "not allowed. Disconnecting.",
 | 
				
			||||||
					fmt::format("TLS-CONNECTION({}): Session={} Sim Device {} is not allowed. Disconnecting.",
 | 
					 | 
				
			||||||
												  CId_, State_.sessionId, CN_));
 | 
																	  CId_, State_.sessionId, CN_));
 | 
				
			||||||
				EndConnection();
 | 
									EndConnection();
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!CN_.empty() && StorageService()->IsBlackListed(SerialNumber_)) {
 | 
								if(AP_WS_Server::IsSim(CN_)) {
 | 
				
			||||||
 | 
									State_.VerifiedCertificate = GWObjects::SIMULATED;
 | 
				
			||||||
 | 
									Simulated_ = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::string reason, author;
 | 
				
			||||||
 | 
								std::uint64_t created;
 | 
				
			||||||
 | 
								if (!CN_.empty() && StorageService()->IsBlackListed(CN_, reason, author, created)) {
 | 
				
			||||||
 | 
									DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
 | 
				
			||||||
				poco_warning(
 | 
									poco_warning(
 | 
				
			||||||
					Logger_,
 | 
										Logger_,
 | 
				
			||||||
					fmt::format("TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
 | 
										fmt::format(
 | 
				
			||||||
 | 
											"TLS-CONNECTION({}): Session={} Device {} is black listed. Disconnecting.",
 | 
				
			||||||
						CId_, State_.sessionId, CN_));
 | 
											CId_, State_.sessionId, CN_));
 | 
				
			||||||
				EndConnection();
 | 
									EndConnection();
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
 | 
				
			||||||
			SerialNumber_ = CN_;
 | 
								SerialNumber_ = CN_;
 | 
				
			||||||
			SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
 | 
								SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			poco_debug(Logger_, fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_, State_.sessionId , CN_, ConcurrentStartingDevices_));
 | 
								poco_trace(Logger_,
 | 
				
			||||||
 | 
										   fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
 | 
				
			||||||
 | 
													   State_.sessionId, CN_, ConcurrentStartingDevices_));
 | 
				
			||||||
			DeviceValidated_ = true;
 | 
								DeviceValidated_ = true;
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} catch (const Poco::Net::CertificateValidationException &E) {
 | 
							} catch (const Poco::Net::CertificateValidationException &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate Validation failed during connection. Device will have to retry.",
 | 
								poco_error(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format(
 | 
				
			||||||
 | 
										"CONNECTION({}): Session:{} Poco::CertificateValidationException Certificate "
 | 
				
			||||||
 | 
										"Validation failed during connection. Device will have to retry.",
 | 
				
			||||||
					CId_, State_.sessionId));
 | 
										CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (const Poco::Net::WebSocketException &E) {
 | 
							} catch (const Poco::Net::WebSocketException &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket error during connection. Device will have to retry.",
 | 
								poco_error(Logger_,
 | 
				
			||||||
 | 
										   fmt::format("CONNECTION({}): Session:{} Poco::WebSocketException WebSocket "
 | 
				
			||||||
 | 
													   "error during connection. Device will have to retry.",
 | 
				
			||||||
								   CId_, State_.sessionId));
 | 
													   CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (const Poco::Net::ConnectionAbortedException &E) {
 | 
							} catch (const Poco::Net::ConnectionAbortedException &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}):Session:{}  Poco::ConnectionAbortedException Connection was aborted during connection. Device will have to retry.",
 | 
								poco_error(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("CONNECTION({}):Session:{}  Poco::ConnectionAbortedException "
 | 
				
			||||||
 | 
												"Connection was aborted during connection. Device will have to retry.",
 | 
				
			||||||
							CId_, State_.sessionId));
 | 
												CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (const Poco::Net::ConnectionResetException &E) {
 | 
							} catch (const Poco::Net::ConnectionResetException &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection was reset during connection. Device will have to retry.",
 | 
								poco_error(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("CONNECTION({}): Session:{} Poco::ConnectionResetException Connection "
 | 
				
			||||||
 | 
												"was reset during connection. Device will have to retry.",
 | 
				
			||||||
							CId_, State_.sessionId));
 | 
												CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (const Poco::Net::InvalidCertificateException &E) {
 | 
							} catch (const Poco::Net::InvalidCertificateException &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format(
 | 
								poco_error(Logger_,
 | 
				
			||||||
									"CONNECTION({}): Session:{} Poco::InvalidCertificateException Invalid certificate. Device will have to retry.",
 | 
										   fmt::format("CONNECTION({}): Session:{} Poco::InvalidCertificateException "
 | 
				
			||||||
 | 
													   "Invalid certificate. Device will have to retry.",
 | 
				
			||||||
								   CId_, State_.sessionId));
 | 
													   CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (const Poco::Net::SSLException &E) {
 | 
							} catch (const Poco::Net::SSLException &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception during connection. Device will have to retry.",
 | 
								poco_error(Logger_,
 | 
				
			||||||
 | 
										   fmt::format("CONNECTION({}): Session:{} Poco::SSLException SSL Exception "
 | 
				
			||||||
 | 
													   "during connection. Device will have to retry.",
 | 
				
			||||||
								   CId_, State_.sessionId));
 | 
													   CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Poco::Exception caught during device connection. Device will have to retry.",
 | 
								poco_error(Logger_, fmt::format("CONNECTION({}): Session:{} Poco::Exception caught "
 | 
				
			||||||
 | 
																"during device connection. Device will have to retry.",
 | 
				
			||||||
											CId_, State_.sessionId));
 | 
																CId_, State_.sessionId));
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. Device will have to retry. Unsecure connect denied.",
 | 
								poco_error(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("CONNECTION({}): Session:{} Exception caught during device connection. "
 | 
				
			||||||
 | 
												"Device will have to retry. Unsecure connect denied.",
 | 
				
			||||||
							CId_, State_.sessionId));
 | 
												CId_, State_.sessionId));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		EndConnection();
 | 
							EndConnection();
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void NotifyKafkaDisconnect(const std::string & SerialNumber) {
 | 
						static void NotifyKafkaDisconnect(const std::string &SerialNumber, std::uint64_t uuid) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			Poco::JSON::Object Disconnect;
 | 
								Poco::JSON::Object Disconnect;
 | 
				
			||||||
			Poco::JSON::Object Details;
 | 
								Poco::JSON::Object Details;
 | 
				
			||||||
			Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
 | 
								Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber);
 | 
				
			||||||
			Details.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
 | 
								Details.set(uCentralProtocol::TIMESTAMP, Utils::Now());
 | 
				
			||||||
 | 
								Details.set(uCentralProtocol::UUID,uuid);
 | 
				
			||||||
			Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
 | 
								Disconnect.set(uCentralProtocol::DISCONNECTION, Details);
 | 
				
			||||||
			Poco::JSON::Stringifier Stringify;
 | 
								KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, Disconnect);
 | 
				
			||||||
			std::ostringstream OS;
 | 
					 | 
				
			||||||
			Stringify.condense(Disconnect, OS);
 | 
					 | 
				
			||||||
			KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber, OS.str());
 | 
					 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AP_WS_Connection::~AP_WS_Connection() {
 | 
						AP_WS_Connection::~AP_WS_Connection() {
 | 
				
			||||||
		std::cout << "Deleting session=" << State_.sessionId << std::endl;
 | 
					 | 
				
			||||||
		Valid_ = false;
 | 
							Valid_ = false;
 | 
				
			||||||
		EndConnection();
 | 
							EndConnection();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::EndConnection() {
 | 
						void DeviceDisconnectionCleanup(const std::string &SerialNumber, std::uint64_t uuid) {
 | 
				
			||||||
 | 
							if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
								NotifyKafkaDisconnect(SerialNumber, uuid);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							RADIUSSessionTracker()->DeviceDisconnect(SerialNumber);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AP_WS_Connection::EndConnection(bool DeleteSession) {
 | 
				
			||||||
    	Valid_ = false;
 | 
					    	Valid_ = false;
 | 
				
			||||||
		if (!Dead_.test_and_set()) {
 | 
							if (!Dead_.test_and_set()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(!SerialNumber_.empty() && State_.LastContact!=0) {
 | 
				
			||||||
 | 
									StorageService()->SetDeviceLastRecordedContact(SerialNumber_, State_.LastContact);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (Registered_) {
 | 
								if (Registered_) {
 | 
				
			||||||
				Registered_ = false;
 | 
									Registered_ = false;
 | 
				
			||||||
				Reactor_.removeEventHandler(
 | 
									Reactor_.removeEventHandler(
 | 
				
			||||||
@@ -232,15 +271,20 @@ namespace OpenWifi {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			WS_->close();
 | 
								WS_->close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (KafkaManager()->Enabled() && !SerialNumber_.empty()) {
 | 
								if(!SerialNumber_.empty()) {
 | 
				
			||||||
				std::string s(SerialNumber_);
 | 
									std::thread	Cleanup(DeviceDisconnectionCleanup,SerialNumber_, uuid_);
 | 
				
			||||||
				std::thread t([s]() { NotifyKafkaDisconnect(s); });
 | 
									Cleanup.detach();
 | 
				
			||||||
				t.detach();
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
 | 
								bool SessionDeleted = false;
 | 
				
			||||||
			if (SessionDeleted)
 | 
								if(DeleteSession)
 | 
				
			||||||
				WebSocketClientNotificationDeviceDisconnected(SerialNumber_);
 | 
									SessionDeleted = AP_WS_Server()->EndSession(State_.sessionId, SerialNumberInt_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (SessionDeleted || !DeleteSession) {
 | 
				
			||||||
 | 
									GWWebSocketNotifications::SingleDevice_t N;
 | 
				
			||||||
 | 
									N.content.serialNumber = SerialNumber_;
 | 
				
			||||||
 | 
									GWWebSocketNotifications::DeviceDisconnected(N);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -259,29 +303,36 @@ namespace OpenWifi {
 | 
				
			|||||||
		GWObjects::Device D;
 | 
							GWObjects::Device D;
 | 
				
			||||||
		if (StorageService()->GetDevice(SerialNumber_, D)) {
 | 
							if (StorageService()->GetDevice(SerialNumber_, D)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//	This is the case where the cache is empty after a restart. So GoodConfig will 0. If the device already 	has the right UUID, we just return.
 | 
								if(D.pendingUUID!=0 && UUID==D.pendingUUID) {
 | 
				
			||||||
 | 
									//	so we sent an upgrade to a device, and now it is completing now...
 | 
				
			||||||
 | 
									UpgradedUUID = D.pendingUUID;
 | 
				
			||||||
 | 
									StorageService()->CompleteDeviceConfigurationChange(SerialNumber_);
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//	This is the case where the cache is empty after a restart. So GoodConfig will 0. If
 | 
				
			||||||
 | 
								// the device already 	has the right UUID, we just return.
 | 
				
			||||||
			if (D.UUID == UUID) {
 | 
								if (D.UUID == UUID) {
 | 
				
			||||||
				UpgradedUUID = UUID;
 | 
									UpgradedUUID = UUID;
 | 
				
			||||||
				ConfigurationCache().Add(SerialNumberInt_, UUID);
 | 
									ConfigurationCache().Add(SerialNumberInt_, UUID);
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(UUID>D.UUID) {
 | 
					 | 
				
			||||||
				//	so we have a problem, the device has a newer config than we have. So we need to make sure our config
 | 
					 | 
				
			||||||
				//	is newer.
 | 
					 | 
				
			||||||
			Config::Config Cfg(D.Configuration);
 | 
								Config::Config Cfg(D.Configuration);
 | 
				
			||||||
 | 
								if (UUID > D.UUID) {
 | 
				
			||||||
 | 
									//	so we have a problem, the device has a newer config than we have. So we need to
 | 
				
			||||||
 | 
									// make sure our config 	is newer.
 | 
				
			||||||
				D.UUID = UUID + 2;
 | 
									D.UUID = UUID + 2;
 | 
				
			||||||
				UpgradedUUID = D.UUID;
 | 
									UpgradedUUID = D.UUID;
 | 
				
			||||||
				Cfg.SetUUID(D.UUID);
 | 
					 | 
				
			||||||
				D.Configuration = Cfg.get();
 | 
					 | 
				
			||||||
				StorageService()->UpdateDevice(D);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			UpgradedUUID = D.UUID;
 | 
								Cfg.SetUUID(D.UUID);
 | 
				
			||||||
			State_.PendingUUID = D.UUID;
 | 
								D.Configuration = Cfg.get();
 | 
				
			||||||
 | 
								State_.PendingUUID = UpgradedUUID = D.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			GWObjects::CommandDetails Cmd;
 | 
								GWObjects::CommandDetails Cmd;
 | 
				
			||||||
			Cmd.SerialNumber = SerialNumber_;
 | 
								Cmd.SerialNumber = SerialNumber_;
 | 
				
			||||||
			Cmd.UUID = MicroService::CreateUUID();
 | 
								Cmd.UUID = MicroServiceCreateUUID();
 | 
				
			||||||
			Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
 | 
								Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
 | 
				
			||||||
			Cmd.Status = uCentralProtocol::PENDING;
 | 
								Cmd.Status = uCentralProtocol::PENDING;
 | 
				
			||||||
			Cmd.Command = uCentralProtocol::CONFIGURE;
 | 
								Cmd.Command = uCentralProtocol::CONFIGURE;
 | 
				
			||||||
@@ -296,14 +347,22 @@ namespace OpenWifi {
 | 
				
			|||||||
			std::ostringstream O;
 | 
								std::ostringstream O;
 | 
				
			||||||
			Poco::JSON::Stringifier::stringify(Params, O);
 | 
								Poco::JSON::Stringifier::stringify(Params, O);
 | 
				
			||||||
			Cmd.Details = O.str();
 | 
								Cmd.Details = O.str();
 | 
				
			||||||
			poco_information(Logger_,fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
 | 
								poco_information(Logger_,
 | 
				
			||||||
 | 
												 fmt::format("CFG-UPGRADE({}): Current ID: {}, newer configuration {}.",
 | 
				
			||||||
										 CId_, UUID, D.UUID));
 | 
															 CId_, UUID, D.UUID));
 | 
				
			||||||
			bool Sent;
 | 
								bool Sent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
 | 
								StorageService()->AddCommand(SerialNumber_, Cmd,
 | 
				
			||||||
			CommandManager()->PostCommand(CommandManager()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
 | 
															 Storage::CommandExecutionType::COMMAND_EXECUTED);
 | 
				
			||||||
 | 
								CommandManager()->PostCommand(
 | 
				
			||||||
 | 
									CommandManager()->Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
 | 
				
			||||||
 | 
									SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent, false, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			WebSocketClientNotificationDeviceConfigurationChange(D.SerialNumber, UUID, UpgradedUUID);
 | 
								GWWebSocketNotifications::SingleDeviceConfigurationChange_t Notification;
 | 
				
			||||||
 | 
								Notification.content.serialNumber = D.SerialNumber;
 | 
				
			||||||
 | 
								Notification.content.oldUUID = UUID;
 | 
				
			||||||
 | 
								Notification.content.newUUID = UpgradedUUID;
 | 
				
			||||||
 | 
								GWWebSocketNotifications::DeviceConfigurationChange(Notification);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -311,21 +370,24 @@ namespace OpenWifi {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
 | 
						void AP_WS_Connection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc) {
 | 
				
			||||||
		poco_debug(Logger_,fmt::format("RECEIVED-RPC({}): {}.", CId_, Doc->get(uCentralProtocol::ID).toString()));
 | 
							poco_trace(Logger_, fmt::format("RECEIVED-RPC({}): {}.", CId_,
 | 
				
			||||||
		CommandManager()->PostCommandResult(SerialNumber_, *Doc);
 | 
															Doc->get(uCentralProtocol::ID).toString()));
 | 
				
			||||||
 | 
							CommandManager()->PostCommandResult(SerialNumber_, Doc);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc) {
 | 
						void AP_WS_Connection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc) {
 | 
				
			||||||
		auto Method = Doc->get(uCentralProtocol::METHOD).toString();
 | 
							auto Method = Doc->get(uCentralProtocol::METHOD).toString();
 | 
				
			||||||
		auto EventType = uCentralProtocol::Events::EventFromString(Method);
 | 
							auto EventType = uCentralProtocol::Events::EventFromString(Method);
 | 
				
			||||||
		if (EventType == uCentralProtocol::Events::ET_UNKNOWN) {
 | 
							if (EventType == uCentralProtocol::Events::ET_UNKNOWN) {
 | 
				
			||||||
			poco_warning(Logger_,fmt::format("ILLEGAL-PROTOCOL({}): Unknown message type '{}'", CId_, Method));
 | 
								poco_warning(Logger_, fmt::format("ILLEGAL-PROTOCOL({}): Unknown message type '{}'",
 | 
				
			||||||
 | 
																  CId_, Method));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!Doc->isObject(uCentralProtocol::PARAMS)) {
 | 
							if (!Doc->isObject(uCentralProtocol::PARAMS)) {
 | 
				
			||||||
			poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): params must be an object.", CId_));
 | 
								poco_warning(Logger_,
 | 
				
			||||||
 | 
											 fmt::format("MISSING-PARAMS({}): params must be an object.", CId_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -341,19 +403,24 @@ namespace OpenWifi {
 | 
				
			|||||||
					compress_sz = ParamsObj->get("compress_sz");
 | 
										compress_sz = ParamsObj->get("compress_sz");
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (Utils::ExtractBase64CompressedData(CompressedData, UncompressedData, compress_sz)) {
 | 
									if (Utils::ExtractBase64CompressedData(CompressedData, UncompressedData,
 | 
				
			||||||
					poco_trace(Logger_,fmt::format("EVENT({}): Found compressed payload expanded to '{}'.",
 | 
																		   compress_sz)) {
 | 
				
			||||||
 | 
										poco_trace(Logger_,
 | 
				
			||||||
 | 
												   fmt::format("EVENT({}): Found compressed payload expanded to '{}'.",
 | 
				
			||||||
										   CId_, UncompressedData));
 | 
															   CId_, UncompressedData));
 | 
				
			||||||
					Poco::JSON::Parser Parser;
 | 
										Poco::JSON::Parser Parser;
 | 
				
			||||||
					ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
 | 
										ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-DATA({}): Compressed cannot be uncompressed - content must be corrupt..: size={}",
 | 
										poco_warning(Logger_,
 | 
				
			||||||
 | 
													 fmt::format("INVALID-COMPRESSED-DATA({}): Compressed cannot be "
 | 
				
			||||||
 | 
																 "uncompressed - content must be corrupt..: size={}",
 | 
				
			||||||
											 CId_, CompressedData.size()));
 | 
																 CId_, CompressedData.size()));
 | 
				
			||||||
					Errors_++;
 | 
										Errors_++;
 | 
				
			||||||
					return;
 | 
										return;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (const Poco::Exception &E) {
 | 
								} catch (const Poco::Exception &E) {
 | 
				
			||||||
				poco_warning(Logger_,fmt::format("INVALID-COMPRESSED-JSON-DATA({}): Compressed cannot be parsed - JSON must be corrupt..",
 | 
									poco_warning(Logger_, fmt::format("INVALID-COMPRESSED-JSON-DATA({}): Compressed "
 | 
				
			||||||
 | 
																	  "cannot be parsed - JSON must be corrupt..",
 | 
				
			||||||
												  CId_));
 | 
																	  CId_));
 | 
				
			||||||
				Logger_.log(E);
 | 
									Logger_.log(E);
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
@@ -361,11 +428,14 @@ namespace OpenWifi {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!ParamsObj->has(uCentralProtocol::SERIAL)) {
 | 
							if (!ParamsObj->has(uCentralProtocol::SERIAL)) {
 | 
				
			||||||
			poco_warning(Logger_,fmt::format("MISSING-PARAMS({}): Serial number is missing in message.", CId_));
 | 
								poco_warning(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("MISSING-PARAMS({}): Serial number is missing in message.", CId_));
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto Serial = Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
 | 
							auto Serial =
 | 
				
			||||||
 | 
								Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
 | 
				
			||||||
		if (!Utils::ValidSerialNumber(Serial)) {
 | 
							if (!Utils::ValidSerialNumber(Serial)) {
 | 
				
			||||||
			Poco::Exception E(
 | 
								Poco::Exception E(
 | 
				
			||||||
				fmt::format(
 | 
									fmt::format(
 | 
				
			||||||
@@ -375,7 +445,10 @@ namespace OpenWifi {
 | 
				
			|||||||
			E.rethrow();
 | 
								E.rethrow();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (StorageService()->IsBlackListed(Serial)) {
 | 
							std::string reason, author;
 | 
				
			||||||
 | 
							std::uint64_t created;
 | 
				
			||||||
 | 
							if (StorageService()->IsBlackListed(Serial, reason, author, created)) {
 | 
				
			||||||
 | 
								DeviceBlacklistedKafkaEvent KE(Utils::SerialNumberToInt(CN_), Utils::Now(), reason, author, created, CId_);
 | 
				
			||||||
			Poco::Exception E(
 | 
								Poco::Exception E(
 | 
				
			||||||
				fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
 | 
									fmt::format("BLACKLIST({}): device is blacklisted and not allowed to connect.",
 | 
				
			||||||
							Serial),
 | 
												Serial),
 | 
				
			||||||
@@ -428,27 +501,50 @@ namespace OpenWifi {
 | 
				
			|||||||
			Process_venuebroadcast(ParamsObj);
 | 
								Process_venuebroadcast(ParamsObj);
 | 
				
			||||||
		} break;
 | 
							} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case uCentralProtocol::Events::ET_EVENT: {
 | 
				
			||||||
 | 
								Process_event(ParamsObj);
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case uCentralProtocol::Events::ET_ALARM: {
 | 
				
			||||||
 | 
								Process_alarm(ParamsObj);
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case uCentralProtocol::Events::ET_WIFISCAN: {
 | 
				
			||||||
 | 
								Process_wifiscan(ParamsObj);
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case uCentralProtocol::Events::ET_REBOOTLOG: {
 | 
				
			||||||
 | 
								Process_rebootLog(ParamsObj);
 | 
				
			||||||
 | 
							} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 	this will never be called but some compilers will complain if we do not have a case for
 | 
							// 	this will never be called but some compilers will complain if we do not have a case for
 | 
				
			||||||
		//	every single values of an enum
 | 
							//	every single values of an enum
 | 
				
			||||||
		case uCentralProtocol::Events::ET_UNKNOWN: {
 | 
							case uCentralProtocol::Events::ET_UNKNOWN: {
 | 
				
			||||||
				poco_warning(Logger_, fmt::format("ILLEGAL-EVENT({}): Event '{}' unknown. CN={}", CId_, Method, CN_));
 | 
								poco_warning(Logger_, fmt::format("ILLEGAL-EVENT({}): Event '{}' unknown. CN={}", CId_,
 | 
				
			||||||
 | 
																  Method, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::StartTelemetry(std::uint64_t RPCID) {
 | 
						bool AP_WS_Connection::StartTelemetry(uint64_t RPCID,
 | 
				
			||||||
 | 
															  const std::vector<std::string> &TelemetryTypes) {
 | 
				
			||||||
		poco_information(Logger_, fmt::format("TELEMETRY({}): Starting.", CId_));
 | 
							poco_information(Logger_, fmt::format("TELEMETRY({}): Starting.", CId_));
 | 
				
			||||||
		Poco::JSON::Object StartMessage;
 | 
							Poco::JSON::Object StartMessage;
 | 
				
			||||||
		StartMessage.set("jsonrpc", "2.0");
 | 
							StartMessage.set("jsonrpc", "2.0");
 | 
				
			||||||
		StartMessage.set("method", "telemetry");
 | 
							StartMessage.set("method", "telemetry");
 | 
				
			||||||
		Poco::JSON::Object Params;
 | 
							Poco::JSON::Object Params;
 | 
				
			||||||
		Params.set("serial", SerialNumber_);
 | 
							Params.set("serial", SerialNumber_);
 | 
				
			||||||
		Params.set("interval", TelemetryInterval_);
 | 
							Params.set("interval", (uint64_t)TelemetryInterval_);
 | 
				
			||||||
		Poco::JSON::Array Types;
 | 
							Poco::JSON::Array Types;
 | 
				
			||||||
 | 
							if (TelemetryTypes.empty()) {
 | 
				
			||||||
			Types.add("wifi-frames");
 | 
								Types.add("wifi-frames");
 | 
				
			||||||
			Types.add("dhcp-snooping");
 | 
								Types.add("dhcp-snooping");
 | 
				
			||||||
			Types.add("state");
 | 
								Types.add("state");
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								for (const auto &type : TelemetryTypes)
 | 
				
			||||||
 | 
									Types.add(type);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		Params.set(RESTAPI::Protocol::TYPES, Types);
 | 
							Params.set(RESTAPI::Protocol::TYPES, Types);
 | 
				
			||||||
		StartMessage.set("id", RPCID);
 | 
							StartMessage.set("id", RPCID);
 | 
				
			||||||
		StartMessage.set("params", Params);
 | 
							StartMessage.set("params", Params);
 | 
				
			||||||
@@ -458,7 +554,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		return Send(OS.str());
 | 
							return Send(OS.str());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::StopTelemetry(std::uint64_t RPCID) {
 | 
						bool AP_WS_Connection::StopTelemetry(uint64_t RPCID) {
 | 
				
			||||||
		poco_information(Logger_, fmt::format("TELEMETRY({}): Stopping.", CId_));
 | 
							poco_information(Logger_, fmt::format("TELEMETRY({}): Stopping.", CId_));
 | 
				
			||||||
		Poco::JSON::Object StopMessage;
 | 
							Poco::JSON::Object StopMessage;
 | 
				
			||||||
		StopMessage.set("jsonrpc", "2.0");
 | 
							StopMessage.set("jsonrpc", "2.0");
 | 
				
			||||||
@@ -481,36 +577,47 @@ namespace OpenWifi {
 | 
				
			|||||||
		State_.webSocketClients = TelemetryWebSocketRefCount_;
 | 
							State_.webSocketClients = TelemetryWebSocketRefCount_;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t Interval,
 | 
						bool AP_WS_Connection::SetWebSocketTelemetryReporting(
 | 
				
			||||||
													  uint64_t LifeTime) {
 | 
							uint64_t RPCID, uint64_t Interval, uint64_t LifeTime,
 | 
				
			||||||
 | 
							const std::vector<std::string> &TelemetryTypes) {
 | 
				
			||||||
		std::unique_lock Lock(TelemetryMutex_);
 | 
							std::unique_lock Lock(TelemetryMutex_);
 | 
				
			||||||
		TelemetryWebSocketRefCount_++;
 | 
							TelemetryWebSocketRefCount_++;
 | 
				
			||||||
		TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
 | 
							TelemetryInterval_ = TelemetryInterval_
 | 
				
			||||||
		auto TelemetryWebSocketTimer = LifeTime + OpenWifi::Now();
 | 
													 ? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
 | 
				
			||||||
		TelemetryWebSocketTimer_ = std::max(TelemetryWebSocketTimer, TelemetryWebSocketTimer_);
 | 
													 : Interval;
 | 
				
			||||||
 | 
							auto TelemetryWebSocketTimer = LifeTime + Utils::Now();
 | 
				
			||||||
 | 
							TelemetryWebSocketTimer_ = TelemetryWebSocketTimer > TelemetryWebSocketTimer_
 | 
				
			||||||
 | 
														   ? TelemetryWebSocketTimer
 | 
				
			||||||
 | 
														   : TelemetryWebSocketTimer_;
 | 
				
			||||||
		UpdateCounts();
 | 
							UpdateCounts();
 | 
				
			||||||
		if (!TelemetryReporting_) {
 | 
							if (!TelemetryReporting_) {
 | 
				
			||||||
			TelemetryReporting_ = true;
 | 
								TelemetryReporting_ = true;
 | 
				
			||||||
			return StartTelemetry(RPCID);
 | 
								return StartTelemetry(RPCID, TelemetryTypes);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t Interval, uint64_t LifeTime) {
 | 
						bool
 | 
				
			||||||
 | 
						AP_WS_Connection::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t Interval,
 | 
				
			||||||
 | 
																	 uint64_t LifeTime,
 | 
				
			||||||
 | 
																	 const std::vector<std::string> &TelemetryTypes) {
 | 
				
			||||||
		std::unique_lock Lock(TelemetryMutex_);
 | 
							std::unique_lock Lock(TelemetryMutex_);
 | 
				
			||||||
		TelemetryKafkaRefCount_++;
 | 
							TelemetryKafkaRefCount_++;
 | 
				
			||||||
		TelemetryInterval_ = TelemetryInterval_ ? std::min(Interval, TelemetryInterval_) : Interval;
 | 
							TelemetryInterval_ = TelemetryInterval_
 | 
				
			||||||
		auto TelemetryKafkaTimer = LifeTime + OpenWifi::Now();
 | 
													 ? (Interval < TelemetryInterval_ ? Interval : TelemetryInterval_)
 | 
				
			||||||
		TelemetryKafkaTimer_ = std::max(TelemetryKafkaTimer, TelemetryKafkaTimer_);
 | 
													 : Interval;
 | 
				
			||||||
 | 
							auto TelemetryKafkaTimer = LifeTime + Utils::Now();
 | 
				
			||||||
 | 
							TelemetryKafkaTimer_ =
 | 
				
			||||||
 | 
								TelemetryKafkaTimer > TelemetryKafkaTimer_ ? TelemetryKafkaTimer : TelemetryKafkaTimer_;
 | 
				
			||||||
		UpdateCounts();
 | 
							UpdateCounts();
 | 
				
			||||||
		if (!TelemetryReporting_) {
 | 
							if (!TelemetryReporting_) {
 | 
				
			||||||
			TelemetryReporting_ = true;
 | 
								TelemetryReporting_ = true;
 | 
				
			||||||
			return StartTelemetry(RPCID);
 | 
								return StartTelemetry(RPCID, TelemetryTypes);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::StopWebSocketTelemetry(std::uint64_t RPCID) {
 | 
						bool AP_WS_Connection::StopWebSocketTelemetry(uint64_t RPCID) {
 | 
				
			||||||
		std::unique_lock Lock(TelemetryMutex_);
 | 
							std::unique_lock Lock(TelemetryMutex_);
 | 
				
			||||||
		if (TelemetryWebSocketRefCount_)
 | 
							if (TelemetryWebSocketRefCount_)
 | 
				
			||||||
			TelemetryWebSocketRefCount_--;
 | 
								TelemetryWebSocketRefCount_--;
 | 
				
			||||||
@@ -522,7 +629,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::StopKafkaTelemetry(std::uint64_t RPCID) {
 | 
						bool AP_WS_Connection::StopKafkaTelemetry(uint64_t RPCID) {
 | 
				
			||||||
		std::unique_lock Lock(TelemetryMutex_);
 | 
							std::unique_lock Lock(TelemetryMutex_);
 | 
				
			||||||
		if (TelemetryKafkaRefCount_)
 | 
							if (TelemetryKafkaRefCount_)
 | 
				
			||||||
			TelemetryKafkaRefCount_--;
 | 
								TelemetryKafkaRefCount_--;
 | 
				
			||||||
@@ -534,17 +641,20 @@ namespace OpenWifi {
 | 
				
			|||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
 | 
						void AP_WS_Connection::OnSocketShutdown(
 | 
				
			||||||
 | 
							[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
 | 
				
			||||||
		poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
 | 
							poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
 | 
				
			||||||
		return EndConnection();
 | 
							return EndConnection();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::OnSocketError([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
 | 
						void AP_WS_Connection::OnSocketError(
 | 
				
			||||||
 | 
							[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
 | 
				
			||||||
		poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
 | 
							poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
 | 
				
			||||||
		return EndConnection();
 | 
							return EndConnection();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
 | 
						void AP_WS_Connection::OnSocketReadable(
 | 
				
			||||||
 | 
							[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!Valid_)
 | 
							if (!Valid_)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
@@ -562,10 +672,13 @@ namespace OpenWifi {
 | 
				
			|||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const std::exception &E) {
 | 
							} catch (const std::exception &E) {
 | 
				
			||||||
			std::string W = E.what();
 | 
								std::string W = E.what();
 | 
				
			||||||
			poco_information(Logger_, fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
 | 
								poco_information(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("std::exception caught: {}. Connection terminated with {}", W, CId_));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_information(Logger_, fmt::format("Unknown exception for {}. Connection terminated.", CId_));
 | 
								poco_information(Logger_,
 | 
				
			||||||
 | 
												 fmt::format("Unknown exception for {}. Connection terminated.", CId_));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -579,15 +692,18 @@ namespace OpenWifi {
 | 
				
			|||||||
			Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
								Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (IncomingSize == 0 && flags == 0 && Op == 0) {
 | 
								if (IncomingSize == 0 && flags == 0 && Op == 0) {
 | 
				
			||||||
				poco_information(Logger_, fmt::format("DISCONNECT({}): device has disconnected. Session={}", CId_, State_.sessionId));
 | 
									poco_information(Logger_,
 | 
				
			||||||
 | 
													 fmt::format("DISCONNECT({}): device has disconnected. Session={}",
 | 
				
			||||||
 | 
																 CId_, State_.sessionId));
 | 
				
			||||||
				return EndConnection();
 | 
									return EndConnection();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			IncomingFrame.append(0);
 | 
								IncomingFrame.append(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			State_.RX += IncomingSize;
 | 
								State_.RX += IncomingSize;
 | 
				
			||||||
 | 
								AP_WS_Server()->AddRX(IncomingSize);
 | 
				
			||||||
			State_.MessageCount++;
 | 
								State_.MessageCount++;
 | 
				
			||||||
			State_.LastContact = OpenWifi::Now();
 | 
								State_.LastContact = Utils::Now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (Op) {
 | 
								switch (Op) {
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_PING: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_PING: {
 | 
				
			||||||
@@ -595,7 +711,6 @@ namespace OpenWifi {
 | 
				
			|||||||
				WS_->sendFrame("", 0,
 | 
									WS_->sendFrame("", 0,
 | 
				
			||||||
							   (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
												   (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
				
			||||||
								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
													   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
				
			||||||
					State_.MessageCount++;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (KafkaManager()->Enabled()) {
 | 
									if (KafkaManager()->Enabled()) {
 | 
				
			||||||
					Poco::JSON::Object PingObject;
 | 
										Poco::JSON::Object PingObject;
 | 
				
			||||||
@@ -604,13 +719,12 @@ namespace OpenWifi {
 | 
				
			|||||||
					PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
 | 
										PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
 | 
				
			||||||
					PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
 | 
										PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
 | 
				
			||||||
					PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
 | 
										PingDetails.set(uCentralProtocol::CONNECTIONIP, CId_);
 | 
				
			||||||
						PingDetails.set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
 | 
										PingDetails.set(uCentralProtocol::TIMESTAMP, Utils::Now());
 | 
				
			||||||
 | 
										PingDetails.set(uCentralProtocol::UUID, uuid_);
 | 
				
			||||||
					PingDetails.set("locale", State_.locale);
 | 
										PingDetails.set("locale", State_.locale);
 | 
				
			||||||
					PingObject.set(uCentralProtocol::PING, PingDetails);
 | 
										PingObject.set(uCentralProtocol::PING, PingDetails);
 | 
				
			||||||
						Poco::JSON::Stringifier Stringify;
 | 
										poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
 | 
				
			||||||
						std::ostringstream OS;
 | 
										KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
 | 
				
			||||||
						Stringify.condense(PingObject, OS);
 | 
					 | 
				
			||||||
						KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
@@ -621,8 +735,9 @@ namespace OpenWifi {
 | 
				
			|||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
				
			||||||
					poco_trace(Logger_, fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}", CId_,
 | 
									poco_trace(Logger_,
 | 
				
			||||||
									 IncomingSize, flags, IncomingFrame.begin()));
 | 
											   fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
 | 
				
			||||||
 | 
														   CId_, IncomingSize, flags, IncomingFrame.begin()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Poco::JSON::Parser parser;
 | 
									Poco::JSON::Parser parser;
 | 
				
			||||||
				auto ParsedMessage = parser.parse(IncomingFrame.begin());
 | 
									auto ParsedMessage = parser.parse(IncomingFrame.begin());
 | 
				
			||||||
@@ -634,10 +749,12 @@ namespace OpenWifi {
 | 
				
			|||||||
						ProcessJSONRPCEvent(IncomingJSON);
 | 
											ProcessJSONRPCEvent(IncomingJSON);
 | 
				
			||||||
					} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
 | 
										} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
 | 
				
			||||||
							   IncomingJSON->has(uCentralProtocol::ID)) {
 | 
												   IncomingJSON->has(uCentralProtocol::ID)) {
 | 
				
			||||||
							poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_, IncomingFrame.begin()));
 | 
											poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_,
 | 
				
			||||||
 | 
																			IncomingFrame.begin()));
 | 
				
			||||||
						ProcessJSONRPCResult(IncomingJSON);
 | 
											ProcessJSONRPCResult(IncomingJSON);
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
							poco_warning(Logger_,
 | 
											poco_warning(
 | 
				
			||||||
 | 
												Logger_,
 | 
				
			||||||
							fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
 | 
												fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
 | 
				
			||||||
										CId_, IncomingFrame.begin()));
 | 
															CId_, IncomingFrame.begin()));
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -647,8 +764,10 @@ namespace OpenWifi {
 | 
				
			|||||||
					std::ostringstream iS;
 | 
										std::ostringstream iS;
 | 
				
			||||||
					IncomingJSON->stringify(iS);
 | 
										IncomingJSON->stringify(iS);
 | 
				
			||||||
					std::cout << iS.str() << std::endl;
 | 
										std::cout << iS.str() << std::endl;
 | 
				
			||||||
						poco_warning(Logger_, fmt::format(
 | 
										poco_warning(
 | 
				
			||||||
												   "FRAME({}): illegal transaction header, missing 'jsonrpc'", CId_));
 | 
											Logger_,
 | 
				
			||||||
 | 
											fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc'",
 | 
				
			||||||
 | 
														CId_));
 | 
				
			||||||
					Errors_++;
 | 
										Errors_++;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
@@ -661,75 +780,79 @@ namespace OpenWifi {
 | 
				
			|||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			default: {
 | 
								default: {
 | 
				
			||||||
					poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}", CId_,
 | 
									poco_warning(Logger_, fmt::format("UNKNOWN({}): unknown WS Frame operation: {}",
 | 
				
			||||||
												  std::to_string(Op)));
 | 
																	  CId_, std::to_string(Op)));
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} catch (const Poco::Net::ConnectionResetException &E) {
 | 
							} catch (const Poco::Net::ConnectionResetException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
 | 
				
			||||||
				E.displayText(),
 | 
														 CId_, E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::JSON::JSONException &E) {
 | 
							} catch (const Poco::JSON::JSONException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("JSONException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
		   		CId_,
 | 
											 fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::Net::WebSocketException &E) {
 | 
							} catch (const Poco::Net::WebSocketException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
 | 
							} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(
 | 
				
			||||||
				CId_,
 | 
									Logger_,
 | 
				
			||||||
				E.displayText(),
 | 
									fmt::format(
 | 
				
			||||||
 | 
										"SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
 | 
				
			||||||
 | 
										CId_, E.displayText(),
 | 
				
			||||||
					IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
										IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
					State_.sessionId));
 | 
										State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::Net::SSLException &E) {
 | 
							} catch (const Poco::Net::SSLException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("SSLException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::Net::NetException &E) {
 | 
							} catch (const Poco::Net::NetException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("NetException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::IOException &E) {
 | 
							} catch (const Poco::IOException &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("IOException({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("Exception({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (const std::exception &E) {
 | 
							} catch (const std::exception &E) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("std::exception({}): Text:{} Payload:{} Session:{}",
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				CId_,
 | 
											 fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.what(),
 | 
														 E.what(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_error(Logger_,fmt::format("UnknownException({}): Device must be disconnected. Unknown exception.  Session:{}", CId_, State_.sessionId));
 | 
								poco_error(Logger_, fmt::format("UnknownException({}): Device must be disconnected. "
 | 
				
			||||||
 | 
																"Unknown exception.  Session:{}",
 | 
				
			||||||
 | 
																CId_, State_.sessionId));
 | 
				
			||||||
			return EndConnection();
 | 
								return EndConnection();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -743,7 +866,41 @@ namespace OpenWifi {
 | 
				
			|||||||
	bool AP_WS_Connection::Send(const std::string &Payload) {
 | 
						bool AP_WS_Connection::Send(const std::string &Payload) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			size_t BytesSent = WS_->sendFrame(Payload.c_str(), (int)Payload.size());
 | 
								size_t BytesSent = WS_->sendFrame(Payload.c_str(), (int)Payload.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * 	There is a possibility to actually try and send data but the device is no longer
 | 
				
			||||||
 | 
								 * listening. This code attempts to wait 5 seconds to see if the device is actually
 | 
				
			||||||
 | 
								 * still listening. if the data is not acked under 5 seconds, then we consider that the
 | 
				
			||||||
 | 
								 * data never made it or the device is disconnected somehow.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
					#if defined(__APPLE__)
 | 
				
			||||||
 | 
								tcp_connection_info info;
 | 
				
			||||||
 | 
								int timeout = 4000;
 | 
				
			||||||
 | 
								auto expireAt = std::chrono::system_clock::now() + std::chrono::milliseconds(timeout);
 | 
				
			||||||
 | 
								do {
 | 
				
			||||||
 | 
									std::this_thread::sleep_for(std::chrono::milliseconds(50));
 | 
				
			||||||
 | 
									socklen_t opt_len = sizeof(info);
 | 
				
			||||||
 | 
									getsockopt(WS_->impl()->sockfd(), SOL_SOCKET, TCP_CONNECTION_INFO, (void *)&info,
 | 
				
			||||||
 | 
											   &opt_len);
 | 
				
			||||||
 | 
								} while (!info.tcpi_tfo_syn_data_acked && expireAt > std::chrono::system_clock::now());
 | 
				
			||||||
 | 
								if (!info.tcpi_tfo_syn_data_acked)
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
								tcp_info info;
 | 
				
			||||||
 | 
								int timeout = 4000;
 | 
				
			||||||
 | 
								auto expireAt = std::chrono::system_clock::now() + std::chrono::milliseconds(timeout);
 | 
				
			||||||
 | 
								do {
 | 
				
			||||||
 | 
									std::this_thread::sleep_for(std::chrono::milliseconds(20));
 | 
				
			||||||
 | 
									socklen_t opt_len = sizeof(info);
 | 
				
			||||||
 | 
									getsockopt(WS_->impl()->sockfd(), SOL_TCP, TCP_INFO, (void *)&info, &opt_len);
 | 
				
			||||||
 | 
								} while (info.tcpi_unacked > 0 && expireAt > std::chrono::system_clock::now());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (info.tcpi_unacked > 0) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
			State_.TX += BytesSent;
 | 
								State_.TX += BytesSent;
 | 
				
			||||||
 | 
								AP_WS_Server()->AddTX(BytesSent);
 | 
				
			||||||
			return BytesSent == Payload.size();
 | 
								return BytesSent == Payload.size();
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
			Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
@@ -763,7 +920,8 @@ namespace OpenWifi {
 | 
				
			|||||||
		return ofs.str();
 | 
							return ofs.str();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Connection::SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size) {
 | 
						bool AP_WS_Connection::SendRadiusAuthenticationData(const unsigned char *buffer,
 | 
				
			||||||
 | 
																			std::size_t size) {
 | 
				
			||||||
		Poco::JSON::Object Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
		Answer.set(uCentralProtocol::RADIUS, uCentralProtocol::RADIUSAUTH);
 | 
							Answer.set(uCentralProtocol::RADIUS, uCentralProtocol::RADIUSAUTH);
 | 
				
			||||||
		Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer, size));
 | 
							Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer, size));
 | 
				
			||||||
@@ -799,16 +957,19 @@ namespace OpenWifi {
 | 
				
			|||||||
			if (Type == uCentralProtocol::RADIUSACCT) {
 | 
								if (Type == uCentralProtocol::RADIUSACCT) {
 | 
				
			||||||
				auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
 | 
									auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
 | 
				
			||||||
				auto DecodedData = Base64Decode(Data);
 | 
									auto DecodedData = Base64Decode(Data);
 | 
				
			||||||
				RADIUS_proxy_server()->SendAccountingData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
 | 
									RADIUS_proxy_server()->SendAccountingData(SerialNumber_, DecodedData.c_str(),
 | 
				
			||||||
 | 
																			  DecodedData.size());
 | 
				
			||||||
			} else if (Type == uCentralProtocol::RADIUSAUTH) {
 | 
								} else if (Type == uCentralProtocol::RADIUSAUTH) {
 | 
				
			||||||
				auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
 | 
									auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
 | 
				
			||||||
				auto DecodedData = Base64Decode(Data);
 | 
									auto DecodedData = Base64Decode(Data);
 | 
				
			||||||
				RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
 | 
									RADIUS_proxy_server()->SendAuthenticationData(SerialNumber_, DecodedData.c_str(),
 | 
				
			||||||
 | 
																				  DecodedData.size());
 | 
				
			||||||
			} else if (Type == uCentralProtocol::RADIUSCOA) {
 | 
								} else if (Type == uCentralProtocol::RADIUSCOA) {
 | 
				
			||||||
				auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
 | 
									auto Data = Doc->get(uCentralProtocol::RADIUSDATA).toString();
 | 
				
			||||||
				auto DecodedData = Base64Decode(Data);
 | 
									auto DecodedData = Base64Decode(Data);
 | 
				
			||||||
				RADIUS_proxy_server()->SendCoAData(SerialNumber_,DecodedData.c_str(),DecodedData.size());
 | 
									RADIUS_proxy_server()->SendCoAData(SerialNumber_, DecodedData.c_str(),
 | 
				
			||||||
			}
 | 
																	   DecodedData.size());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,38 +4,37 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <shared_mutex>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
 | 
					#include <Poco/JSON/Parser.h>
 | 
				
			||||||
 | 
					#include "Poco/Logger.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/SocketNotification.h"
 | 
				
			||||||
#include "Poco/Net/SocketReactor.h"
 | 
					#include "Poco/Net/SocketReactor.h"
 | 
				
			||||||
#include "Poco/Net/StreamSocket.h"
 | 
					#include "Poco/Net/StreamSocket.h"
 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					 | 
				
			||||||
#include "Poco/Net/SocketNotification.h"
 | 
					 | 
				
			||||||
#include "Poco/Logger.h"
 | 
					 | 
				
			||||||
#include "Poco/Net/WebSocket.h"
 | 
					#include "Poco/Net/WebSocket.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTObjects/RESTAPI_GWobjects.h"
 | 
					#include "RESTObjects/RESTAPI_GWobjects.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class AP_WS_Connection {
 | 
						class AP_WS_Connection {
 | 
				
			||||||
		static constexpr int BufSize = 256000;
 | 
							static constexpr int BufSize = 256000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
 | 
							explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
 | 
				
			||||||
									Poco::Net::HTTPServerResponse &response,
 | 
													  Poco::Net::HTTPServerResponse &response, uint64_t connection_id,
 | 
				
			||||||
									std::uint64_t connection_id,
 | 
													  Poco::Logger &L, Poco::Net::SocketReactor &R);
 | 
				
			||||||
									Poco::Logger &L,
 | 
					 | 
				
			||||||
									Poco::Net::SocketReactor &R);
 | 
					 | 
				
			||||||
		~AP_WS_Connection();
 | 
							~AP_WS_Connection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void EndConnection();
 | 
							void EndConnection(bool DeleteSession=true);
 | 
				
			||||||
		void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
 | 
							void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
 | 
				
			||||||
		void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
 | 
							void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
 | 
				
			||||||
		void ProcessIncomingFrame();
 | 
							void ProcessIncomingFrame();
 | 
				
			||||||
		void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
 | 
							void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool Send(const std::string &Payload);
 | 
							[[nodiscard]] bool Send(const std::string &Payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size);
 | 
							bool SendRadiusAuthenticationData(const unsigned char *buffer, std::size_t size);
 | 
				
			||||||
		bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size);
 | 
							bool SendRadiusAccountingData(const unsigned char *buffer, std::size_t size);
 | 
				
			||||||
@@ -44,14 +43,79 @@ namespace OpenWifi {
 | 
				
			|||||||
		void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
 | 
							void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
 | 
				
			||||||
		void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
 | 
							void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf);
 | 
				
			||||||
		void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
 | 
							void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
 | 
				
			||||||
		bool LookForUpgrade(const uint64_t UUID, uint64_t & UpgradedUUID);
 | 
							bool LookForUpgrade(uint64_t UUID, uint64_t &UpgradedUUID);
 | 
				
			||||||
		static bool ExtractBase64CompressedData(const std::string & CompressedData, std::string & UnCompressedData, uint64_t compress_sz);
 | 
							static bool ExtractBase64CompressedData(const std::string &CompressedData,
 | 
				
			||||||
 | 
																	std::string &UnCompressedData,
 | 
				
			||||||
 | 
																	uint64_t compress_sz);
 | 
				
			||||||
		void LogException(const Poco::Exception &E);
 | 
							void LogException(const Poco::Exception &E);
 | 
				
			||||||
		inline Poco::Logger &Logger() { return Logger_; }
 | 
							inline Poco::Logger &Logger() { return Logger_; }
 | 
				
			||||||
		bool SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryWebSocketTimer);
 | 
							bool SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t interval,
 | 
				
			||||||
		bool SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t interval, uint64_t TelemetryKafkaTimer);
 | 
																uint64_t TelemetryWebSocketTimer,
 | 
				
			||||||
		bool StopWebSocketTelemetry(std::uint64_t RPCID);
 | 
																const std::vector<std::string> &TelemetryTypes);
 | 
				
			||||||
		bool StopKafkaTelemetry(std::uint64_t RPCID);
 | 
							bool SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t interval,
 | 
				
			||||||
 | 
															uint64_t TelemetryKafkaTimer,
 | 
				
			||||||
 | 
															const std::vector<std::string> &TelemetryTypes);
 | 
				
			||||||
 | 
							bool StopWebSocketTelemetry(uint64_t RPCID);
 | 
				
			||||||
 | 
							bool StopKafkaTelemetry(uint64_t RPCID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void GetLastStats(std::string &LastStats) {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								LastStats = RawLastStats_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void SetLastStats(const std::string &LastStats) {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								RawLastStats_ = LastStats;
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									Poco::JSON::Parser P;
 | 
				
			||||||
 | 
									auto Stats = P.parse(LastStats).extract<Poco::JSON::Object::Ptr>();
 | 
				
			||||||
 | 
									hasGPS = Stats->isObject("gps");
 | 
				
			||||||
 | 
									auto Unit = Stats->getObject("unit");
 | 
				
			||||||
 | 
									auto Memory = Unit->getObject("memory");
 | 
				
			||||||
 | 
									std::uint64_t TotalMemory = Memory->get("total");
 | 
				
			||||||
 | 
									std::uint64_t FreeMemory = Memory->get("free");
 | 
				
			||||||
 | 
									if(TotalMemory>0) {
 | 
				
			||||||
 | 
										memory_used_ =
 | 
				
			||||||
 | 
											(100.0 * ((double)TotalMemory - (double)FreeMemory)) / (double)TotalMemory;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if(Unit->isArray("load")) {
 | 
				
			||||||
 | 
										Poco::JSON::Array::Ptr Load = Unit->getArray("load");
 | 
				
			||||||
 | 
										if(Load->size()>1) {
 | 
				
			||||||
 | 
											cpu_load_ = Load->get(1);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if(Unit->isArray("temperature")) {
 | 
				
			||||||
 | 
										Poco::JSON::Array::Ptr Temperature = Unit->getArray("temperature");
 | 
				
			||||||
 | 
										if(Temperature->size()>1) {
 | 
				
			||||||
 | 
											temperature_ = Temperature->get(0);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								RawLastHealthcheck_ = H;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void GetLastHealthCheck(GWObjects::HealthCheck &H) {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								H = RawLastHealthcheck_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void GetState(GWObjects::ConnectionState &State) const {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								State = State_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool HasGPS() { return hasGPS; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void GetRestrictions(GWObjects::DeviceRestrictions &R) const {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								R = Restrictions_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
 | 
							void Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial);
 | 
				
			||||||
		void Process_state(Poco::JSON::Object::Ptr ParamsObj);
 | 
							void Process_state(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
@@ -64,6 +128,10 @@ namespace OpenWifi {
 | 
				
			|||||||
		void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
 | 
							void Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial);
 | 
				
			||||||
		void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
 | 
							void Process_telemetry(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
		void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
 | 
							void Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
 | 
							void Process_event(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
 | 
							void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
 | 
							void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
 | 
							void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool ValidatedDevice();
 | 
							bool ValidatedDevice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,12 +151,18 @@ namespace OpenWifi {
 | 
				
			|||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		friend class DeviceRegistry;
 | 
					 | 
				
			||||||
		friend class AP_WS_Server;
 | 
							friend class AP_WS_Server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline GWObjects::DeviceRestrictions Restrictions() const {
 | 
				
			||||||
 | 
								std::lock_guard G(ConnectionMutex_);
 | 
				
			||||||
 | 
								return Restrictions_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool MustBeSecureRtty() const { return RttyMustBeSecure_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		// std::recursive_mutex 				LocalMutex_;
 | 
							mutable std::mutex ConnectionMutex_;
 | 
				
			||||||
		std::shared_mutex					TelemetryMutex_;
 | 
							std::mutex TelemetryMutex_;
 | 
				
			||||||
		Poco::Logger &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
		Poco::Net::SocketReactor &Reactor_;
 | 
							Poco::Net::SocketReactor &Reactor_;
 | 
				
			||||||
		std::unique_ptr<Poco::Net::WebSocket> WS_;
 | 
							std::unique_ptr<Poco::Net::WebSocket> WS_;
 | 
				
			||||||
@@ -100,29 +174,35 @@ namespace OpenWifi {
 | 
				
			|||||||
		std::string CN_;
 | 
							std::string CN_;
 | 
				
			||||||
		uint64_t Errors_ = 0;
 | 
							uint64_t Errors_ = 0;
 | 
				
			||||||
		Poco::Net::IPAddress PeerAddress_;
 | 
							Poco::Net::IPAddress PeerAddress_;
 | 
				
			||||||
		std::atomic_bool 					TelemetryReporting_ = false;
 | 
							volatile bool TelemetryReporting_ = false;
 | 
				
			||||||
		std::atomic_uint64_t				TelemetryWebSocketRefCount_ = 0;
 | 
							volatile uint64_t TelemetryWebSocketRefCount_ = 0;
 | 
				
			||||||
		std::atomic_uint64_t				TelemetryKafkaRefCount_ = 0;
 | 
							volatile uint64_t TelemetryKafkaRefCount_ = 0;
 | 
				
			||||||
		uint64_t 							TelemetryWebSocketTimer_ = 0;
 | 
							volatile uint64_t TelemetryWebSocketTimer_ = 0;
 | 
				
			||||||
		uint64_t 							TelemetryKafkaTimer_ = 0 ;
 | 
							volatile uint64_t TelemetryKafkaTimer_ = 0;
 | 
				
			||||||
		uint64_t 							TelemetryInterval_ = 0;
 | 
							volatile uint64_t TelemetryInterval_ = 0;
 | 
				
			||||||
		std::atomic_uint64_t				TelemetryWebSocketPackets_=0;
 | 
							volatile uint64_t TelemetryWebSocketPackets_ = 0;
 | 
				
			||||||
		std::atomic_uint64_t				TelemetryKafkaPackets_=0;
 | 
							volatile uint64_t TelemetryKafkaPackets_ = 0;
 | 
				
			||||||
		GWObjects::ConnectionState State_;
 | 
							GWObjects::ConnectionState State_;
 | 
				
			||||||
		std::string        					LastStats_;
 | 
							std::string RawLastStats_;
 | 
				
			||||||
		GWObjects::HealthCheck				LastHealthcheck_;
 | 
							GWObjects::HealthCheck RawLastHealthcheck_;
 | 
				
			||||||
		std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ = std::chrono::high_resolution_clock::now();
 | 
							std::chrono::time_point<std::chrono::high_resolution_clock> ConnectionStart_ =
 | 
				
			||||||
 | 
								std::chrono::high_resolution_clock::now();
 | 
				
			||||||
		std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
 | 
							std::chrono::duration<double, std::milli> ConnectionCompletionTime_{0.0};
 | 
				
			||||||
		bool 								Threaded_=false;
 | 
					 | 
				
			||||||
		std::atomic_flag Dead_ = false;
 | 
							std::atomic_flag Dead_ = false;
 | 
				
			||||||
		std::atomic_bool DeviceValidated_ = false;
 | 
							std::atomic_bool DeviceValidated_ = false;
 | 
				
			||||||
		std::atomic_bool Valid_ = false;
 | 
							std::atomic_bool Valid_ = false;
 | 
				
			||||||
 | 
							OpenWifi::GWObjects::DeviceRestrictions Restrictions_;
 | 
				
			||||||
 | 
							bool 			RttyMustBeSecure_ = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
 | 
							static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool StartTelemetry(std::uint64_t RPCID);
 | 
							bool StartTelemetry(uint64_t RPCID, const std::vector<std::string> &TelemetryTypes);
 | 
				
			||||||
		bool StopTelemetry(std::uint64_t RPCID);
 | 
							bool StopTelemetry(uint64_t RPCID);
 | 
				
			||||||
		void UpdateCounts();
 | 
							void UpdateCounts();
 | 
				
			||||||
 | 
							bool hasGPS=false;
 | 
				
			||||||
 | 
							std::double_t 	memory_used_=0.0, cpu_load_ = 0.0, temperature_ = 0.0;
 | 
				
			||||||
 | 
							std::uint64_t 	uuid_=0;
 | 
				
			||||||
 | 
							bool	Simulated_=false;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/AP_WS_Process_alarm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/AP_WS_Process_alarm.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-01-22.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
						void AP_WS_Connection::Process_alarm(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
 | 
							if (!State_.Connected) {
 | 
				
			||||||
 | 
								poco_warning(Logger_,
 | 
				
			||||||
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
 | 
								Errors_++;
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							poco_trace(Logger_, fmt::format("Alarm data received for {}", SerialNumber_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
 | 
				
			||||||
 | 
								if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
									KafkaManager()->PostMessage(KafkaTopics::ALERTS, SerialNumber_, *ParamsObj);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -9,8 +9,9 @@
 | 
				
			|||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_cfgpending(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (!State_.Connected) {
 | 
							if (!State_.Connected) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format(
 | 
								poco_warning(Logger_,
 | 
				
			||||||
									   "INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -18,9 +19,10 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
 | 
								[[maybe_unused]] uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
 | 
				
			||||||
			[[maybe_unused]] uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
 | 
								[[maybe_unused]] uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
 | 
				
			||||||
			poco_trace(Logger_, fmt::format("CFG-PENDING({}): Active: {} Target: {}", CId_, Active, UUID));
 | 
								poco_trace(Logger_,
 | 
				
			||||||
 | 
										   fmt::format("CFG-PENDING({}): Active: {} Target: {}", CId_, Active, UUID));
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("CFG-PENDING({}): Missing some parameters", CId_));
 | 
								poco_warning(Logger_, fmt::format("CFG-PENDING({}): Missing some parameters", CId_));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,26 +4,67 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					#include "AP_WS_Server.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "FindCountry.h"
 | 
					 | 
				
			||||||
#include "framework/WebSocketClientNotifications.h"
 | 
					 | 
				
			||||||
#include "Daemon.h"
 | 
					 | 
				
			||||||
#include "CentralConfig.h"
 | 
					#include "CentralConfig.h"
 | 
				
			||||||
 | 
					#include "Daemon.h"
 | 
				
			||||||
 | 
					#include "FindCountry.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "CommandManager.h"
 | 
					#include "CommandManager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "firmware_revision_cache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "UI_GW_WebSocketNotifications.h"
 | 
				
			||||||
 | 
					#include <GWKafkaEvents.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj, const std::string &Serial) {
 | 
						[[maybe_unused]] static void SendKafkaFirmwareUpdate(const std::string &SerialNumber,
 | 
				
			||||||
	if (ParamsObj->has(uCentralProtocol::UUID) &&
 | 
																			 const std::string &OldFirmware,
 | 
				
			||||||
		ParamsObj->has(uCentralProtocol::FIRMWARE) &&
 | 
																			 const std::string &NewFirmware) {
 | 
				
			||||||
 | 
							if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
								Poco::JSON::Object EventDetails;
 | 
				
			||||||
 | 
								EventDetails.set("oldFirmware", OldFirmware);
 | 
				
			||||||
 | 
								EventDetails.set("newFirmware", NewFirmware);
 | 
				
			||||||
 | 
								Poco::JSON::Object Event;
 | 
				
			||||||
 | 
								Event.set("type", "device.firmware_change");
 | 
				
			||||||
 | 
								Event.set("timestamp", Utils::Now());
 | 
				
			||||||
 | 
								Event.set("payload", EventDetails);
 | 
				
			||||||
 | 
								KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, Event);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[maybe_unused]] static void SendKafkaDeviceNotProvisioned(	const std::string &SerialNumber,
 | 
				
			||||||
 | 
																			 		const std::string &Firmware,
 | 
				
			||||||
 | 
																				   	const std::string &DeviceType,
 | 
				
			||||||
 | 
																				   	const std::string &IP) {
 | 
				
			||||||
 | 
							if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
								Poco::JSON::Object EventDetails;
 | 
				
			||||||
 | 
								EventDetails.set("firmware", Firmware);
 | 
				
			||||||
 | 
								EventDetails.set("deviceType", DeviceType);
 | 
				
			||||||
 | 
								EventDetails.set("IP", IP);
 | 
				
			||||||
 | 
								Poco::JSON::Object Event;
 | 
				
			||||||
 | 
								Event.set("type", "device.not_provisioned");
 | 
				
			||||||
 | 
								Event.set("timestamp", Utils::Now());
 | 
				
			||||||
 | 
								Event.set("payload", EventDetails);
 | 
				
			||||||
 | 
								KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber, Event);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj,
 | 
				
			||||||
 | 
															   const std::string &Serial) {
 | 
				
			||||||
 | 
							if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::FIRMWARE) &&
 | 
				
			||||||
			ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
 | 
								ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
 | 
				
			||||||
			uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
 | 
								uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
 | 
				
			||||||
			auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
 | 
								auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
 | 
				
			||||||
		auto CapabilitiesString = ParamsObj->get(uCentralProtocol::CAPABILITIES).toString();
 | 
								auto Capabilities = ParamsObj->getObject(uCentralProtocol::CAPABILITIES);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Config::Capabilities Caps(CapabilitiesString);
 | 
								std::string DevicePassword;
 | 
				
			||||||
		Compatible_ = Caps.Compatible();
 | 
								if(ParamsObj->has("password")) {
 | 
				
			||||||
 | 
									DevicePassword = ParamsObj->get("password").toString();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			SerialNumber_ = Serial;
 | 
								SerialNumber_ = Serial;
 | 
				
			||||||
			SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
 | 
								SerialNumberInt_ = Utils::SerialNumberToInt(SerialNumber_);
 | 
				
			||||||
@@ -31,99 +72,241 @@ void AP_WS_Connection::Process_connect(Poco::JSON::Object::Ptr ParamsObj, const
 | 
				
			|||||||
			CommandManager()->ClearQueue(SerialNumberInt_);
 | 
								CommandManager()->ClearQueue(SerialNumberInt_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			AP_WS_Server()->SetSessionDetails(State_.sessionId, SerialNumberInt_);
 | 
								AP_WS_Server()->SetSessionDetails(State_.sessionId, SerialNumberInt_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::lock_guard Lock(ConnectionMutex_);
 | 
				
			||||||
 | 
								Config::Capabilities Caps(Capabilities);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Compatible_ = Caps.Compatible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			State_.UUID = UUID;
 | 
								State_.UUID = UUID;
 | 
				
			||||||
			State_.Firmware = Firmware;
 | 
								State_.Firmware = Firmware;
 | 
				
			||||||
			State_.PendingUUID = 0;
 | 
								State_.PendingUUID = 0;
 | 
				
			||||||
			State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
 | 
								State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
 | 
				
			||||||
			CId_ = SerialNumber_ + "@" + CId_;
 | 
								CId_ = SerialNumber_ + "@" + CId_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(ParamsObj->has("reason")) {
 | 
				
			||||||
 | 
									State_.connectReason = ParamsObj->get("reason").toString();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto IP = PeerAddress_.toString();
 | 
								auto IP = PeerAddress_.toString();
 | 
				
			||||||
			if (IP.substr(0, 7) == "::ffff:") {
 | 
								if (IP.substr(0, 7) == "::ffff:") {
 | 
				
			||||||
				IP = IP.substr(7);
 | 
									IP = IP.substr(7);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bool RestrictedDevice = false;
 | 
				
			||||||
 | 
								if (Capabilities->has("restrictions")) {
 | 
				
			||||||
 | 
									RestrictedDevice = true;
 | 
				
			||||||
 | 
									Poco::JSON::Object::Ptr RestrictionObject = Capabilities->getObject("restrictions");
 | 
				
			||||||
 | 
									Restrictions_.from_json(RestrictionObject);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (Capabilities->has("developer")) {
 | 
				
			||||||
 | 
									Restrictions_.developer = Capabilities->getValue<bool>("developer");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(Capabilities->has("secure-rtty")) {
 | 
				
			||||||
 | 
									RttyMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			State_.locale = FindCountryFromIP()->Get(IP);
 | 
								State_.locale = FindCountryFromIP()->Get(IP);
 | 
				
			||||||
			GWObjects::Device DeviceInfo;
 | 
								GWObjects::Device DeviceInfo;
 | 
				
			||||||
			auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
 | 
								auto DeviceExists = StorageService()->GetDevice(SerialNumber_, DeviceInfo);
 | 
				
			||||||
			if (Daemon()->AutoProvisioning() && !DeviceExists) {
 | 
								if (Daemon()->AutoProvisioning() && !DeviceExists) {
 | 
				
			||||||
			StorageService()->CreateDefaultDevice(SerialNumber_, CapabilitiesString, Firmware,
 | 
									//	check the firmware version. if this is too old, we cannot let that device connect yet, we must
 | 
				
			||||||
												  Compatible_, PeerAddress_);
 | 
									//	force a firmware upgrade
 | 
				
			||||||
 | 
									GWObjects::DefaultFirmware	MinimumFirmware;
 | 
				
			||||||
 | 
									if(FirmwareRevisionCache()->DeviceMustUpgrade(Compatible_, Firmware, MinimumFirmware)) {
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										{    "jsonrpc" : "2.0" ,
 | 
				
			||||||
 | 
											 "method" : "upgrade" ,
 | 
				
			||||||
 | 
											 "params" : {
 | 
				
			||||||
 | 
													"serial" : <serial number> ,
 | 
				
			||||||
 | 
													"when"  : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
 | 
				
			||||||
 | 
													"uri"   : <URI to download the firmware>,
 | 
				
			||||||
 | 
													"FWsignature" : <string representation of the signature for the FW> (optional)
 | 
				
			||||||
 | 
											 },
 | 
				
			||||||
 | 
											 "id" : <some number>
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
										Poco::JSON::Object	UpgradeCommand, Params;
 | 
				
			||||||
 | 
										UpgradeCommand.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION);
 | 
				
			||||||
 | 
										UpgradeCommand.set(uCentralProtocol::METHOD,uCentralProtocol::UPGRADE);
 | 
				
			||||||
 | 
										Params.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
 | 
				
			||||||
 | 
										Params.set(uCentralProtocol::WHEN, 0);
 | 
				
			||||||
 | 
										Params.set(uCentralProtocol::URI, MinimumFirmware.uri);
 | 
				
			||||||
 | 
										Params.set(uCentralProtocol::KEEP_REDIRECTOR,1);
 | 
				
			||||||
 | 
										UpgradeCommand.set(uCentralProtocol::PARAMS, Params);
 | 
				
			||||||
 | 
										UpgradeCommand.set(uCentralProtocol::ID, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										std::ostringstream Command;
 | 
				
			||||||
 | 
										UpgradeCommand.stringify(Command);
 | 
				
			||||||
 | 
										if(Send(Command.str())) {
 | 
				
			||||||
 | 
											poco_information(
 | 
				
			||||||
 | 
												Logger(),
 | 
				
			||||||
 | 
												fmt::format(
 | 
				
			||||||
 | 
													"Forcing device {} to upgrade to {} before connection is allowed.",
 | 
				
			||||||
 | 
													SerialNumber_, MinimumFirmware.revision));
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											poco_error(
 | 
				
			||||||
 | 
												Logger(),
 | 
				
			||||||
 | 
												fmt::format(
 | 
				
			||||||
 | 
													"Could not force device {} to upgrade to {} before connection is allowed.",
 | 
				
			||||||
 | 
													SerialNumber_, MinimumFirmware.revision));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										StorageService()->CreateDefaultDevice(
 | 
				
			||||||
 | 
											SerialNumber_, Caps, Firmware, PeerAddress_,
 | 
				
			||||||
 | 
											State_.VerifiedCertificate == GWObjects::SIMULATED);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else if (!Daemon()->AutoProvisioning() && !DeviceExists) {
 | 
				
			||||||
 | 
									SendKafkaDeviceNotProvisioned(SerialNumber_, Firmware, Compatible_, CId_);
 | 
				
			||||||
 | 
									poco_warning(Logger(),fmt::format("Device {} is a {} from {} and cannot be provisioned.",SerialNumber_,Compatible_, CId_));
 | 
				
			||||||
 | 
									return EndConnection();
 | 
				
			||||||
			} else if (DeviceExists) {
 | 
								} else if (DeviceExists) {
 | 
				
			||||||
			StorageService()->UpdateDeviceCapabilities(SerialNumber_, CapabilitiesString,
 | 
									StorageService()->UpdateDeviceCapabilities(SerialNumber_, Caps);
 | 
				
			||||||
													   Compatible_);
 | 
									int Updated{0};
 | 
				
			||||||
			bool Updated = false;
 | 
									if (!Firmware.empty()) {
 | 
				
			||||||
			if(!Firmware.empty() && Firmware!=DeviceInfo.Firmware) {
 | 
										if (Firmware != DeviceInfo.Firmware) {
 | 
				
			||||||
 | 
											DeviceFirmwareChangeKafkaEvent KEvent(SerialNumberInt_, Utils::Now(),
 | 
				
			||||||
 | 
																				  DeviceInfo.Firmware, Firmware);
 | 
				
			||||||
						DeviceInfo.Firmware = Firmware;
 | 
											DeviceInfo.Firmware = Firmware;
 | 
				
			||||||
				Updated = true;
 | 
											DeviceInfo.LastFWUpdate = Utils::Now();
 | 
				
			||||||
				WebSocketClientNotificationDeviceFirmwareUpdated(SerialNumber_, Firmware);
 | 
											++Updated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											GWWebSocketNotifications::SingleDeviceFirmwareChange_t Notification;
 | 
				
			||||||
 | 
											Notification.content.serialNumber = SerialNumber_;
 | 
				
			||||||
 | 
											Notification.content.newFirmware = Firmware;
 | 
				
			||||||
 | 
											GWWebSocketNotifications::DeviceFirmwareUpdated(Notification);
 | 
				
			||||||
 | 
										} else if (DeviceInfo.LastFWUpdate == 0) {
 | 
				
			||||||
 | 
											DeviceInfo.LastFWUpdate = Utils::Now();
 | 
				
			||||||
 | 
											++Updated;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(ParamsObj->has("reason")) {
 | 
				
			||||||
 | 
										State_.connectReason = ParamsObj->get("reason").toString();
 | 
				
			||||||
 | 
										DeviceInfo.connectReason = State_.connectReason;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(DeviceInfo.DevicePassword!=DevicePassword) {
 | 
				
			||||||
 | 
										DeviceInfo.DevicePassword = DevicePassword.empty() ? "openwifi" : DevicePassword ;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (DeviceInfo.lastRecordedContact==0) {
 | 
				
			||||||
 | 
										DeviceInfo.lastRecordedContact = Utils::Now();
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (DeviceInfo.simulated && (State_.VerifiedCertificate!=GWObjects::SIMULATED)) {
 | 
				
			||||||
 | 
										DeviceInfo.simulated = false;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!DeviceInfo.simulated && (State_.VerifiedCertificate==GWObjects::SIMULATED)) {
 | 
				
			||||||
 | 
										DeviceInfo.simulated = true;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (DeviceInfo.locale != State_.locale) {
 | 
									if (DeviceInfo.locale != State_.locale) {
 | 
				
			||||||
					DeviceInfo.locale = State_.locale;
 | 
										DeviceInfo.locale = State_.locale;
 | 
				
			||||||
				Updated = true;
 | 
										++Updated;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (Compatible_ != DeviceInfo.DeviceType) {
 | 
									if (Compatible_ != DeviceInfo.DeviceType) {
 | 
				
			||||||
					DeviceInfo.DeviceType = Compatible_;
 | 
										DeviceInfo.DeviceType = Compatible_;
 | 
				
			||||||
				Updated = true;
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (RestrictedDevice != DeviceInfo.restrictedDevice) {
 | 
				
			||||||
 | 
										DeviceInfo.restrictedDevice = RestrictedDevice;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (Restrictions_ != DeviceInfo.restrictionDetails) {
 | 
				
			||||||
 | 
										DeviceInfo.restrictionDetails = Restrictions_;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(DeviceInfo.certificateExpiryDate!=State_.certificateExpiryDate) {
 | 
				
			||||||
 | 
										DeviceInfo.certificateExpiryDate = State_.certificateExpiryDate;
 | 
				
			||||||
 | 
										++Updated;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (Updated) {
 | 
									if (Updated) {
 | 
				
			||||||
					StorageService()->UpdateDevice(DeviceInfo);
 | 
										StorageService()->UpdateDevice(DeviceInfo);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(!Simulated_) {
 | 
				
			||||||
					uint64_t UpgradedUUID = 0;
 | 
										uint64_t UpgradedUUID = 0;
 | 
				
			||||||
					LookForUpgrade(UUID, UpgradedUUID);
 | 
										LookForUpgrade(UUID, UpgradedUUID);
 | 
				
			||||||
					State_.UUID = UpgradedUUID;
 | 
										State_.UUID = UpgradedUUID;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			State_.Compatible = Compatible_;
 | 
								State_.Compatible = Compatible_;
 | 
				
			||||||
			State_.Connected = true;
 | 
								State_.Connected = true;
 | 
				
			||||||
		ConnectionCompletionTime_ = std::chrono::high_resolution_clock::now() - ConnectionStart_;
 | 
								ConnectionCompletionTime_ =
 | 
				
			||||||
 | 
									std::chrono::high_resolution_clock::now() - ConnectionStart_;
 | 
				
			||||||
			State_.connectionCompletionTime = ConnectionCompletionTime_.count();
 | 
								State_.connectionCompletionTime = ConnectionCompletionTime_.count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (State_.VerifiedCertificate == GWObjects::VALID_CERTIFICATE) {
 | 
								if (State_.VerifiedCertificate == GWObjects::VALID_CERTIFICATE) {
 | 
				
			||||||
			if ((	Utils::SerialNumberMatch(CN_, SerialNumber_, AP_WS_Server()->MismatchDepth())) ||
 | 
									if ((Utils::SerialNumberMatch(CN_, SerialNumber_,
 | 
				
			||||||
 | 
																  (int)AP_WS_Server()->MismatchDepth())) ||
 | 
				
			||||||
					AP_WS_Server()->IsSimSerialNumber(CN_)) {
 | 
										AP_WS_Server()->IsSimSerialNumber(CN_)) {
 | 
				
			||||||
					State_.VerifiedCertificate = GWObjects::VERIFIED;
 | 
										State_.VerifiedCertificate = GWObjects::VERIFIED;
 | 
				
			||||||
				poco_information(Logger_, fmt::format("CONNECT({}): Fully validated and authenticated device. Session={} ConnectionCompletion Time={}",
 | 
										poco_information(Logger_,
 | 
				
			||||||
													   CId_,
 | 
														 fmt::format("CONNECT({}): Fully validated and authenticated "
 | 
				
			||||||
													   State_.sessionId,
 | 
																	 "device. Session={} ConnectionCompletion Time={}",
 | 
				
			||||||
 | 
																	 CId_, State_.sessionId,
 | 
				
			||||||
												 State_.connectionCompletionTime));
 | 
																	 State_.connectionCompletionTime));
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					State_.VerifiedCertificate = GWObjects::MISMATCH_SERIAL;
 | 
										State_.VerifiedCertificate = GWObjects::MISMATCH_SERIAL;
 | 
				
			||||||
					if (AP_WS_Server()->AllowSerialNumberMismatch()) {
 | 
										if (AP_WS_Server()->AllowSerialNumberMismatch()) {
 | 
				
			||||||
						poco_information(
 | 
											poco_information(
 | 
				
			||||||
						Logger_, fmt::format("CONNECT({}): Serial number mismatch allowed. CN={} Serial={} Session={} ConnectionCompletion Time={}",
 | 
												Logger_,
 | 
				
			||||||
 | 
												fmt::format("CONNECT({}): Serial number mismatch allowed. CN={} "
 | 
				
			||||||
 | 
															"Serial={} Session={} ConnectionCompletion Time={}",
 | 
				
			||||||
										CId_, CN_, SerialNumber_, State_.sessionId,
 | 
															CId_, CN_, SerialNumber_, State_.sessionId,
 | 
				
			||||||
										State_.connectionCompletionTime));
 | 
															State_.connectionCompletionTime));
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						poco_information(
 | 
											poco_information(
 | 
				
			||||||
						Logger_, fmt::format("CONNECT({}): Serial number mismatch disallowed. Device rejected. CN={} Serial={} Session={} ConnectionCompletion Time={}",
 | 
												Logger_, fmt::format("CONNECT({}): Serial number mismatch disallowed. "
 | 
				
			||||||
											 CId_, CN_, SerialNumber_, State_.sessionId,
 | 
																	 "Device rejected. CN={} Serial={} Session={}",
 | 
				
			||||||
											 State_.connectionCompletionTime));
 | 
																	 CId_, CN_, SerialNumber_, State_.sessionId));
 | 
				
			||||||
						return EndConnection();
 | 
											return EndConnection();
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									poco_information(Logger_,
 | 
				
			||||||
 | 
													 fmt::format("CONNECT({}): Simulator device. "
 | 
				
			||||||
 | 
																 "Session={} ConnectionCompletion Time={}",
 | 
				
			||||||
 | 
																 CId_, State_.sessionId,
 | 
				
			||||||
 | 
																 State_.connectionCompletionTime));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		WebSocketClientNotificationDeviceConnected(SerialNumber_);
 | 
								GWWebSocketNotifications::SingleDevice_t Notification;
 | 
				
			||||||
 | 
								Notification.content.serialNumber = SerialNumber_;
 | 
				
			||||||
		// std::cout << "Serial: " << SerialNumber_ << "Session: " << State_.sessionId << std::endl;
 | 
								GWWebSocketNotifications::DeviceConnected(Notification);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (KafkaManager()->Enabled()) {
 | 
								if (KafkaManager()->Enabled()) {
 | 
				
			||||||
			Poco::JSON::Stringifier Stringify;
 | 
					 | 
				
			||||||
				ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
 | 
									ParamsObj->set(uCentralProtocol::CONNECTIONIP, CId_);
 | 
				
			||||||
				ParamsObj->set("locale", State_.locale);
 | 
									ParamsObj->set("locale", State_.locale);
 | 
				
			||||||
			ParamsObj->set(uCentralProtocol::TIMESTAMP, OpenWifi::Now());
 | 
									ParamsObj->set(uCentralProtocol::TIMESTAMP, Utils::Now());
 | 
				
			||||||
			std::ostringstream OS;
 | 
									ParamsObj->set(uCentralProtocol::UUID, uuid_);
 | 
				
			||||||
			Stringify.condense(ParamsObj, OS);
 | 
									KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, *ParamsObj);
 | 
				
			||||||
			KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
		poco_warning(Logger_,fmt::format("INVALID-PROTOCOL({}): Missing one of uuid, firmware, or capabilities", CId_));
 | 
								poco_warning(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("INVALID-PROTOCOL({}): Missing one of uuid, firmware, or capabilities",
 | 
				
			||||||
 | 
												CId_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -5,9 +5,14 @@
 | 
				
			|||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					#include <GWKafkaEvents.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_crashlog(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
 | 
							if (ParamsObj->has(uCentralProtocol::UUID)
 | 
				
			||||||
 | 
								&& ParamsObj->has(uCentralProtocol::LOGLINES)) {
 | 
				
			||||||
			poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
 | 
								poco_trace(Logger_, fmt::format("CRASH-LOG({}): new entry.", CId_));
 | 
				
			||||||
			auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
 | 
								auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
 | 
				
			||||||
			std::string LogText;
 | 
								std::string LogText;
 | 
				
			||||||
@@ -21,14 +26,14 @@ namespace OpenWifi {
 | 
				
			|||||||
										   .Log = LogText,
 | 
															   .Log = LogText,
 | 
				
			||||||
										   .Data = "",
 | 
															   .Data = "",
 | 
				
			||||||
										   .Severity = GWObjects::DeviceLog::LOG_EMERG,
 | 
															   .Severity = GWObjects::DeviceLog::LOG_EMERG,
 | 
				
			||||||
										   .Recorded = (uint64_t)time(nullptr),
 | 
															   .Recorded = Utils::Now(),
 | 
				
			||||||
										   .LogType = 1,
 | 
															   .LogType = 1,
 | 
				
			||||||
										   .UUID = 0};
 | 
															   .UUID = ParamsObj->get(uCentralProtocol::UUID)};
 | 
				
			||||||
			StorageService()->AddLog(DeviceLog);
 | 
								StorageService()->AddLog(DeviceLog);
 | 
				
			||||||
 | 
								DeviceLogKafkaEvent	E(DeviceLog);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
 | 
								poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -5,12 +5,16 @@
 | 
				
			|||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj, std::string &Serial) {
 | 
						void AP_WS_Connection::Process_deviceupdate(Poco::JSON::Object::Ptr ParamsObj,
 | 
				
			||||||
 | 
																	std::string &Serial) {
 | 
				
			||||||
		if (!State_.Connected) {
 | 
							if (!State_.Connected) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format(
 | 
								poco_warning(Logger_,
 | 
				
			||||||
									   "INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -18,8 +22,10 @@ namespace OpenWifi {
 | 
				
			|||||||
			auto Password = ParamsObj->get("currentPassword").toString();
 | 
								auto Password = ParamsObj->get("currentPassword").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			StorageService()->SetDevicePassword(Serial, Password);
 | 
								StorageService()->SetDevicePassword(Serial, Password);
 | 
				
			||||||
			poco_trace(Logger_, fmt::format("DEVICEUPDATE({}): Device is updating its login password.", Serial));
 | 
								poco_trace(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("DEVICE-UPDATE({}): Device is updating its login password.", Serial));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/AP_WS_Process_event.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/AP_WS_Process_event.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-01-22.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
						void AP_WS_Connection::Process_event(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
 | 
							if (!State_.Connected) {
 | 
				
			||||||
 | 
								poco_warning(Logger_,
 | 
				
			||||||
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
 | 
								Errors_++;
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							poco_trace(Logger_, fmt::format("Event data received for {}", SerialNumber_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								if (ParamsObj->has(uCentralProtocol::SERIAL) &&
 | 
				
			||||||
 | 
									ParamsObj->has(uCentralProtocol::DATA)) {
 | 
				
			||||||
 | 
									if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
										auto Data = ParamsObj->getObject(uCentralProtocol::DATA);
 | 
				
			||||||
 | 
										auto Event = Data->getArray("event");
 | 
				
			||||||
 | 
										auto EventTimeStamp = Event->getElement<std::uint64_t>(0);
 | 
				
			||||||
 | 
										auto EventDetails = Event->getObject(1);
 | 
				
			||||||
 | 
										auto EventType = EventDetails->get("type").extract<std::string>();
 | 
				
			||||||
 | 
										auto EventPayload = EventDetails->getObject("payload");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Poco::JSON::Object FullEvent;
 | 
				
			||||||
 | 
										FullEvent.set("type", EventType);
 | 
				
			||||||
 | 
										FullEvent.set("timestamp", EventTimeStamp);
 | 
				
			||||||
 | 
										FullEvent.set("payload", EventPayload);
 | 
				
			||||||
 | 
										if(strncmp(EventType.c_str(),"rrm.",4) == 0 ) {
 | 
				
			||||||
 | 
											KafkaManager()->PostMessage(KafkaTopics::RRM, SerialNumber_,
 | 
				
			||||||
 | 
																		FullEvent);
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, SerialNumber_,
 | 
				
			||||||
 | 
																		FullEvent);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
 | 
								Logger_.log(E);
 | 
				
			||||||
 | 
							} catch (...) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -5,17 +5,24 @@
 | 
				
			|||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (!State_.Connected) {
 | 
							if (!State_.Connected) {
 | 
				
			||||||
		poco_warning(Logger_, fmt::format(
 | 
								poco_warning(Logger_,
 | 
				
			||||||
								   "INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) &&
 | 
							if (ParamsObj->has(uCentralProtocol::UUID) &&
 | 
				
			||||||
 | 
								ParamsObj->has(uCentralProtocol::SANITY) &&
 | 
				
			||||||
			ParamsObj->has(uCentralProtocol::DATA)) {
 | 
								ParamsObj->has(uCentralProtocol::DATA)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
 | 
								uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
 | 
				
			||||||
			auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
 | 
								auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
 | 
				
			||||||
			auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
 | 
								auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
 | 
				
			||||||
@@ -27,22 +34,16 @@ void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			|||||||
				request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
 | 
									request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (request_uuid.empty()) {
 | 
								if (request_uuid.empty()) {
 | 
				
			||||||
			poco_trace(Logger_,
 | 
									poco_trace(Logger_, fmt::format("HEALTHCHECK({}): UUID={} Updating.", CId_, UUID));
 | 
				
			||||||
					   fmt::format("HEALTHCHECK({}): UUID={} Updating.", CId_, UUID));
 | 
					 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
			poco_trace(Logger_,
 | 
									poco_trace(Logger_, fmt::format("HEALTHCHECK({}): UUID={} Updating for CMD={}.",
 | 
				
			||||||
					   fmt::format("HEALTHCHECK({}): UUID={} Updating for CMD={}.", CId_,
 | 
																	CId_, UUID, request_uuid));
 | 
				
			||||||
								   UUID, request_uuid));
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint64_t UpgradedUUID;
 | 
					 | 
				
			||||||
		LookForUpgrade(UUID,UpgradedUUID);
 | 
					 | 
				
			||||||
		State_.UUID = UpgradedUUID;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			GWObjects::HealthCheck Check;
 | 
								GWObjects::HealthCheck Check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Check.SerialNumber = SerialNumber_;
 | 
								Check.SerialNumber = SerialNumber_;
 | 
				
			||||||
		Check.Recorded = OpenWifi::Now();
 | 
								Check.Recorded = Utils::Now();
 | 
				
			||||||
			Check.UUID = UUID;
 | 
								Check.UUID = UUID;
 | 
				
			||||||
			Check.Data = CheckData;
 | 
								Check.Data = CheckData;
 | 
				
			||||||
			Check.Sanity = Sanity;
 | 
								Check.Sanity = Sanity;
 | 
				
			||||||
@@ -53,13 +54,9 @@ void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			|||||||
				StorageService()->SetCommandResult(request_uuid, CheckData);
 | 
									StorageService()->SetCommandResult(request_uuid, CheckData);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LastHealthcheck_ = Check;
 | 
								SetLastHealthCheck(Check);
 | 
				
			||||||
			if (KafkaManager()->Enabled()) {
 | 
								if (KafkaManager()->Enabled()) {
 | 
				
			||||||
			Poco::JSON::Stringifier Stringify;
 | 
									KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, *ParamsObj);
 | 
				
			||||||
			std::ostringstream OS;
 | 
					 | 
				
			||||||
			ParamsObj->set("timestamp", OpenWifi::Now());
 | 
					 | 
				
			||||||
			Stringify.condense(ParamsObj, OS);
 | 
					 | 
				
			||||||
			KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
 | 
								poco_warning(Logger_, fmt::format("HEALTHCHECK({}): Missing parameter", CId_));
 | 
				
			||||||
@@ -67,5 +64,4 @@ void AP_WS_Connection::Process_healthcheck(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -5,12 +5,16 @@
 | 
				
			|||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					#include <GWKafkaEvents.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_log(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (!State_.Connected) {
 | 
							if (!State_.Connected) {
 | 
				
			||||||
			poco_warning(
 | 
								poco_warning(Logger_,
 | 
				
			||||||
				Logger_,
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
				fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
 | 
														 CId_, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -33,9 +37,10 @@ namespace OpenWifi {
 | 
				
			|||||||
										   .LogType = 0,
 | 
															   .LogType = 0,
 | 
				
			||||||
										   .UUID = State_.UUID};
 | 
															   .UUID = State_.UUID};
 | 
				
			||||||
			StorageService()->AddLog(DeviceLog);
 | 
								StorageService()->AddLog(DeviceLog);
 | 
				
			||||||
 | 
								DeviceLogKafkaEvent	E(DeviceLog);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
 | 
								poco_warning(Logger_, fmt::format("LOG({}): Missing parameters.", CId_));
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -15,4 +15,4 @@ namespace OpenWifi {
 | 
				
			|||||||
			poco_warning(Logger_, fmt::format("PING({}): Missing parameter.", CId_));
 | 
								poco_warning(Logger_, fmt::format("PING({}): Missing parameter.", CId_));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/AP_WS_Process_rebootLog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/AP_WS_Process_rebootLog.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-05-16.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					#include <GWKafkaEvents.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void StripNulls(std::string &S) {
 | 
				
			||||||
 | 
							for(std::size_t i=0;i<S.size();++i) {
 | 
				
			||||||
 | 
								if(S[i]==0)
 | 
				
			||||||
 | 
									S[i]=' ';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AP_WS_Connection::Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
 | 
							if (ParamsObj->has(uCentralProtocol::UUID)
 | 
				
			||||||
 | 
								&& ParamsObj->isArray(uCentralProtocol::INFO)
 | 
				
			||||||
 | 
								&& ParamsObj->has(uCentralProtocol::TYPE)
 | 
				
			||||||
 | 
								&& ParamsObj->has(uCentralProtocol::DATE) ) {
 | 
				
			||||||
 | 
								poco_warning(Logger_, fmt::format("REBOOT-LOG({}): new entry.", CId_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto InfoLines = ParamsObj->getArray(uCentralProtocol::INFO);
 | 
				
			||||||
 | 
								std::ostringstream os;
 | 
				
			||||||
 | 
								InfoLines->stringify(os);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								GWObjects::DeviceLog DeviceLog{.SerialNumber = SerialNumber_,
 | 
				
			||||||
 | 
															   .Log = ParamsObj->get(uCentralProtocol::TYPE).toString(),
 | 
				
			||||||
 | 
															   .Data = "{ \"info\" : " + os.str() + "}",
 | 
				
			||||||
 | 
															   .Severity = GWObjects::DeviceLog::LOG_INFO,
 | 
				
			||||||
 | 
															   .Recorded = ParamsObj->get(uCentralProtocol::DATE),
 | 
				
			||||||
 | 
															   .LogType = 2,
 | 
				
			||||||
 | 
															   .UUID = ParamsObj->get(uCentralProtocol::UUID)};
 | 
				
			||||||
 | 
								StorageService()->AddLog(DeviceLog);
 | 
				
			||||||
 | 
								DeviceLogKafkaEvent	E(DeviceLog);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								poco_warning(Logger_, fmt::format("REBOOT-LOG({}): Missing parameters.", CId_));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -3,8 +3,12 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "CommandManager.h"
 | 
					#include "CommandManager.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_recovery(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_recovery(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
@@ -36,7 +40,7 @@ namespace OpenWifi {
 | 
				
			|||||||
			if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
 | 
								if (ParamsObj->get(uCentralProtocol::REBOOT).toString() == "true") {
 | 
				
			||||||
				GWObjects::CommandDetails Cmd;
 | 
									GWObjects::CommandDetails Cmd;
 | 
				
			||||||
				Cmd.SerialNumber = SerialNumber_;
 | 
									Cmd.SerialNumber = SerialNumber_;
 | 
				
			||||||
				Cmd.UUID = MicroService::CreateUUID();
 | 
									Cmd.UUID = MicroServiceCreateUUID();
 | 
				
			||||||
				Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
 | 
									Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
 | 
				
			||||||
				Cmd.Status = uCentralProtocol::PENDING;
 | 
									Cmd.Status = uCentralProtocol::PENDING;
 | 
				
			||||||
				Cmd.Command = uCentralProtocol::REBOOT;
 | 
									Cmd.Command = uCentralProtocol::REBOOT;
 | 
				
			||||||
@@ -47,16 +51,24 @@ namespace OpenWifi {
 | 
				
			|||||||
				Poco::JSON::Stringifier::stringify(Params, O);
 | 
									Poco::JSON::Stringifier::stringify(Params, O);
 | 
				
			||||||
				Cmd.Details = O.str();
 | 
									Cmd.Details = O.str();
 | 
				
			||||||
				bool Sent;
 | 
									bool Sent;
 | 
				
			||||||
				CommandManager()->PostCommand(CommandManager()->NextRPCId(),SerialNumber_, Cmd.Command, Params, Cmd.UUID, Sent);
 | 
									CommandManager()->PostCommand(CommandManager()->Next_RPC_ID(),
 | 
				
			||||||
				StorageService()->AddCommand(SerialNumber_, Cmd, Storage::CommandExecutionType::COMMAND_EXECUTED);
 | 
																  APCommands::Commands::reboot, SerialNumber_,
 | 
				
			||||||
				poco_information(Logger_, fmt::format("RECOVERY({}): Recovery mode received, need for a reboot.", CId_));
 | 
																  Cmd.Command, Params, Cmd.UUID, Sent, false, false);
 | 
				
			||||||
 | 
									StorageService()->AddCommand(SerialNumber_, Cmd,
 | 
				
			||||||
 | 
																 Storage::CommandExecutionType::COMMAND_EXECUTED);
 | 
				
			||||||
 | 
									poco_information(
 | 
				
			||||||
 | 
										Logger_,
 | 
				
			||||||
 | 
										fmt::format("RECOVERY({}): Recovery mode received, need for a reboot.", CId_));
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				poco_information(Logger_, fmt::format(
 | 
									poco_information(
 | 
				
			||||||
											   "RECOVERY({}): Recovery mode received, no need for a reboot.", CId_));
 | 
										Logger_,
 | 
				
			||||||
 | 
										fmt::format("RECOVERY({}): Recovery mode received, no need for a reboot.",
 | 
				
			||||||
 | 
													CId_));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("RECOVERY({}): Recovery missing one of serialnumber, firmware, uuid, loglines, reboot",
 | 
								poco_warning(Logger_, fmt::format("RECOVERY({}): Recovery missing one of serialnumber, "
 | 
				
			||||||
 | 
																  "firmware, uuid, loglines, reboot",
 | 
				
			||||||
											  CId_));
 | 
																  CId_));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -3,15 +3,22 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "framework/WebSocketClientNotifications.h"
 | 
					 | 
				
			||||||
#include "StateUtils.h"
 | 
					#include "StateUtils.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "UI_GW_WebSocketNotifications.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_state(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_state(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (!State_.Connected) {
 | 
							if (!State_.Connected) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format(
 | 
								poco_warning(Logger_,
 | 
				
			||||||
									   "INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -28,40 +35,40 @@ namespace OpenWifi {
 | 
				
			|||||||
			if (request_uuid.empty()) {
 | 
								if (request_uuid.empty()) {
 | 
				
			||||||
				poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating.", CId_, UUID));
 | 
									poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating.", CId_, UUID));
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating for CMD={}.",
 | 
									poco_trace(Logger_, fmt::format("STATE({}): UUID={} Updating for CMD={}.", CId_,
 | 
				
			||||||
												 CId_, UUID, request_uuid));
 | 
																	UUID, request_uuid));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(!Simulated_) {
 | 
				
			||||||
				uint64_t UpgradedUUID;
 | 
									uint64_t UpgradedUUID;
 | 
				
			||||||
				LookForUpgrade(UUID, UpgradedUUID);
 | 
									LookForUpgrade(UUID, UpgradedUUID);
 | 
				
			||||||
				State_.UUID = UpgradedUUID;
 | 
									State_.UUID = UpgradedUUID;
 | 
				
			||||||
			LastStats_ = StateStr;
 | 
								}
 | 
				
			||||||
 | 
								SetLastStats(StateStr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			GWObjects::Statistics Stats{
 | 
								GWObjects::Statistics Stats{
 | 
				
			||||||
				.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
 | 
									.SerialNumber = SerialNumber_, .UUID = UUID, .Data = StateStr};
 | 
				
			||||||
			Stats.Recorded = OpenWifi::Now();
 | 
								Stats.Recorded = Utils::Now();
 | 
				
			||||||
			StorageService()->AddStatisticsData(Stats);
 | 
								StorageService()->AddStatisticsData(Stats);
 | 
				
			||||||
			if (!request_uuid.empty()) {
 | 
								if (!request_uuid.empty()) {
 | 
				
			||||||
				StorageService()->SetCommandResult(request_uuid, StateStr);
 | 
									StorageService()->SetCommandResult(request_uuid, StateStr);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
 | 
								StateUtils::ComputeAssociations(StateObj, State_.Associations_2G,
 | 
				
			||||||
														State_.Associations_5G);
 | 
																State_.Associations_5G, State_.Associations_6G);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (KafkaManager()->Enabled()) {
 | 
								if (KafkaManager()->Enabled()) {
 | 
				
			||||||
				Poco::JSON::Stringifier Stringify;
 | 
									KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, *ParamsObj);
 | 
				
			||||||
				std::ostringstream OS;
 | 
					 | 
				
			||||||
				Stringify.condense(ParamsObj, OS);
 | 
					 | 
				
			||||||
				KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			WebSocketNotification<WebNotificationSingleDevice>	N;
 | 
								GWWebSocketNotifications::SingleDevice_t N;
 | 
				
			||||||
			N.content.serialNumber = SerialNumber_;
 | 
								N.content.serialNumber = SerialNumber_;
 | 
				
			||||||
			N.type = "device_statistics";
 | 
								GWWebSocketNotifications::DeviceStatistics(N);
 | 
				
			||||||
			WebSocketClientServer()->SendNotification(N);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
 | 
								poco_warning(
 | 
				
			||||||
		}
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("STATE({}): Invalid request. Missing serial, uuid, or state", CId_));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -3,32 +3,45 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "TelemetryStream.h"
 | 
					 | 
				
			||||||
#include "CommandManager.h"
 | 
					#include "CommandManager.h"
 | 
				
			||||||
 | 
					#include "TelemetryStream.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_telemetry(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_telemetry(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (!State_.Connected) {
 | 
							if (!State_.Connected) {
 | 
				
			||||||
			poco_warning(Logger_, fmt::format(
 | 
								poco_warning(Logger_,
 | 
				
			||||||
									   "INVALID-PROTOCOL({}): Device '{}' is not following protocol", CId_, CN_));
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
			Errors_++;
 | 
								Errors_++;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (TelemetryReporting_) {
 | 
							poco_trace(Logger_, fmt::format("Telemetry data received for {}", SerialNumber_));
 | 
				
			||||||
 | 
							if (TelemetryReporting_ || ParamsObj->has("adhoc")) {
 | 
				
			||||||
			if (ParamsObj->has("data")) {
 | 
								if (ParamsObj->has("data")) {
 | 
				
			||||||
				auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
 | 
									auto Payload = ParamsObj->get("data").extract<Poco::JSON::Object::Ptr>();
 | 
				
			||||||
				Payload->set("timestamp", OpenWifi::Now());
 | 
									Payload->set("timestamp", Utils::Now());
 | 
				
			||||||
				std::ostringstream SS;
 | 
									std::ostringstream SS;
 | 
				
			||||||
				Payload->stringify(SS);
 | 
									Payload->stringify(SS);
 | 
				
			||||||
				auto now=OpenWifi::Now();
 | 
									auto now = Utils::Now();
 | 
				
			||||||
 | 
									auto KafkaPayload = SS.str();
 | 
				
			||||||
 | 
									if (ParamsObj->has("adhoc")) {
 | 
				
			||||||
 | 
										KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
 | 
				
			||||||
 | 
																	KafkaPayload);
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				if (TelemetryWebSocketRefCount_) {
 | 
									if (TelemetryWebSocketRefCount_) {
 | 
				
			||||||
					if (now < TelemetryWebSocketTimer_) {
 | 
										if (now < TelemetryWebSocketTimer_) {
 | 
				
			||||||
						// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" << std::endl;
 | 
											// std::cout << SerialNumber_ << ": Updating WebSocket telemetry" <<
 | 
				
			||||||
 | 
											// std::endl;
 | 
				
			||||||
						TelemetryWebSocketPackets_++;
 | 
											TelemetryWebSocketPackets_++;
 | 
				
			||||||
						State_.websocketPackets = TelemetryWebSocketPackets_;
 | 
											State_.websocketPackets = TelemetryWebSocketPackets_;
 | 
				
			||||||
						TelemetryStream()->UpdateEndPoint(SerialNumberInt_, SS.str());
 | 
											TelemetryStream()->NotifyEndPoint(SerialNumberInt_, KafkaPayload);
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						StopWebSocketTelemetry(CommandManager()->NextRPCId());
 | 
											StopWebSocketTelemetry(CommandManager()->Next_RPC_ID());
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if (TelemetryKafkaRefCount_) {
 | 
									if (TelemetryKafkaRefCount_) {
 | 
				
			||||||
@@ -37,18 +50,20 @@ namespace OpenWifi {
 | 
				
			|||||||
						TelemetryKafkaPackets_++;
 | 
											TelemetryKafkaPackets_++;
 | 
				
			||||||
						State_.kafkaPackets = TelemetryKafkaPackets_;
 | 
											State_.kafkaPackets = TelemetryKafkaPackets_;
 | 
				
			||||||
						KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
 | 
											KafkaManager()->PostMessage(KafkaTopics::DEVICE_TELEMETRY, SerialNumber_,
 | 
				
			||||||
													SS.str());
 | 
																		KafkaPayload);
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						StopKafkaTelemetry(CommandManager()->NextRPCId());
 | 
											StopKafkaTelemetry(CommandManager()->Next_RPC_ID());
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				poco_debug(Logger_,fmt::format("TELEMETRY({}): Invalid telemetry packet.",SerialNumber_));
 | 
									poco_debug(Logger_,
 | 
				
			||||||
 | 
											   fmt::format("TELEMETRY({}): Invalid telemetry packet.", SerialNumber_));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// if we are ignoring telemetry, then close it down on the device.
 | 
								// if we are ignoring telemetry, then close it down on the device.
 | 
				
			||||||
			poco_debug(Logger_,fmt::format("TELEMETRY({}): Stopping runaway telemetry.",SerialNumber_));
 | 
								poco_debug(Logger_,
 | 
				
			||||||
			StopTelemetry(CommandManager()->NextRPCId());
 | 
										   fmt::format("TELEMETRY({}): Stopping runaway telemetry.", SerialNumber_));
 | 
				
			||||||
		}
 | 
								StopTelemetry(CommandManager()->Next_RPC_ID());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -8,10 +8,9 @@
 | 
				
			|||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void AP_WS_Connection::Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj) {
 | 
						void AP_WS_Connection::Process_venuebroadcast(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
		if (ParamsObj->has("data") && ParamsObj->has("serial") && ParamsObj->has("timestamp")) {
 | 
							if (ParamsObj->has("data") && ParamsObj->has("serial") && ParamsObj->has("timestamp")) {
 | 
				
			||||||
			VenueBroadcaster()->Broadcast(
 | 
								VenueBroadcaster()->Broadcast(ParamsObj->get("serial").toString(),
 | 
				
			||||||
				ParamsObj->get("serial").toString(),
 | 
															  ParamsObj->getObject("data"),
 | 
				
			||||||
				ParamsObj->get("data").toString(),
 | 
					 | 
				
			||||||
										  ParamsObj->get("timestamp"));
 | 
															  ParamsObj->get("timestamp"));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/AP_WS_Process_wifiscan.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/AP_WS_Process_wifiscan.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-01-22.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/KafkaManager.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
						void AP_WS_Connection::Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj) {
 | 
				
			||||||
 | 
							if (!State_.Connected) {
 | 
				
			||||||
 | 
								poco_warning(Logger_,
 | 
				
			||||||
 | 
											 fmt::format("INVALID-PROTOCOL({}): Device '{}' is not following protocol",
 | 
				
			||||||
 | 
														 CId_, CN_));
 | 
				
			||||||
 | 
								Errors_++;
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							poco_trace(Logger_, fmt::format("Wifiscan data received for {}", SerialNumber_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::DATA)) {
 | 
				
			||||||
 | 
								if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
									KafkaManager()->PostMessage(KafkaTopics::WIFISCAN, SerialNumber_, *ParamsObj);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,24 +4,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <shared_mutex>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/Net/SocketAcceptor.h"
 | 
					 | 
				
			||||||
#include "Poco/Environment.h"
 | 
					#include "Poco/Environment.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/SocketAcceptor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	class AP_WS_ReactorThreadPool {
 | 
						class AP_WS_ReactorThreadPool {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		explicit AP_WS_ReactorThreadPool() {
 | 
							explicit AP_WS_ReactorThreadPool() {
 | 
				
			||||||
			NumberOfThreads_ = Poco::Environment::processorCount()*2;
 | 
								NumberOfThreads_ = Poco::Environment::processorCount() * 4;
 | 
				
			||||||
			if (NumberOfThreads_ == 0)
 | 
								if (NumberOfThreads_ == 0)
 | 
				
			||||||
				NumberOfThreads_ = 4;
 | 
									NumberOfThreads_ = 4;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		~ AP_WS_ReactorThreadPool() {
 | 
							~AP_WS_ReactorThreadPool() { Stop(); }
 | 
				
			||||||
			Stop();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void Start() {
 | 
							void Start() {
 | 
				
			||||||
			for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
 | 
								for (uint64_t i = 0; i < NumberOfThreads_; ++i) {
 | 
				
			||||||
@@ -46,17 +46,17 @@ namespace OpenWifi {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Poco::Net::SocketReactor &NextReactor() {
 | 
							Poco::Net::SocketReactor &NextReactor() {
 | 
				
			||||||
			std::shared_lock		Lock(Mutex_);
 | 
								std::lock_guard Lock(Mutex_);
 | 
				
			||||||
			NextReactor_++;
 | 
								NextReactor_++;
 | 
				
			||||||
			NextReactor_ %= NumberOfThreads_;
 | 
								NextReactor_ %= NumberOfThreads_;
 | 
				
			||||||
			return *Reactors_[NextReactor_];
 | 
								return *Reactors_[NextReactor_];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::shared_mutex	Mutex_;
 | 
							std::mutex Mutex_;
 | 
				
			||||||
		uint64_t NumberOfThreads_;
 | 
							uint64_t NumberOfThreads_;
 | 
				
			||||||
		uint64_t NextReactor_ = 0;
 | 
							uint64_t NextReactor_ = 0;
 | 
				
			||||||
		std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
 | 
							std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
 | 
				
			||||||
		std::vector<std::unique_ptr<Poco::Thread>> Threads_;
 | 
							std::vector<std::unique_ptr<Poco::Thread>> Threads_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -6,31 +6,42 @@
 | 
				
			|||||||
//	Arilia Wireless Inc.
 | 
					//	Arilia Wireless Inc.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/Net/HTTPHeaderStream.h"
 | 
					 | 
				
			||||||
#include "Poco/JSON/Array.h"
 | 
					 | 
				
			||||||
#include "Poco/Net/Context.h"
 | 
					#include "Poco/Net/Context.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTTPHeaderStream.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTTPServerRequest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
 | 
					#include "AP_WS_Server.h"
 | 
				
			||||||
#include "ConfigurationCache.h"
 | 
					#include "ConfigurationCache.h"
 | 
				
			||||||
#include "TelemetryStream.h"
 | 
					#include "TelemetryStream.h"
 | 
				
			||||||
#include "framework/WebSocketClientNotifications.h"
 | 
					
 | 
				
			||||||
 | 
					#include "UI_GW_WebSocketNotifications.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					#include <framework/KafkaManager.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
 | 
						void AP_WS_RequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request,
 | 
				
			||||||
											 Poco::Net::HTTPServerResponse &response) {
 | 
																 Poco::Net::HTTPServerResponse &response) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			AP_WS_Server()->AddConnection(id_,std::make_shared<AP_WS_Connection>(request,response,id_, Logger_, AP_WS_Server()->NextReactor()));
 | 
								AP_WS_Server()->AddConnection(
 | 
				
			||||||
 | 
									id_, std::make_shared<AP_WS_Connection>(request, response, id_, Logger_,
 | 
				
			||||||
 | 
																			AP_WS_Server()->NextReactor()));
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_warning(Logger_, "Exception during WS creation");
 | 
								poco_warning(Logger_, "Exception during WS creation");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
 | 
						bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
 | 
				
			||||||
 | 
															   const Poco::Crypto::X509Certificate &Certificate) {
 | 
				
			||||||
		if (IsCertOk()) {
 | 
							if (IsCertOk()) {
 | 
				
			||||||
			if (!Certificate.issuedBy(*IssuerCert_)) {
 | 
								if (!Certificate.issuedBy(*IssuerCert_)) {
 | 
				
			||||||
				poco_warning(Logger(),fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
 | 
									poco_warning(
 | 
				
			||||||
 | 
										Logger(),
 | 
				
			||||||
 | 
										fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'",
 | 
				
			||||||
 | 
													ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
@@ -40,15 +51,19 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	int AP_WS_Server::Start() {
 | 
						int AP_WS_Server::Start() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AllowSerialNumberMismatch_ = MicroService::instance().ConfigGetBool("openwifi.certificates.allowmismatch",true);
 | 
							AllowSerialNumberMismatch_ =
 | 
				
			||||||
		MismatchDepth_ = MicroService::instance().ConfigGetInt("openwifi.certificates.mismatchdepth",2);
 | 
								MicroServiceConfigGetBool("openwifi.certificates.allowmismatch", true);
 | 
				
			||||||
 | 
							MismatchDepth_ = MicroServiceConfigGetInt("openwifi.certificates.mismatchdepth", 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SessionTimeOut_ = MicroServiceConfigGetInt("openwifi.session.timeout", 10*60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
 | 
							Reactor_pool_ = std::make_unique<AP_WS_ReactorThreadPool>();
 | 
				
			||||||
		Reactor_pool_->Start();
 | 
							Reactor_pool_->Start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (const auto &Svr : ConfigServersList_) {
 | 
							for (const auto &Svr : ConfigServersList_) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			poco_notice(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(),
 | 
								poco_notice(Logger(),
 | 
				
			||||||
 | 
											fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(),
 | 
				
			||||||
									Svr.Port(), Svr.KeyFile(), Svr.CertFile()));
 | 
														Svr.Port(), Svr.KeyFile(), Svr.CertFile()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Svr.LogCert(Logger());
 | 
								Svr.LogCert(Logger());
 | 
				
			||||||
@@ -57,8 +72,8 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (!IsCertOk()) {
 | 
								if (!IsCertOk()) {
 | 
				
			||||||
				IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
 | 
									IssuerCert_ = std::make_unique<Poco::Crypto::X509Certificate>(Svr.IssuerCertFile());
 | 
				
			||||||
				poco_information(Logger(),
 | 
									poco_information(
 | 
				
			||||||
					fmt::format("Certificate Issuer Name:{}", IssuerCert_->issuerName()));
 | 
										Logger(), fmt::format("Certificate Issuer Name:{}", IssuerCert_->issuerName()));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Poco::Net::Context::Params P;
 | 
								Poco::Net::Context::Params P;
 | 
				
			||||||
@@ -70,12 +85,8 @@ namespace OpenWifi {
 | 
				
			|||||||
			P.dhUse2048Bits = true;
 | 
								P.dhUse2048Bits = true;
 | 
				
			||||||
			P.caLocation = Svr.Cas();
 | 
								P.caLocation = Svr.Cas();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
 | 
								auto Context = Poco::AutoPtr<Poco::Net::Context>(
 | 
				
			||||||
 | 
									new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
 | 
				
			||||||
			if(!Svr.KeyFilePassword().empty()) {
 | 
					 | 
				
			||||||
				auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(Svr.KeyFilePassword(),Logger()));
 | 
					 | 
				
			||||||
				Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Poco::Crypto::X509Certificate Cert(Svr.CertFile());
 | 
								Poco::Crypto::X509Certificate Cert(Svr.CertFile());
 | 
				
			||||||
			Poco::Crypto::X509Certificate Root(Svr.RootCA());
 | 
								Poco::Crypto::X509Certificate Root(Svr.RootCA());
 | 
				
			||||||
@@ -96,8 +107,8 @@ namespace OpenWifi {
 | 
				
			|||||||
			Context->flushSessionCache();
 | 
								Context->flushSessionCache();
 | 
				
			||||||
			Context->enableSessionCache(true);
 | 
								Context->enableSessionCache(true);
 | 
				
			||||||
			Context->enableExtendedCertificateVerification(false);
 | 
								Context->enableExtendedCertificateVerification(false);
 | 
				
			||||||
			// Context->disableStatelessSessionResumption();
 | 
								Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 |
 | 
				
			||||||
			Context->disableProtocols(Poco::Net::Context::PROTO_TLSV1 | Poco::Net::Context::PROTO_TLSV1_1);
 | 
														  Poco::Net::Context::PROTO_TLSV1_1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
 | 
								auto WebServerHttpParams = new Poco::Net::HTTPServerParams;
 | 
				
			||||||
			WebServerHttpParams->setMaxThreads(50);
 | 
								WebServerHttpParams->setMaxThreads(50);
 | 
				
			||||||
@@ -111,13 +122,17 @@ namespace OpenWifi {
 | 
				
			|||||||
													  : Poco::Net::AddressFamily::IPv4));
 | 
																		  : Poco::Net::AddressFamily::IPv4));
 | 
				
			||||||
				Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
 | 
									Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
 | 
				
			||||||
				auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
 | 
									auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
 | 
				
			||||||
					new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
 | 
										new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_,
 | 
				
			||||||
 | 
										Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context),
 | 
				
			||||||
 | 
										WebServerHttpParams);
 | 
				
			||||||
				WebServers_.push_back(std::move(NewWebServer));
 | 
									WebServers_.push_back(std::move(NewWebServer));
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				Poco::Net::IPAddress Addr(Svr.Address());
 | 
									Poco::Net::IPAddress Addr(Svr.Address());
 | 
				
			||||||
				Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
 | 
									Poco::Net::SocketAddress SockAddr(Addr, Svr.Port());
 | 
				
			||||||
				auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
 | 
									auto NewWebServer = std::make_unique<Poco::Net::HTTPServer>(
 | 
				
			||||||
					new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_, Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context), WebServerHttpParams);
 | 
										new AP_WS_RequestHandlerFactory(Logger()), DeviceConnectionPool_,
 | 
				
			||||||
 | 
										Poco::Net::SecureServerSocket(SockAddr, Svr.Backlog(), Context),
 | 
				
			||||||
 | 
										WebServerHttpParams);
 | 
				
			||||||
				WebServers_.push_back(std::move(NewWebServer));
 | 
									WebServers_.push_back(std::move(NewWebServer));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -128,7 +143,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		ReactorThread_.start(Reactor_);
 | 
							ReactorThread_.start(Reactor_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto ProvString = MicroService::instance().ConfigGetString("autoprovisioning.process","default");
 | 
							auto ProvString = MicroServiceConfigGetString("autoprovisioning.process", "default");
 | 
				
			||||||
		if (ProvString != "default") {
 | 
							if (ProvString != "default") {
 | 
				
			||||||
			auto Tokens = Poco::StringTokenizer(ProvString, ",");
 | 
								auto Tokens = Poco::StringTokenizer(ProvString, ",");
 | 
				
			||||||
			for (const auto &i : Tokens) {
 | 
								for (const auto &i : Tokens) {
 | 
				
			||||||
@@ -141,61 +156,113 @@ namespace OpenWifi {
 | 
				
			|||||||
			UseDefaultConfig_ = true;
 | 
								UseDefaultConfig_ = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		SimulatorId_ = MicroService::instance().ConfigGetString("simulatorid","");
 | 
							SimulatorId_ = MicroServiceConfigGetString("simulatorid", "");
 | 
				
			||||||
		SimulatorEnabled_ = !SimulatorId_.empty();
 | 
							SimulatorEnabled_ = !SimulatorId_.empty();
 | 
				
			||||||
		Utils::SetThreadName(ReactorThread_, "dev:react:head");
 | 
							Utils::SetThreadName(ReactorThread_, "dev:react:head");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(*this,&AP_WS_Server::onGarbageCollecting);
 | 
							GarbageCollectorCallback_ = std::make_unique<Poco::TimerCallback<AP_WS_Server>>(
 | 
				
			||||||
 | 
								*this, &AP_WS_Server::onGarbageCollecting);
 | 
				
			||||||
		Timer_.setStartInterval(10 * 1000);
 | 
							Timer_.setStartInterval(10 * 1000);
 | 
				
			||||||
		Timer_.setPeriodicInterval(5 * 1000); // every minute
 | 
							Timer_.setPeriodicInterval(10 * 1000); // every minute
 | 
				
			||||||
		Timer_.start(*GarbageCollectorCallback_, MicroService::instance().TimerPool());
 | 
							Timer_.start(*GarbageCollectorCallback_, MicroServiceTimerPool());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Running_ = true;
 | 
							Running_ = true;
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
 | 
						void AP_WS_Server::onGarbageCollecting([[maybe_unused]] Poco::Timer &timer) {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
							static uint64_t last_log = Utils::Now(), last_zombie_run = 0;
 | 
				
			||||||
		if(Garbage_.size()>0) {
 | 
							auto now = Utils::Now();
 | 
				
			||||||
			std::cout << "Removing " << Garbage_.size() << " old connections." << std::endl;
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::lock_guard SessionLock(SessionMutex_);
 | 
				
			||||||
 | 
									if (!Garbage_.empty()) {
 | 
				
			||||||
					Garbage_.clear();
 | 
										Garbage_.clear();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static std::uint64_t last_log = OpenWifi::Now();
 | 
								uint64_t total_connected_time = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(now-last_zombie_run > 20) {
 | 
				
			||||||
 | 
									poco_information(Logger(), fmt::format("Garbage collecting..."));
 | 
				
			||||||
 | 
									std::vector<std::uint64_t> SessionsToRemove;
 | 
				
			||||||
				NumberOfConnectedDevices_ = 0;
 | 
									NumberOfConnectedDevices_ = 0;
 | 
				
			||||||
				NumberOfConnectingDevices_ = 0;
 | 
									NumberOfConnectingDevices_ = 0;
 | 
				
			||||||
				AverageDeviceConnectionTime_ = 0;
 | 
									AverageDeviceConnectionTime_ = 0;
 | 
				
			||||||
		std::uint64_t	total_connected_time=0;
 | 
									last_zombie_run = now;
 | 
				
			||||||
 | 
									for(int hashIndex=0;hashIndex<256;hashIndex++) {
 | 
				
			||||||
		auto now = OpenWifi::Now();
 | 
										std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
		for (auto connection=SerialNumbers_.begin(); connection!=SerialNumbers_.end();) {
 | 
										auto hint = SerialNumbers_[hashIndex].begin();
 | 
				
			||||||
 | 
										while (hint != end(SerialNumbers_[hashIndex])) {
 | 
				
			||||||
			if(connection->second.second== nullptr) {
 | 
											if (hint->second.second == nullptr) {
 | 
				
			||||||
				connection++;
 | 
												hint = SerialNumbers_[hashIndex].erase(hint);
 | 
				
			||||||
				continue;
 | 
											} else if ((now - hint->second.second->State_.LastContact) >
 | 
				
			||||||
			}
 | 
													   SessionTimeOut_) {
 | 
				
			||||||
 | 
												hint->second.second->EndConnection(false);
 | 
				
			||||||
			if (connection->second.second->State_.Connected) {
 | 
												poco_information(
 | 
				
			||||||
 | 
													Logger(),
 | 
				
			||||||
 | 
													fmt::format(
 | 
				
			||||||
 | 
														"{}: Session seems idle. Controller disconnecting device.",
 | 
				
			||||||
 | 
														hint->second.second->SerialNumber_));
 | 
				
			||||||
 | 
												SessionsToRemove.emplace_back(hint->second.first);
 | 
				
			||||||
 | 
												Garbage_.push_back(hint->second.second);
 | 
				
			||||||
 | 
												hint = SerialNumbers_[hashIndex].erase(hint);
 | 
				
			||||||
 | 
											} else if (hint->second.second->State_.Connected) {
 | 
				
			||||||
							NumberOfConnectedDevices_++;
 | 
												NumberOfConnectedDevices_++;
 | 
				
			||||||
				total_connected_time += (now - connection->second.second->State_.started);
 | 
												total_connected_time += (now - hint->second.second->State_.started);
 | 
				
			||||||
				connection++;
 | 
												hint++;
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							NumberOfConnectingDevices_++;
 | 
												NumberOfConnectingDevices_++;
 | 
				
			||||||
				connection++;
 | 
												hint++;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AverageDeviceConnectionTime_ = (NumberOfConnectedDevices_!=0) ? total_connected_time/NumberOfConnectedDevices_ : 0;
 | 
									if(SessionsToRemove.empty()) {
 | 
				
			||||||
 | 
										poco_information(Logger(), fmt::format("Removing {} sessions.", SessionsToRemove.size()));
 | 
				
			||||||
 | 
										std::lock_guard Lock(SessionMutex_);
 | 
				
			||||||
 | 
										for (const auto &Session : SessionsToRemove) {
 | 
				
			||||||
 | 
											Sessions_.erase(Session);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									AverageDeviceConnectionTime_ =
 | 
				
			||||||
 | 
									NumberOfConnectedDevices_ > 0 ? total_connected_time / NumberOfConnectedDevices_
 | 
				
			||||||
 | 
																  : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									poco_information(Logger(), fmt::format("Garbage collecting done..."));
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									std::lock_guard SessionLock(SessionMutex_);
 | 
				
			||||||
 | 
									NumberOfConnectedDevices_ = Sessions_.size();
 | 
				
			||||||
 | 
									AverageDeviceConnectionTime_ += 10;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if ((now - last_log) > 120) {
 | 
								if ((now - last_log) > 120) {
 | 
				
			||||||
				last_log = now;
 | 
									last_log = now;
 | 
				
			||||||
				poco_information(Logger(),
 | 
									poco_information(Logger(),
 | 
				
			||||||
								 fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
 | 
													 fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
 | 
				
			||||||
										 NumberOfConnectedDevices_, NumberOfConnectingDevices_, AverageDeviceConnectionTime_));
 | 
																 NumberOfConnectedDevices_, NumberOfConnectingDevices_,
 | 
				
			||||||
 | 
																 AverageDeviceConnectionTime_));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		WebSocketClientNotificationNumberOfConnections(NumberOfConnectedDevices_,
 | 
							}
 | 
				
			||||||
													   AverageDeviceConnectionTime_,
 | 
					
 | 
				
			||||||
													   NumberOfConnectingDevices_);
 | 
							GWWebSocketNotifications::NumberOfConnection_t Notification;
 | 
				
			||||||
 | 
							Notification.content.numberOfConnectingDevices = NumberOfConnectingDevices_;
 | 
				
			||||||
 | 
							Notification.content.numberOfDevices = NumberOfConnectedDevices_;
 | 
				
			||||||
 | 
							Notification.content.averageConnectedTime = AverageDeviceConnectionTime_;
 | 
				
			||||||
 | 
							GetTotalDataStatistics(Notification.content.tx,Notification.content.rx);
 | 
				
			||||||
 | 
							GWWebSocketNotifications::NumberOfConnections(Notification);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Poco::JSON::Object	KafkaNotification;
 | 
				
			||||||
 | 
							Notification.to_json(KafkaNotification);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Poco::JSON::Object FullEvent;
 | 
				
			||||||
 | 
							FullEvent.set("type", "load-update");
 | 
				
			||||||
 | 
							FullEvent.set("timestamp", now);
 | 
				
			||||||
 | 
							FullEvent.set("payload", KafkaNotification);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, "system", FullEvent);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::Stop() {
 | 
						void AP_WS_Server::Stop() {
 | 
				
			||||||
@@ -213,198 +280,251 @@ namespace OpenWifi {
 | 
				
			|||||||
		poco_information(Logger(), "Stopped...");
 | 
							poco_information(Logger(), "Stopped...");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::GetStatistics(std::uint64_t SerialNumber, std::string &Statistics) const {
 | 
						bool AP_WS_Server::GetStatistics(uint64_t SerialNumber, std::string &Statistics) const {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
					
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		Statistics = Device->second.second->LastStats_;
 | 
							}
 | 
				
			||||||
 | 
							Device->second.second->GetLastStats(Statistics);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
 | 
						bool AP_WS_Server::GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
		if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		State = Device->second.second->State_;
 | 
							}
 | 
				
			||||||
 | 
							Device->second.second->GetState(State);
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
 | 
						bool AP_WS_Server::GetHealthcheck(uint64_t SerialNumber,
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
														  GWObjects::HealthCheck &CheckData) const {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == SerialNumbers_[hashIndex].end() || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		CheckData = Device->second.second->LastHealthcheck_;
 | 
							Device->second.second->GetLastHealthCheck(CheckData);
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber) {
 | 
						void AP_WS_Server::SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber) {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
							std::lock_guard SessionLock(SessionMutex_);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Conn = Sessions_.find(connection_id);
 | 
							auto Conn = Sessions_.find(connection_id);
 | 
				
			||||||
		if (Conn == end(Sessions_))
 | 
							if (Conn == end(Sessions_))
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if(	(CurrentSerialNumber==SerialNumbers_.end())	||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto CurrentSerialNumber = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if ((CurrentSerialNumber == SerialNumbers_[hashIndex].end()) ||
 | 
				
			||||||
			(CurrentSerialNumber->second.first < connection_id)) {
 | 
								(CurrentSerialNumber->second.first < connection_id)) {
 | 
				
			||||||
			SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Conn->second.first);
 | 
								SerialNumbers_[hashIndex][SerialNumber] = std::make_pair(connection_id, Conn->second);
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::EndSession(std::uint64_t session_id, std::uint64_t serial_number) {
 | 
						bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {
 | 
				
			||||||
		std::unique_lock G(LocalMutex_);
 | 
							std::lock_guard SessionLock(SessionMutex_);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Session = Sessions_.find(session_id);
 | 
							auto Session = Sessions_.find(session_id);
 | 
				
			||||||
		if (Session == end(Sessions_))
 | 
							if (Session == end(Sessions_))
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Garbage_.push_back(Session->second.first);
 | 
							Garbage_.push_back(Session->second);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto Device = SerialNumbers_.find(serial_number);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if (Device == end(SerialNumbers_)) {
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex])) {
 | 
				
			||||||
			Sessions_.erase(Session);
 | 
								Sessions_.erase(Session);
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (Device->second.first == session_id) {
 | 
							if (Device->second.first == session_id) {
 | 
				
			||||||
			Sessions_.erase(Session);
 | 
								Sessions_.erase(Session);
 | 
				
			||||||
			SerialNumbers_.erase(Device);
 | 
								SerialNumbers_[hashIndex].erase(Device);
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Sessions_.erase(Session);
 | 
							Sessions_.erase(Session);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
 | 
						bool AP_WS_Server::Connected(uint64_t SerialNumber,
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
													 GWObjects::DeviceRestrictions &Restrictions) const {
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Device->second.second->GetRestrictions(Restrictions);
 | 
				
			||||||
 | 
							return Device->second.second->State_.Connected;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool AP_WS_Server::Connected(uint64_t SerialNumber) const {
 | 
				
			||||||
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return Device->second.second->State_.Connected;
 | 
							return Device->second.second->State_.Connected;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
 | 
						bool AP_WS_Server::SendFrame(uint64_t SerialNumber, const std::string &Payload) const {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			// std::cout << "Device connection pointer: " << (std::uint64_t) Device->second.second << std::endl;
 | 
					 | 
				
			||||||
			return Device->second.second->Send(Payload);
 | 
								return Device->second.second->Send(Payload);
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
 | 
								poco_debug(Logger(), fmt::format(": SendFrame: Could not send data to device '{}'",
 | 
				
			||||||
 | 
																 Utils::IntToSerialNumber(SerialNumber)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
 | 
						void AP_WS_Server::StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		Device->second.second->StopWebSocketTelemetry(RPCID);
 | 
							Device->second.second->StopWebSocketTelemetry(RPCID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
 | 
						void
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
						AP_WS_Server::SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
 | 
				
			||||||
 | 
																	 uint64_t Interval, uint64_t Lifetime,
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
																	 const std::vector<std::string> &TelemetryTypes) {
 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
 | 
							}
 | 
				
			||||||
 | 
							Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
 | 
						void AP_WS_Server::SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
																	  uint64_t Interval, uint64_t Lifetime,
 | 
				
			||||||
 | 
																	  const std::vector<std::string> &TelemetryTypes) {
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
 | 
							}
 | 
				
			||||||
 | 
							Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime, TelemetryTypes);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
 | 
						void AP_WS_Server::StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber) {
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		Device->second.second->StopKafkaTelemetry(RPCID);
 | 
							Device->second.second->StopKafkaTelemetry(RPCID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Server::GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
 | 
						void AP_WS_Server::GetTelemetryParameters(
 | 
				
			||||||
												uint64_t & TelemetryInterval,
 | 
							uint64_t SerialNumber, bool &TelemetryRunning, uint64_t &TelemetryInterval,
 | 
				
			||||||
												uint64_t & TelemetryWebSocketTimer,
 | 
							uint64_t &TelemetryWebSocketTimer, uint64_t &TelemetryKafkaTimer,
 | 
				
			||||||
												uint64_t & TelemetryKafkaTimer,
 | 
							uint64_t &TelemetryWebSocketCount, uint64_t &TelemetryKafkaCount,
 | 
				
			||||||
												uint64_t & TelemetryWebSocketCount,
 | 
							uint64_t &TelemetryWebSocketPackets, uint64_t &TelemetryKafkaPackets) {
 | 
				
			||||||
												uint64_t & TelemetryKafkaCount,
 | 
					 | 
				
			||||||
												uint64_t & TelemetryWebSocketPackets,
 | 
					 | 
				
			||||||
												uint64_t & TelemetryKafkaPackets) {
 | 
					 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(SerialNumber);
 | 
				
			||||||
		if(Device==end(SerialNumbers_)|| Device->second.second== nullptr)
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(SerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		Device->second.second->GetTelemetryParameters(TelemetryRunning,
 | 
					 | 
				
			||||||
													  TelemetryInterval,
 | 
					 | 
				
			||||||
													  TelemetryWebSocketTimer,
 | 
					 | 
				
			||||||
													  TelemetryKafkaTimer,
 | 
					 | 
				
			||||||
													  TelemetryWebSocketCount,
 | 
					 | 
				
			||||||
													  TelemetryKafkaCount,
 | 
					 | 
				
			||||||
													  TelemetryWebSocketPackets,
 | 
					 | 
				
			||||||
													  TelemetryKafkaPackets);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
 | 
							Device->second.second->GetTelemetryParameters(TelemetryRunning, TelemetryInterval,
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
															  TelemetryWebSocketTimer, TelemetryKafkaTimer,
 | 
				
			||||||
		auto Device = 		SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
 | 
															  TelemetryWebSocketCount, TelemetryKafkaCount,
 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
															  TelemetryWebSocketPackets, TelemetryKafkaPackets);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool AP_WS_Server::SendRadiusAccountingData(const std::string &SerialNumber,
 | 
				
			||||||
 | 
																	const unsigned char *buffer, std::size_t size) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
 | 
				
			||||||
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return Device->second.second->SendRadiusAccountingData(buffer, size);
 | 
								return Device->second.second->SendRadiusAccountingData(buffer, size);
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
 | 
								poco_debug(
 | 
				
			||||||
 | 
									Logger(),
 | 
				
			||||||
 | 
									fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'",
 | 
				
			||||||
 | 
												SerialNumber));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
 | 
						bool AP_WS_Server::SendRadiusAuthenticationData(const std::string &SerialNumber,
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
																		const unsigned char *buffer, std::size_t size) {
 | 
				
			||||||
		auto Device = 		SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
 | 
							auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return Device->second.second->SendRadiusAuthenticationData(buffer, size);
 | 
								return Device->second.second->SendRadiusAuthenticationData(buffer, size);
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
 | 
								poco_debug(
 | 
				
			||||||
 | 
									Logger(),
 | 
				
			||||||
 | 
									fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'",
 | 
				
			||||||
 | 
												SerialNumber));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool AP_WS_Server::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
 | 
						bool AP_WS_Server::SendRadiusCoAData(const std::string &SerialNumber,
 | 
				
			||||||
		std::lock_guard			Lock(LocalMutex_);
 | 
															 const unsigned char *buffer, std::size_t size) {
 | 
				
			||||||
		auto Device = 		SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
 | 
							auto IntSerialNumber = Utils::SerialNumberToInt(SerialNumber);
 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
							auto hashIndex = Utils::CalculateMacAddressHash(IntSerialNumber);
 | 
				
			||||||
 | 
							std::lock_guard Lock(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
							auto Device = SerialNumbers_[hashIndex].find(IntSerialNumber);
 | 
				
			||||||
 | 
							if (Device == end(SerialNumbers_[hashIndex]) || Device->second.second == nullptr) {
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			return Device->second.second->SendRadiusCoAData(buffer, size);
 | 
								return Device->second.second->SendRadiusCoAData(buffer, size);
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
 | 
								poco_debug(Logger(),
 | 
				
			||||||
 | 
										   fmt::format(": SendRadiusCoAData: Could not send data to device '{}'",
 | 
				
			||||||
 | 
													   SerialNumber));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}      //namespace
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -8,43 +8,44 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <mutex>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <ctime>
 | 
					#include <ctime>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include <thread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/AutoPtr.h"
 | 
					#include "Poco/AutoPtr.h"
 | 
				
			||||||
#include "Poco/Net/SocketReactor.h"
 | 
					#include "Poco/Net/HTTPRequestHandler.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTTPRequestHandlerFactory.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTTPServer.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTTPServerRequest.h"
 | 
				
			||||||
#include "Poco/Net/ParallelSocketAcceptor.h"
 | 
					#include "Poco/Net/ParallelSocketAcceptor.h"
 | 
				
			||||||
#include "Poco/Net/SocketAcceptor.h"
 | 
					#include "Poco/Net/SocketAcceptor.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/SocketReactor.h"
 | 
				
			||||||
#include "Poco/Timer.h"
 | 
					#include "Poco/Timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Connection.h"
 | 
					#include "AP_WS_Connection.h"
 | 
				
			||||||
#include "AP_WS_ReactorPool.h"
 | 
					#include "AP_WS_ReactorPool.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
 | 
						class AP_WS_RequestHandler : public Poco::Net::HTTPRequestHandler {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		explicit AP_WS_RequestHandler(Poco::Logger &L, std::uint64_t id)
 | 
							explicit AP_WS_RequestHandler(Poco::Logger &L, uint64_t id) : Logger_(L), id_(id){};
 | 
				
			||||||
			: Logger_(L),
 | 
					 | 
				
			||||||
			  id_(id){
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void handleRequest(Poco::Net::HTTPServerRequest &request,
 | 
							void handleRequest(Poco::Net::HTTPServerRequest &request,
 | 
				
			||||||
						   Poco::Net::HTTPServerResponse &response) override;
 | 
											   Poco::Net::HTTPServerResponse &response) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		Poco::Logger &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
		std::uint64_t 				id_=0;
 | 
							uint64_t id_ = 0;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
 | 
						class AP_WS_RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L)
 | 
							inline explicit AP_WS_RequestHandlerFactory(Poco::Logger &L) : Logger_(L) {}
 | 
				
			||||||
		: Logger_(L) {
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline Poco::Net::HTTPRequestHandler *
 | 
							inline Poco::Net::HTTPRequestHandler *
 | 
				
			||||||
		createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
 | 
							createRequestHandler(const Poco::Net::HTTPServerRequest &request) override {
 | 
				
			||||||
@@ -56,9 +57,10 @@ namespace OpenWifi {
 | 
				
			|||||||
				return nullptr;
 | 
									return nullptr;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		Poco::Logger &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
		inline static std::uint64_t 		id_=1;
 | 
							inline static uint64_t id_ = 1;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class AP_WS_Server : public SubSystemServer {
 | 
						class AP_WS_Server : public SubSystemServer {
 | 
				
			||||||
@@ -71,86 +73,94 @@ namespace OpenWifi {
 | 
				
			|||||||
		int Start() override;
 | 
							int Start() override;
 | 
				
			||||||
		void Stop() override;
 | 
							void Stop() override;
 | 
				
			||||||
		bool IsCertOk() { return IssuerCert_ != nullptr; }
 | 
							bool IsCertOk() { return IssuerCert_ != nullptr; }
 | 
				
			||||||
		bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
 | 
							bool ValidateCertificate(const std::string &ConnectionId,
 | 
				
			||||||
		// Poco::Net::SocketReactor & GetNextReactor() { return ReactorPool_.NextReactor(); }
 | 
													 const Poco::Crypto::X509Certificate &Certificate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
 | 
							inline bool IsSimSerialNumber(const std::string &SerialNumber) const {
 | 
				
			||||||
			return IsSim(Poco::toLower(SerialNumber)) && Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
 | 
								return IsSim(Poco::toLower(SerialNumber)) &&
 | 
				
			||||||
 | 
									   Poco::toLower(SerialNumber) == Poco::toLower(SimulatorId_);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline static bool IsSim(const std::string &SerialNumber) {
 | 
							inline static bool IsSim(const std::string &SerialNumber) {
 | 
				
			||||||
			return SerialNumber.substr(0, 6) == "53494d";
 | 
								return SerialNumber.substr(0, 6) == "53494d";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool IsSimEnabled() const {
 | 
							inline bool IsSimEnabled() const { return SimulatorEnabled_; }
 | 
				
			||||||
			return SimulatorEnabled_;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool AllowSerialNumberMismatch() const {
 | 
							inline bool AllowSerialNumberMismatch() const { return AllowSerialNumberMismatch_; }
 | 
				
			||||||
			return AllowSerialNumberMismatch_;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline std::uint64_t MismatchDepth() const {
 | 
							inline uint64_t MismatchDepth() const { return MismatchDepth_; }
 | 
				
			||||||
			return MismatchDepth_;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool UseProvisioning() const { return LookAtProvisioning_; }
 | 
							inline bool UseProvisioning() const { return LookAtProvisioning_; }
 | 
				
			||||||
		inline bool UseDefaults() const { return UseDefaultConfig_; }
 | 
							inline bool UseDefaults() const { return UseDefaultConfig_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]] inline Poco::Net::SocketReactor & NextReactor() { return Reactor_pool_->NextReactor(); }
 | 
							[[nodiscard]] inline Poco::Net::SocketReactor &NextReactor() {
 | 
				
			||||||
 | 
								return Reactor_pool_->NextReactor();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		[[nodiscard]] inline bool Running() const { return Running_; }
 | 
							[[nodiscard]] inline bool Running() const { return Running_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline void AddConnection(std::uint64_t session_id, std::shared_ptr<AP_WS_Connection> Connection ) {
 | 
							inline void AddConnection(uint64_t session_id,
 | 
				
			||||||
			std::lock_guard			Lock(LocalMutex_);
 | 
													  std::shared_ptr<AP_WS_Connection> Connection) {
 | 
				
			||||||
			Sessions_[session_id] = std::make_pair(std::move(Connection),false);
 | 
								std::lock_guard Lock(SessionMutex_);
 | 
				
			||||||
 | 
								Sessions_[session_id] = std::move(Connection);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline std::shared_ptr<AP_WS_Connection> FindConnection(std::uint64_t session_id) const {
 | 
							inline bool DeviceRequiresSecureRtty(uint64_t serialNumber) const {
 | 
				
			||||||
			std::lock_guard			Lock(LocalMutex_);
 | 
								auto hashIndex = Utils::CalculateMacAddressHash(serialNumber);
 | 
				
			||||||
 | 
								std::lock_guard	G(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto Connection = Sessions_.find(session_id);
 | 
								auto Connection = SerialNumbers_[hashIndex].find(serialNumber);
 | 
				
			||||||
			if(Connection!=end(Sessions_))
 | 
								if (Connection==end(SerialNumbers_[hashIndex]) || Connection->second.second==nullptr)
 | 
				
			||||||
				return Connection->second.first;
 | 
									return false;
 | 
				
			||||||
			return nullptr;
 | 
								return Connection->second.second->RttyMustBeSecure_;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const {
 | 
							inline bool GetStatistics(const std::string &SerialNumber, std::string &Statistics) const {
 | 
				
			||||||
			return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics);
 | 
								return GetStatistics(Utils::SerialNumberToInt(SerialNumber), Statistics);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bool GetStatistics(std::uint64_t SerialNumber, std::string & Statistics) const ;
 | 
							bool GetStatistics(uint64_t SerialNumber, std::string &Statistics) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
 | 
							inline bool GetState(const std::string &SerialNumber,
 | 
				
			||||||
 | 
												 GWObjects::ConnectionState &State) const {
 | 
				
			||||||
			return GetState(Utils::SerialNumberToInt(SerialNumber), State);
 | 
								return GetState(Utils::SerialNumberToInt(SerialNumber), State);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bool GetState(std::uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
 | 
							bool GetState(uint64_t SerialNumber, GWObjects::ConnectionState &State) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
 | 
							inline bool GetHealthcheck(const std::string &SerialNumber,
 | 
				
			||||||
 | 
													   GWObjects::HealthCheck &CheckData) const {
 | 
				
			||||||
			return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
 | 
								return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bool GetHealthcheck(std::uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
 | 
							bool GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck &CheckData) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const;
 | 
				
			||||||
		bool Connected(uint64_t SerialNumber) const;
 | 
							bool Connected(uint64_t SerialNumber) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
 | 
							inline bool SendFrame(const std::string &SerialNumber, const std::string &Payload) const {
 | 
				
			||||||
			return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
 | 
								return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool SendFrame(std::uint64_t SerialNumber, const std::string & Payload) const ;
 | 
							bool SendFrame(uint64_t SerialNumber, const std::string &Payload) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
 | 
							bool SendRadiusAuthenticationData(const std::string &SerialNumber,
 | 
				
			||||||
		bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
 | 
															  const unsigned char *buffer, std::size_t size);
 | 
				
			||||||
		bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
 | 
							bool SendRadiusAccountingData(const std::string &SerialNumber, const unsigned char *buffer,
 | 
				
			||||||
 | 
														  std::size_t size);
 | 
				
			||||||
 | 
							bool SendRadiusCoAData(const std::string &SerialNumber, const unsigned char *buffer,
 | 
				
			||||||
 | 
												   std::size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber);
 | 
							void SetSessionDetails(uint64_t connection_id, uint64_t SerialNumber);
 | 
				
			||||||
		bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
 | 
							bool EndSession(uint64_t connection_id, uint64_t serial_number);
 | 
				
			||||||
 | 
							bool EndSessionUnSafe(uint64_t session_id, uint64_t serial_number);
 | 
				
			||||||
		void SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
 | 
							void SetWebSocketTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber,
 | 
				
			||||||
		void StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
 | 
																uint64_t Interval, uint64_t Lifetime,
 | 
				
			||||||
		void SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
 | 
																const std::vector<std::string> &TelemetryTypes);
 | 
				
			||||||
		void StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
 | 
							void StopWebSocketTelemetry(uint64_t RPCID, uint64_t SerialNumber);
 | 
				
			||||||
 | 
							void SetKafkaTelemetryReporting(uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval,
 | 
				
			||||||
 | 
															uint64_t Lifetime,
 | 
				
			||||||
 | 
															const std::vector<std::string> &TelemetryTypes);
 | 
				
			||||||
 | 
							void StopKafkaTelemetry(uint64_t RPCID, uint64_t SerialNumber);
 | 
				
			||||||
		void GetTelemetryParameters(uint64_t SerialNumber, bool &TelemetryRunning,
 | 
							void GetTelemetryParameters(uint64_t SerialNumber, bool &TelemetryRunning,
 | 
				
			||||||
									uint64_t & TelemetryInterval,
 | 
														uint64_t &TelemetryInterval, uint64_t &TelemetryWebSocketTimer,
 | 
				
			||||||
									uint64_t & TelemetryWebSocketTimer,
 | 
					 | 
				
			||||||
									uint64_t &TelemetryKafkaTimer,
 | 
														uint64_t &TelemetryKafkaTimer,
 | 
				
			||||||
									uint64_t &TelemetryWebSocketCount,
 | 
														uint64_t &TelemetryWebSocketCount,
 | 
				
			||||||
									uint64_t &TelemetryKafkaCount,
 | 
														uint64_t &TelemetryKafkaCount,
 | 
				
			||||||
@@ -159,14 +169,67 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		void onGarbageCollecting(Poco::Timer &timer);
 | 
							void onGarbageCollecting(Poco::Timer &timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline void AverageDeviceStatistics( std::uint64_t & Connections, std::uint64_t & AverageConnectionTime, std::uint64_t & NumberOfConnectingDevices) const {
 | 
							inline void AverageDeviceStatistics(uint64_t &Connections, uint64_t &AverageConnectionTime,
 | 
				
			||||||
 | 
																uint64_t &NumberOfConnectingDevices) const {
 | 
				
			||||||
			Connections = NumberOfConnectedDevices_;
 | 
								Connections = NumberOfConnectedDevices_;
 | 
				
			||||||
			AverageConnectionTime = AverageDeviceConnectionTime_;
 | 
								AverageConnectionTime = AverageDeviceConnectionTime_;
 | 
				
			||||||
			NumberOfConnectingDevices = NumberOfConnectingDevices_;
 | 
								NumberOfConnectingDevices = NumberOfConnectingDevices_;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void AddRX(std::uint64_t bytes) {
 | 
				
			||||||
 | 
								std::lock_guard		G(StatsMutex_);
 | 
				
			||||||
 | 
								RX_ += bytes;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void AddTX(std::uint64_t bytes) {
 | 
				
			||||||
 | 
								std::lock_guard		G(StatsMutex_);
 | 
				
			||||||
 | 
								TX_ += bytes;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void GetTotalDataStatistics(std::uint64_t &TX, std::uint64_t &RX) const {
 | 
				
			||||||
 | 
								std::lock_guard		G(StatsMutex_);
 | 
				
			||||||
 | 
								TX = TX_;
 | 
				
			||||||
 | 
								RX = RX_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//	TOD: move to hash based map.
 | 
				
			||||||
 | 
							inline bool GetHealthDevices(std::uint64_t lowLimit, std::uint64_t  highLimit, std::vector<std::string> & SerialNumbers) {
 | 
				
			||||||
 | 
								std::lock_guard Lock(SessionMutex_);
 | 
				
			||||||
 | 
								for(const auto &connection:Sessions_) {
 | 
				
			||||||
 | 
									if(	connection.second->RawLastHealthcheck_.Sanity>=lowLimit 	&&
 | 
				
			||||||
 | 
										connection.second->RawLastHealthcheck_.Sanity<=highLimit) {
 | 
				
			||||||
 | 
										SerialNumbers.push_back(connection.second->SerialNumber_);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline bool ExtendedAttributes(const std::string &serialNumber,
 | 
				
			||||||
 | 
								bool & hasGPS,
 | 
				
			||||||
 | 
								std::uint64_t &Sanity,
 | 
				
			||||||
 | 
								std::double_t &MemoryUsed,
 | 
				
			||||||
 | 
								std::double_t &Load,
 | 
				
			||||||
 | 
								std::double_t &Temperature
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto serialNumberInt = Utils::SerialNumberToInt(serialNumber);
 | 
				
			||||||
 | 
								auto hashIndex = Utils::CalculateMacAddressHash(serialNumberInt);
 | 
				
			||||||
 | 
								std::lock_guard	G(SerialNumbersMutex_[hashIndex]);
 | 
				
			||||||
 | 
								auto session_hint = SerialNumbers_[hashIndex].find(Utils::SerialNumberToInt(serialNumber));
 | 
				
			||||||
 | 
								if(session_hint==end(SerialNumbers_[hashIndex])) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								hasGPS = session_hint->second.second->hasGPS;
 | 
				
			||||||
 | 
								Sanity = session_hint->second.second->RawLastHealthcheck_.Sanity;
 | 
				
			||||||
 | 
								MemoryUsed = session_hint->second.second->memory_used_;
 | 
				
			||||||
 | 
								Load = session_hint->second.second->cpu_load_;
 | 
				
			||||||
 | 
								Temperature = session_hint->second.second->temperature_;
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		mutable std::recursive_mutex								LocalMutex_;
 | 
							mutable std::mutex 			SessionMutex_;
 | 
				
			||||||
 | 
							mutable std::mutex			StatsMutex_;
 | 
				
			||||||
		std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
 | 
							std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
 | 
				
			||||||
		std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
 | 
							std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
 | 
				
			||||||
		Poco::Net::SocketReactor Reactor_;
 | 
							Poco::Net::SocketReactor Reactor_;
 | 
				
			||||||
@@ -178,14 +241,23 @@ namespace OpenWifi {
 | 
				
			|||||||
		bool SimulatorEnabled_ = false;
 | 
							bool SimulatorEnabled_ = false;
 | 
				
			||||||
		std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
 | 
							std::unique_ptr<AP_WS_ReactorThreadPool> Reactor_pool_;
 | 
				
			||||||
		std::atomic_bool Running_ = false;
 | 
							std::atomic_bool Running_ = false;
 | 
				
			||||||
		std::map<std::uint64_t,	std::pair<std::shared_ptr<AP_WS_Connection>,bool>>	Sessions_;
 | 
							std::map<std::uint64_t, std::shared_ptr<AP_WS_Connection>> Sessions_;
 | 
				
			||||||
		std::map<std::uint64_t, std::pair<std::uint64_t,std::shared_ptr<AP_WS_Connection>>>	SerialNumbers_;
 | 
					
 | 
				
			||||||
 | 
							using SerialNumberMap = std::map<uint64_t /* serial number */, std::pair<uint64_t /* session id*/,
 | 
				
			||||||
 | 
														 std::shared_ptr<AP_WS_Connection>>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::array<SerialNumberMap,256>			SerialNumbers_;
 | 
				
			||||||
 | 
							mutable std::array<std::mutex,256>		SerialNumbersMutex_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::atomic_bool AllowSerialNumberMismatch_ = true;
 | 
							std::atomic_bool AllowSerialNumberMismatch_ = true;
 | 
				
			||||||
		std::atomic_uint64_t MismatchDepth_ = 2;
 | 
							std::atomic_uint64_t MismatchDepth_ = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::atomic_uint64_t 										NumberOfConnectedDevices_=0;
 | 
							std::uint64_t 			NumberOfConnectedDevices_ = 0;
 | 
				
			||||||
		std::atomic_uint64_t 										AverageDeviceConnectionTime_=0;
 | 
							std::uint64_t 			AverageDeviceConnectionTime_ = 0;
 | 
				
			||||||
		std::atomic_uint64_t 										NumberOfConnectingDevices_=0;
 | 
							std::uint64_t 			NumberOfConnectingDevices_ = 0;
 | 
				
			||||||
 | 
							std::uint64_t 			SessionTimeOut_ = 10*60;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::atomic_uint64_t 	TX_=0,RX_=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
 | 
							std::vector<std::shared_ptr<AP_WS_Connection>> Garbage_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,11 +265,10 @@ namespace OpenWifi {
 | 
				
			|||||||
		Poco::Timer Timer_;
 | 
							Poco::Timer Timer_;
 | 
				
			||||||
		Poco::Thread GarbageCollector_;
 | 
							Poco::Thread GarbageCollector_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AP_WS_Server() noexcept:
 | 
							AP_WS_Server() noexcept
 | 
				
			||||||
			SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {
 | 
								: SubSystemServer("WebSocketServer", "WS-SVR", "ucentral.websocket") {}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
 | 
						inline auto AP_WS_Server() { return AP_WS_Server::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} //namespace
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,8 +4,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "CentralConfig.h"
 | 
				
			||||||
#include "nlohmann/json.hpp"
 | 
					#include "nlohmann/json.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
@@ -16,23 +22,22 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	class CapabilitiesCache {
 | 
						class CapabilitiesCache {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
		static auto instance() {
 | 
							static auto instance() {
 | 
				
			||||||
			static auto instance = new CapabilitiesCache;
 | 
								static auto instance = new CapabilitiesCache;
 | 
				
			||||||
			return instance;
 | 
								return instance;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline void Add(const std::string & DeviceType, const std::string & Platform, const std::string & FullCapabilities) {
 | 
							inline void Add(const Config::Capabilities &Caps) {
 | 
				
			||||||
			if(DeviceType.empty() || Platform.empty())
 | 
								if (Caps.Compatible().empty() || Caps.Platform().empty())
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::lock_guard G(Mutex_);
 | 
								std::lock_guard G(Mutex_);
 | 
				
			||||||
			if (!PlatformsLoaded_)
 | 
								if (!PlatformsLoaded_)
 | 
				
			||||||
				LoadPlatforms();
 | 
									LoadPlatforms();
 | 
				
			||||||
			auto P = Poco::toUpper(Platform);
 | 
								auto P = Poco::toUpper(Caps.Platform());
 | 
				
			||||||
			auto Hint = Platforms_.find(DeviceType);
 | 
								auto Hint = Platforms_.find(Caps.Compatible());
 | 
				
			||||||
			if (Hint == Platforms_.end()) {
 | 
								if (Hint == Platforms_.end()) {
 | 
				
			||||||
				Platforms_.insert(std::make_pair(DeviceType,P));
 | 
									Platforms_.insert(std::make_pair(Caps.Compatible(), P));
 | 
				
			||||||
				SavePlatforms();
 | 
									SavePlatforms();
 | 
				
			||||||
			} else if (Hint->second != P) {
 | 
								} else if (Hint->second != P) {
 | 
				
			||||||
				Hint->second = P;
 | 
									Hint->second = P;
 | 
				
			||||||
@@ -42,12 +47,14 @@ namespace OpenWifi {
 | 
				
			|||||||
			if (!CapabilitiesLoaded_)
 | 
								if (!CapabilitiesLoaded_)
 | 
				
			||||||
				LoadCapabilities();
 | 
									LoadCapabilities();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto CapHint = Capabilities_.find(DeviceType);
 | 
								auto CapHint = Capabilities_.find(Caps.Compatible());
 | 
				
			||||||
			if (CapHint == Capabilities_.end()) {
 | 
								if (CapHint == Capabilities_.end()) {
 | 
				
			||||||
				Capabilities_[DeviceType] = nlohmann::json::parse(FullCapabilities);
 | 
									auto C = nlohmann::json::parse(Caps.AsString());
 | 
				
			||||||
 | 
									C.erase("restrictions");
 | 
				
			||||||
 | 
									Capabilities_[Caps.Compatible()] = nlohmann::json::parse(Caps.AsString());
 | 
				
			||||||
				SaveCapabilities();
 | 
									SaveCapabilities();
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				CapHint->second = nlohmann::json::parse(FullCapabilities);
 | 
									CapHint->second = nlohmann::json::parse(Caps.AsString());
 | 
				
			||||||
				SaveCapabilities();
 | 
									SaveCapabilities();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -92,8 +99,9 @@ namespace OpenWifi {
 | 
				
			|||||||
		std::atomic_bool CapabilitiesLoaded_ = false;
 | 
							std::atomic_bool CapabilitiesLoaded_ = false;
 | 
				
			||||||
		std::map<std::string, std::string> Platforms_;
 | 
							std::map<std::string, std::string> Platforms_;
 | 
				
			||||||
		CapabilitiesCache_t Capabilities_;
 | 
							CapabilitiesCache_t Capabilities_;
 | 
				
			||||||
		std::string 							PlatformCacheFileName_{ MicroService::instance().DataDir()+PlatformCacheFileName };
 | 
							std::string PlatformCacheFileName_{MicroServiceDataDirectory() + PlatformCacheFileName};
 | 
				
			||||||
		std::string 							CapabilitiesCacheFileName_{ MicroService::instance().DataDir()+CapabilitiesCacheFileName };
 | 
							std::string CapabilitiesCacheFileName_{MicroServiceDataDirectory() +
 | 
				
			||||||
 | 
																   CapabilitiesCacheFileName};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline void LoadPlatforms() {
 | 
							inline void LoadPlatforms() {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
@@ -105,7 +113,6 @@ namespace OpenWifi {
 | 
				
			|||||||
					Platforms_[Type] = Platform;
 | 
										Platforms_[Type] = Platform;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			PlatformsLoaded_ = true;
 | 
								PlatformsLoaded_ = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -116,13 +123,13 @@ namespace OpenWifi {
 | 
				
			|||||||
				nlohmann::json cache(Platforms_);
 | 
									nlohmann::json cache(Platforms_);
 | 
				
			||||||
				i << cache;
 | 
									i << cache;
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline void LoadCapabilities() {
 | 
							inline void LoadCapabilities() {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				std::ifstream i(CapabilitiesCacheFileName_, std::ios_base::binary|std::ios_base::in);
 | 
									std::ifstream i(CapabilitiesCacheFileName_,
 | 
				
			||||||
 | 
													std::ios_base::binary | std::ios_base::in);
 | 
				
			||||||
				nlohmann::json cache;
 | 
									nlohmann::json cache;
 | 
				
			||||||
				i >> cache;
 | 
									i >> cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,19 +137,21 @@ namespace OpenWifi {
 | 
				
			|||||||
					Capabilities_[Type] = Caps;
 | 
										Capabilities_[Type] = Caps;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			CapabilitiesLoaded_ = true;
 | 
								CapabilitiesLoaded_ = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline void SaveCapabilities() {
 | 
							inline void SaveCapabilities() {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				std::ofstream i(CapabilitiesCacheFileName_, std::ios_base::trunc | std::ios_base::out | std::ios_base::binary );
 | 
									std::ofstream i(CapabilitiesCacheFileName_,
 | 
				
			||||||
 | 
													std::ios_base::trunc | std::ios_base::out | std::ios_base::binary);
 | 
				
			||||||
				nlohmann::json cache(Capabilities_);
 | 
									nlohmann::json cache(Capabilities_);
 | 
				
			||||||
				i << cache;
 | 
									i << cache;
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
						inline auto CapabilitiesCache() { return CapabilitiesCache::instance(); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -7,11 +7,9 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "Poco/File.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
#include "Poco/JSON/Parser.h"
 | 
					#include "Poco/JSON/Parser.h"
 | 
				
			||||||
#include "Poco/File.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "CentralConfig.h"
 | 
					#include "CentralConfig.h"
 | 
				
			||||||
#include "Daemon.h"
 | 
					#include "Daemon.h"
 | 
				
			||||||
@@ -69,11 +67,11 @@ R"lit(
 | 
				
			|||||||
      "ipv4": {
 | 
					      "ipv4": {
 | 
				
			||||||
        "addressing": "static",
 | 
					        "addressing": "static",
 | 
				
			||||||
        "dhcp": {
 | 
					        "dhcp": {
 | 
				
			||||||
          "lease-count": 10000,
 | 
					          "lease-count": 100,
 | 
				
			||||||
          "lease-first": 10,
 | 
					          "lease-first": 10,
 | 
				
			||||||
          "lease-time": "6h"
 | 
					          "lease-time": "6h"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "subnet": "192.168.1.1/16"
 | 
					        "subnet": "192.168.1.1/24"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "name": "LAN",
 | 
					      "name": "LAN",
 | 
				
			||||||
      "role": "downstream",
 | 
					      "role": "downstream",
 | 
				
			||||||
@@ -152,7 +150,8 @@ R"lit(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	void Config::SetBasicConfigFile() {
 | 
						void Config::SetBasicConfigFile() {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			Poco::File DefaultConfigFileName{MicroService::instance().DataDir() + "/default_config.json"};
 | 
								Poco::File DefaultConfigFileName{MicroService::instance().DataDir() +
 | 
				
			||||||
 | 
																 "/default_config.json"};
 | 
				
			||||||
			DefaultConfiguration_ = BasicConfig;
 | 
								DefaultConfiguration_ = BasicConfig;
 | 
				
			||||||
			std::ofstream OS(DefaultConfigFileName.path(), std::ios::binary | std::ios::trunc);
 | 
								std::ofstream OS(DefaultConfigFileName.path(), std::ios::binary | std::ios::trunc);
 | 
				
			||||||
			std::istringstream IS(DefaultConfiguration_);
 | 
								std::istringstream IS(DefaultConfiguration_);
 | 
				
			||||||
@@ -172,7 +171,8 @@ R"lit(
 | 
				
			|||||||
		if (DefaultConfiguration_.empty()) {
 | 
							if (DefaultConfiguration_.empty()) {
 | 
				
			||||||
			//	open the file
 | 
								//	open the file
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				Poco::File DefaultConfigFileName{MicroService::instance().DataDir()+"/default_config.json"};
 | 
									Poco::File DefaultConfigFileName{MicroService::instance().DataDir() +
 | 
				
			||||||
 | 
																	 "/default_config.json"};
 | 
				
			||||||
				if (!DefaultConfigFileName.exists()) {
 | 
									if (!DefaultConfigFileName.exists()) {
 | 
				
			||||||
					SetBasicConfigFile();
 | 
										SetBasicConfigFile();
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
@@ -197,10 +197,9 @@ R"lit(
 | 
				
			|||||||
			Stringifier.condense(Object, NewConfig);
 | 
								Stringifier.condense(Object, NewConfig);
 | 
				
			||||||
			Config_ = NewConfig.str();
 | 
								Config_ = NewConfig.str();
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
        }
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
        catch(const Poco::Exception &E)
 | 
								std::cout << __func__ << ": new Configuration failed with " << E.displayText()
 | 
				
			||||||
        {
 | 
										  << std::endl;
 | 
				
			||||||
            std::cout << __func__ << ": new Configuration failed with " << E.displayText() << std::endl;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -212,9 +211,7 @@ R"lit(
 | 
				
			|||||||
			if (object->has("uuid"))
 | 
								if (object->has("uuid"))
 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
        }
 | 
							} catch (...) {
 | 
				
			||||||
        catch (...)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -230,8 +227,9 @@ R"lit(
 | 
				
			|||||||
		return DefaultConfiguration_;
 | 
							return DefaultConfiguration_;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string Capabilities::Default() {
 | 
						/*    std::string Capabilities::Default() {
 | 
				
			||||||
        return std::string(R"lit({"model":{"id":"linksys,ea8300","name":"Linksys EA8300 (Dallas)"},
 | 
								return std::string(R"lit({"model":{"id":"linksys,ea8300","name":"Linksys EA8300
 | 
				
			||||||
 | 
						   (Dallas)"},
 | 
				
			||||||
							"network":{"lan":{"ifname":"eth0","protocol":"static"},"wan":{"ifname":"eth1","protocol":"dhcp"}},
 | 
												"network":{"lan":{"ifname":"eth0","protocol":"static"},"wan":{"ifname":"eth1","protocol":"dhcp"}},
 | 
				
			||||||
							"switch":{"switch0":{"enable":true,"reset":true,"ports":[{"num":0,"device":"eth0","need_tag":false,
 | 
												"switch":{"switch0":{"enable":true,"reset":true,"ports":[{"num":0,"device":"eth0","need_tag":false,
 | 
				
			||||||
							"want_untag":true},{"num":1,"role":"lan"},{"num":2,"role":"lan"},{"num":3,"role":"lan"},{"num":4,"role":"lan"}],
 | 
												"want_untag":true},{"num":1,"role":"lan"},{"num":2,"role":"lan"},{"num":3,"role":"lan"},{"num":4,"role":"lan"}],
 | 
				
			||||||
@@ -244,50 +242,34 @@ R"lit(
 | 
				
			|||||||
							"platform/soc/a800000.wifi":{"band":["5l"],"ht_capa":6639,"vht_capa":865687986,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],
 | 
												"platform/soc/a800000.wifi":{"band":["5l"],"ht_capa":6639,"vht_capa":865687986,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],
 | 
				
			||||||
							"tx_ant":3,"rx_ant":3,"channels":[36,40,44,48,52,56,60,64]}}})lit");
 | 
												"tx_ant":3,"rx_ant":3,"channels":[36,40,44,48,52,56,60,64]}}})lit");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Capabilities::Parse() {
 | 
						Capabilities::Capabilities(const Poco::JSON::Object::Ptr &Caps) {
 | 
				
			||||||
        if(Capabilities_.empty())
 | 
					 | 
				
			||||||
            Capabilities_=Default();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
            Poco::JSON::Parser parser;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto Result = parser.parse(Capabilities_);
 | 
								if (Caps->has("compatible"))
 | 
				
			||||||
            auto Objects = Result.extract<Poco::JSON::Object::Ptr>();
 | 
									Compatible_ = Caps->get("compatible").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(Objects->has("compatible"))
 | 
								if (Caps->has("model"))
 | 
				
			||||||
				Compatible_ = Objects->get("compatible").toString();
 | 
									Model_ = Caps->get("model").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(Objects->has("model"))
 | 
								if (Caps->has("platform"))
 | 
				
			||||||
				Model_ = Objects->get("model").toString();
 | 
									Platform_ = Caps->get("platform").toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(Objects->has("platform"))
 | 
								std::ostringstream OS;
 | 
				
			||||||
				Platform_ = Objects->get("platform").toString();
 | 
								Caps->stringify(OS);
 | 
				
			||||||
 | 
								AsString_ = OS.str();
 | 
				
			||||||
            Parsed_ = true ;
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch ( const Poco::Exception & E )
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
			Daemon()->logger().log(E);
 | 
								Daemon()->logger().log(E);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const std::string & Capabilities::Compatible() {
 | 
						const std::string &Capabilities::Compatible() const { return Compatible_; }
 | 
				
			||||||
		if(!Parsed_)
 | 
					 | 
				
			||||||
			Parse();
 | 
					 | 
				
			||||||
		return Compatible_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const std::string & Capabilities::Model() {
 | 
						const std::string &Capabilities::Model() const { return Model_; }
 | 
				
			||||||
		if(!Parsed_)
 | 
					 | 
				
			||||||
			Parse();
 | 
					 | 
				
			||||||
		return Model_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const std::string & Capabilities::Platform() {
 | 
						const std::string &Capabilities::Platform() const { return Platform_; }
 | 
				
			||||||
		if(!Parsed_)
 | 
					 | 
				
			||||||
			Parse();
 | 
					 | 
				
			||||||
		return Platform_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
						const std::string &Capabilities::AsString() const { return AsString_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi::Config
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,16 +8,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::Config {
 | 
					namespace OpenWifi::Config {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class Config {
 | 
						class Config {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
        explicit Config(const std::string &Config)
 | 
							explicit Config(const std::string &Config) : Config_(Config) {}
 | 
				
			||||||
        	:Config_(Config) {
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Config();
 | 
							Config();
 | 
				
			||||||
		bool SetUUID(uint64_t UUID);
 | 
							bool SetUUID(uint64_t UUID);
 | 
				
			||||||
@@ -35,32 +33,30 @@ namespace OpenWifi::Config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	class Capabilities {
 | 
						class Capabilities {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
        explicit Capabilities(std::string Caps)
 | 
							explicit Capabilities(const Poco::JSON::Object::Ptr &Caps);
 | 
				
			||||||
        :   Capabilities_(std::move(Caps))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
							/*        Capabilities()
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Capabilities()
 | 
					 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Capabilities_ = Default();
 | 
										Capabilities_ = Default();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				static std::string Default();
 | 
									static std::string Default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				[[nodiscard]] const std::string & Get() const { return Capabilities_; };
 | 
									[[nodiscard]] const std::string & Get() const { return Capabilities_; };
 | 
				
			||||||
        [[nodiscard]] const std::string & Compatible();
 | 
							*/
 | 
				
			||||||
        [[nodiscard]] const std::string & Model();
 | 
					
 | 
				
			||||||
		[[nodiscard]] const std::string & Platform();
 | 
							[[nodiscard]] const std::string &Compatible() const;
 | 
				
			||||||
 | 
							[[nodiscard]] const std::string &Model() const;
 | 
				
			||||||
 | 
							[[nodiscard]] const std::string &Platform() const;
 | 
				
			||||||
 | 
							[[nodiscard]] const std::string &AsString() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
        std::string Capabilities_;
 | 
					 | 
				
			||||||
        bool        Parsed_=false;
 | 
					 | 
				
			||||||
		std::string Compatible_;
 | 
							std::string Compatible_;
 | 
				
			||||||
		std::string Model_;
 | 
							std::string Model_;
 | 
				
			||||||
		std::string Platform_;
 | 
							std::string Platform_;
 | 
				
			||||||
 | 
							std::string AsString_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void Parse();
 | 
							void Parse();
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace OpenWifi::Config
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,14 +8,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/JSON/Parser.h"
 | 
					#include "Poco/JSON/Parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "CommandManager.h"
 | 
					 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					#include "AP_WS_Server.h"
 | 
				
			||||||
 | 
					#include "CommandManager.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
#include "framework/ow_constants.h"
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace std::chrono_literals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,38 +31,59 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				if (Resp != nullptr) {
 | 
									if (Resp != nullptr) {
 | 
				
			||||||
					const Poco::JSON::Object &Payload = Resp->Payload_;
 | 
										Poco::JSON::Object::Ptr Payload = Resp->Payload_;
 | 
				
			||||||
					const std::string &SerialNumber = Resp->SerialNumber_;
 | 
										std::string SerialNumberStr = Utils::IntToSerialNumber(Resp->SerialNumber_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					std::ostringstream SS;
 | 
										if (!Payload->has(uCentralProtocol::ID)) {
 | 
				
			||||||
					Payload.stringify(SS);
 | 
											poco_error(Logger(),
 | 
				
			||||||
 | 
													   fmt::format("({}): Invalid RPC response.", SerialNumberStr));
 | 
				
			||||||
					if (!Payload.has(uCentralProtocol::ID)) {
 | 
					 | 
				
			||||||
						poco_error(Logger(), fmt::format("({}): Invalid RPC response.", SerialNumber));
 | 
					 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						uint64_t ID = Payload.get(uCentralProtocol::ID);
 | 
											uint64_t ID = Payload->get(uCentralProtocol::ID);
 | 
				
			||||||
						poco_debug(Logger(),fmt::format("({}): Processing {} response.", SerialNumber, ID));
 | 
					 | 
				
			||||||
						if (ID > 1) {
 | 
											if (ID > 1) {
 | 
				
			||||||
 | 
												poco_debug(Logger(), fmt::format("({}): Processing {} response.",
 | 
				
			||||||
 | 
																				 SerialNumberStr, ID));
 | 
				
			||||||
							std::lock_guard Lock(LocalMutex_);
 | 
												std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
							auto RPC = OutStandingRequests_.find(ID);
 | 
												auto RPC = OutStandingRequests_.find(ID);
 | 
				
			||||||
							if (RPC == OutStandingRequests_.end() ||
 | 
												if (RPC == OutStandingRequests_.end()) {
 | 
				
			||||||
								RPC->second.SerialNumber !=
 | 
													//								std::cout << __LINE__ << std::endl;
 | 
				
			||||||
									Utils::SerialNumberToInt(Resp->SerialNumber_)) {
 | 
													poco_debug(Logger(), fmt::format("({}): RPC {} cannot be found.",
 | 
				
			||||||
								poco_debug(Logger(),
 | 
																					 SerialNumberStr, ID));
 | 
				
			||||||
									fmt::format("({}): RPC {} completed.", SerialNumber, ID));
 | 
												} else if (RPC->second.SerialNumber != Resp->SerialNumber_) {
 | 
				
			||||||
 | 
													//								std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
													poco_debug(
 | 
				
			||||||
 | 
														Logger(),
 | 
				
			||||||
 | 
														fmt::format("({}): RPC {} serial number mismatch {}!={}.",
 | 
				
			||||||
 | 
																	SerialNumberStr, ID, RPC->second.SerialNumber,
 | 
				
			||||||
 | 
																	Resp->SerialNumber_));
 | 
				
			||||||
							} else {
 | 
												} else {
 | 
				
			||||||
 | 
													std::shared_ptr<promise_type_t> TmpRpcEntry;
 | 
				
			||||||
								std::chrono::duration<double, std::milli> rpc_execution_time =
 | 
													std::chrono::duration<double, std::milli> rpc_execution_time =
 | 
				
			||||||
									std::chrono::high_resolution_clock::now() -
 | 
														std::chrono::high_resolution_clock::now() -
 | 
				
			||||||
									RPC->second.submitted;
 | 
														RPC->second.submitted;
 | 
				
			||||||
 | 
													//								std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
													poco_debug(Logger(),
 | 
				
			||||||
 | 
															   fmt::format("({}): Received RPC answer {}. Command={}",
 | 
				
			||||||
 | 
																		   SerialNumberStr, ID,
 | 
				
			||||||
 | 
																		   APCommands::to_string(RPC->second.Command)));
 | 
				
			||||||
 | 
													if (RPC->second.Command == APCommands::Commands::script) {
 | 
				
			||||||
 | 
														CompleteScriptCommand(RPC->second, Payload, rpc_execution_time);
 | 
				
			||||||
 | 
													} else if (RPC->second.Command == APCommands::Commands::telemetry) {
 | 
				
			||||||
 | 
														CompleteTelemetryCommand(RPC->second, Payload,
 | 
				
			||||||
 | 
																				 rpc_execution_time);
 | 
				
			||||||
 | 
													} else if (RPC->second.Command == APCommands::Commands::configure && RPC->second.rpc_entry==nullptr) {
 | 
				
			||||||
 | 
														CompleteConfigureCommand(RPC->second, Payload,
 | 
				
			||||||
 | 
																				 rpc_execution_time);
 | 
				
			||||||
 | 
													} else {
 | 
				
			||||||
									StorageService()->CommandCompleted(RPC->second.UUID, Payload,
 | 
														StorageService()->CommandCompleted(RPC->second.UUID, Payload,
 | 
				
			||||||
																	   rpc_execution_time, true);
 | 
																						   rpc_execution_time, true);
 | 
				
			||||||
									if (RPC->second.rpc_entry) {
 | 
														if (RPC->second.rpc_entry) {
 | 
				
			||||||
									RPC->second.rpc_entry->set_value(Payload);
 | 
															TmpRpcEntry = RPC->second.rpc_entry;
 | 
				
			||||||
									}
 | 
														}
 | 
				
			||||||
								poco_debug(Logger(),
 | 
														RPC->second.State = 0;
 | 
				
			||||||
									fmt::format("({}): Received RPC answer {}. Command={}",
 | 
					 | 
				
			||||||
												SerialNumber, ID, RPC->second.Command));
 | 
					 | 
				
			||||||
									OutStandingRequests_.erase(ID);
 | 
														OutStandingRequests_.erase(ID);
 | 
				
			||||||
 | 
														if (TmpRpcEntry != nullptr)
 | 
				
			||||||
 | 
															TmpRpcEntry->set_value(Payload);
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -75,20 +98,140 @@ namespace OpenWifi {
 | 
				
			|||||||
		poco_information(Logger(), "RPC Command processor stopping.");
 | 
							poco_information(Logger(), "RPC Command processor stopping.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool CommandManager::CompleteTelemetryCommand(
 | 
				
			||||||
 | 
							CommandInfo &Command, [[maybe_unused]] const Poco::JSON::Object::Ptr &Payload,
 | 
				
			||||||
 | 
							std::chrono::duration<double, std::milli> rpc_execution_time) {
 | 
				
			||||||
 | 
							std::shared_ptr<promise_type_t> TmpRpcEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Command.rpc_entry) {
 | 
				
			||||||
 | 
								TmpRpcEntry = Command.rpc_entry;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Command.State = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							OutStandingRequests_.erase(Command.Id);
 | 
				
			||||||
 | 
							if (TmpRpcEntry != nullptr)
 | 
				
			||||||
 | 
								TmpRpcEntry->set_value(Payload);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool CommandManager::CompleteConfigureCommand(
 | 
				
			||||||
 | 
							CommandInfo &Command, [[maybe_unused]] const Poco::JSON::Object::Ptr &Payload,
 | 
				
			||||||
 | 
							std::chrono::duration<double, std::milli> rpc_execution_time) {
 | 
				
			||||||
 | 
							std::shared_ptr<promise_type_t> TmpRpcEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Command.rpc_entry) {
 | 
				
			||||||
 | 
								TmpRpcEntry = Command.rpc_entry;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Payload->has("result")) {
 | 
				
			||||||
 | 
								auto Result = Payload->getObject("result");
 | 
				
			||||||
 | 
								if (Result->has("status") && Result->has("serial")) {
 | 
				
			||||||
 | 
									auto Status = Result->getObject("status");
 | 
				
			||||||
 | 
									auto SerialNumber = Result->get("serial").toString();
 | 
				
			||||||
 | 
									std::uint64_t Error = Status->get("error");
 | 
				
			||||||
 | 
									if (Error == 2) {
 | 
				
			||||||
 | 
										StorageService()->RollbackDeviceConfigurationChange(SerialNumber);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										StorageService()->CompleteDeviceConfigurationChange(SerialNumber);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								//				std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Command.State = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Command.rpc_entry) {
 | 
				
			||||||
 | 
								TmpRpcEntry = Command.rpc_entry;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							OutStandingRequests_.erase(Command.Id);
 | 
				
			||||||
 | 
							if (TmpRpcEntry != nullptr)
 | 
				
			||||||
 | 
								TmpRpcEntry->set_value(Payload);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool CommandManager::CompleteScriptCommand(
 | 
				
			||||||
 | 
							CommandInfo &Command, const Poco::JSON::Object::Ptr &Payload,
 | 
				
			||||||
 | 
							std::chrono::duration<double, std::milli> rpc_execution_time) {
 | 
				
			||||||
 | 
							bool Reply = true;
 | 
				
			||||||
 | 
							std::shared_ptr<promise_type_t> TmpRpcEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Command.rpc_entry) {
 | 
				
			||||||
 | 
								TmpRpcEntry = Command.rpc_entry;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//		std::cout << __LINE__ << "  State=" << Command.State << std::endl;
 | 
				
			||||||
 | 
							if (Command.State == 2) {
 | 
				
			||||||
 | 
								//	 look at the payload to see if we should continue or not...
 | 
				
			||||||
 | 
								if (Payload->has("result")) {
 | 
				
			||||||
 | 
									auto Result = Payload->getObject("result");
 | 
				
			||||||
 | 
									if (Result->has("status")) {
 | 
				
			||||||
 | 
										auto Status = Result->getObject("status");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										std::uint64_t Error = Status->get("error");
 | 
				
			||||||
 | 
										if (Error == 0) {
 | 
				
			||||||
 | 
											//						std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
											StorageService()->CommandCompleted(Command.UUID, Payload,
 | 
				
			||||||
 | 
																			   rpc_execution_time, true);
 | 
				
			||||||
 | 
											Command.State = 1;
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											//						std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
											StorageService()->CommandCompleted(Command.UUID, Payload,
 | 
				
			||||||
 | 
																			   rpc_execution_time, true);
 | 
				
			||||||
 | 
											std::string ErrorTxt = Status->get("result");
 | 
				
			||||||
 | 
											StorageService()->CancelWaitFile(Command.UUID, ErrorTxt);
 | 
				
			||||||
 | 
											Command.State = 0;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										//					std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									//				std::cout << __LINE__ << std::endl;
 | 
				
			||||||
 | 
									Command.State = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (Command.State == 1) {
 | 
				
			||||||
 | 
								//			std::cout << "Completing script 2 phase commit." << std::endl;
 | 
				
			||||||
 | 
								StorageService()->CommandCompleted(Command.UUID, Payload, rpc_execution_time, true);
 | 
				
			||||||
 | 
								if (Command.Deferred) {
 | 
				
			||||||
 | 
									Reply = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Command.State = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (Command.State == 0) {
 | 
				
			||||||
 | 
								//			std::cout << __LINE__ << "  State=" << Command.State << std::endl;
 | 
				
			||||||
 | 
								OutStandingRequests_.erase(Command.Id);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (Reply && TmpRpcEntry != nullptr)
 | 
				
			||||||
 | 
								TmpRpcEntry->set_value(Payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int CommandManager::Start() {
 | 
						int CommandManager::Start() {
 | 
				
			||||||
		poco_notice(Logger(), "Starting...");
 | 
							poco_notice(Logger(), "Starting...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							commandTimeOut_ = MicroServiceConfigGetInt("command.timeout", 4 * 60 * 60);
 | 
				
			||||||
 | 
							commandRetry_ = MicroServiceConfigGetInt("command.retry", 120);
 | 
				
			||||||
 | 
							janitorInterval_ = MicroServiceConfigGetInt("command.janitor", 2 * 60); //	1 hour
 | 
				
			||||||
 | 
							queueInterval_ = MicroServiceConfigGetInt("command.queue", 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ManagerThread.start(*this);
 | 
							ManagerThread.start(*this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onJanitorTimer);
 | 
							JanitorCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(
 | 
				
			||||||
 | 
								*this, &CommandManager::onJanitorTimer);
 | 
				
			||||||
		JanitorTimer_.setStartInterval(10000);
 | 
							JanitorTimer_.setStartInterval(10000);
 | 
				
			||||||
		JanitorTimer_.setPeriodicInterval(10 * 60 * 1000); // 1 hours
 | 
							JanitorTimer_.setPeriodicInterval(janitorInterval_ * 1000); // 1 hours
 | 
				
			||||||
		JanitorTimer_.start(*JanitorCallback_, MicroService::instance().TimerPool());
 | 
							JanitorTimer_.start(*JanitorCallback_, MicroServiceTimerPool());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(*this,&CommandManager::onCommandRunnerTimer);
 | 
							CommandRunnerCallback_ = std::make_unique<Poco::TimerCallback<CommandManager>>(
 | 
				
			||||||
 | 
								*this, &CommandManager::onCommandRunnerTimer);
 | 
				
			||||||
		CommandRunnerTimer_.setStartInterval(10000);
 | 
							CommandRunnerTimer_.setStartInterval(10000);
 | 
				
			||||||
		CommandRunnerTimer_.setPeriodicInterval(30 * 1000); // 1 hours
 | 
							CommandRunnerTimer_.setPeriodicInterval(queueInterval_ * 1000); // 1 hours
 | 
				
			||||||
		CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroService::instance().TimerPool());
 | 
							CommandRunnerTimer_.start(*CommandRunnerCallback_, MicroServiceTimerPool());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -113,16 +256,27 @@ namespace OpenWifi {
 | 
				
			|||||||
		std::lock_guard Lock(LocalMutex_);
 | 
							std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
		Utils::SetThreadName("cmd:janitor");
 | 
							Utils::SetThreadName("cmd:janitor");
 | 
				
			||||||
		Poco::Logger &MyLogger = Poco::Logger::get("CMD-MGR-JANITOR");
 | 
							Poco::Logger &MyLogger = Poco::Logger::get("CMD-MGR-JANITOR");
 | 
				
			||||||
 | 
							std::string TimeOutError("No response.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto now = std::chrono::high_resolution_clock::now();
 | 
							auto now = std::chrono::high_resolution_clock::now();
 | 
				
			||||||
		for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) {
 | 
							for (auto request = OutStandingRequests_.begin(); request != OutStandingRequests_.end();) {
 | 
				
			||||||
			std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
 | 
								std::chrono::duration<double, std::milli> delta = now - request->second.submitted;
 | 
				
			||||||
			if (delta > 10min) {
 | 
								if (delta > 10min) {
 | 
				
			||||||
				MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.",
 | 
									//				std::cout << __LINE__ << "  -->> " << request->second.Id <<
 | 
				
			||||||
										   request->second.UUID,
 | 
									// std::endl;
 | 
				
			||||||
										   request->second.Command,
 | 
									MyLogger.debug(fmt::format("{}: Command={} for {} Timed out.", request->second.UUID,
 | 
				
			||||||
 | 
															   APCommands::to_string(request->second.Command),
 | 
				
			||||||
										   Utils::IntToSerialNumber(request->second.SerialNumber)));
 | 
															   Utils::IntToSerialNumber(request->second.SerialNumber)));
 | 
				
			||||||
 | 
									if ((request->second.Command == APCommands::Commands::script &&
 | 
				
			||||||
 | 
										 request->second.Deferred) ||
 | 
				
			||||||
 | 
										(request->second.Command == APCommands::Commands::trace)) {
 | 
				
			||||||
 | 
										StorageService()->CancelWaitFile(request->second.UUID, TimeOutError);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									StorageService()->SetCommandTimedOut(request->second.UUID);
 | 
				
			||||||
				request = OutStandingRequests_.erase(request);
 | 
									request = OutStandingRequests_.erase(request);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
 | 
									//				std::cout << __LINE__ << "  -->> " << request->second.Id <<
 | 
				
			||||||
 | 
									// std::endl;
 | 
				
			||||||
				++request;
 | 
									++request;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -132,12 +286,9 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	bool CommandManager::IsCommandRunning(const std::string &C) {
 | 
						bool CommandManager::IsCommandRunning(const std::string &C) {
 | 
				
			||||||
		std::lock_guard Lock(LocalMutex_);
 | 
							std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
		for (const auto &request : OutStandingRequests_) {
 | 
							return std::any_of(
 | 
				
			||||||
			if (request.second.UUID == C) {
 | 
								OutStandingRequests_.begin(), OutStandingRequests_.end(),
 | 
				
			||||||
				return true;
 | 
								[C](const std::pair<std::uint64_t, CommandInfo> &r) { return r.second.UUID == C; });
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
 | 
						void CommandManager::onCommandRunnerTimer([[maybe_unused]] Poco::Timer &timer) {
 | 
				
			||||||
@@ -151,26 +302,36 @@ namespace OpenWifi {
 | 
				
			|||||||
			StorageService()->RemovedExpiredCommands();
 | 
								StorageService()->RemovedExpiredCommands();
 | 
				
			||||||
			StorageService()->RemoveTimedOutCommands();
 | 
								StorageService()->RemoveTimedOutCommands();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::uint64_t offset = 0;
 | 
				
			||||||
 | 
								bool Done = false;
 | 
				
			||||||
 | 
								while (!Done) {
 | 
				
			||||||
				std::vector<GWObjects::CommandDetails> Commands;
 | 
									std::vector<GWObjects::CommandDetails> Commands;
 | 
				
			||||||
			if (StorageService()->GetReadyToExecuteCommands(0, 200, Commands)) {
 | 
									if (StorageService()->GetReadyToExecuteCommands(offset, 200, Commands)) {
 | 
				
			||||||
				poco_trace(MyLogger,fmt::format("Scheduler about to process {} commands.", Commands.size()));
 | 
										if(Commands.empty()) {
 | 
				
			||||||
 | 
											Done=true;
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										poco_trace(MyLogger, fmt::format("Scheduler about to process {} commands.",
 | 
				
			||||||
 | 
																		 Commands.size()));
 | 
				
			||||||
					for (auto &Cmd : Commands) {
 | 
										for (auto &Cmd : Commands) {
 | 
				
			||||||
						if (!Running_) {
 | 
											if (!Running_) {
 | 
				
			||||||
						poco_warning(MyLogger,"Scheduler quitting because service is stopping.");
 | 
												poco_warning(MyLogger,
 | 
				
			||||||
 | 
															 "Scheduler quitting because service is stopping.");
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					poco_trace(
 | 
											poco_trace(MyLogger,
 | 
				
			||||||
						MyLogger, fmt::format("{}: Serial={} Command={} Starting processing.",
 | 
													   fmt::format("{}: Serial={} Command={} Starting processing.",
 | 
				
			||||||
											   Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																   Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
						try {
 | 
											try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							//	Skip an already running command
 | 
												//	Skip an already running command
 | 
				
			||||||
						if(IsCommandRunning(Cmd.UUID))
 | 
												if (IsCommandRunning(Cmd.UUID)) {
 | 
				
			||||||
								continue;
 | 
													continue;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						auto now = OpenWifi::Now();
 | 
												auto now = Utils::Now();
 | 
				
			||||||
							// 2 hour timeout for commands
 | 
												// 2 hour timeout for commands
 | 
				
			||||||
						if ((now - Cmd.Submitted) > (1 * 60 * 60)) {
 | 
												if ((now - Cmd.Submitted) > commandTimeOut_) {
 | 
				
			||||||
								poco_information(
 | 
													poco_information(
 | 
				
			||||||
									MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
 | 
														MyLogger, fmt::format("{}: Serial={} Command={} has expired.",
 | 
				
			||||||
														  Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																			  Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
@@ -178,107 +339,144 @@ namespace OpenWifi {
 | 
				
			|||||||
								continue;
 | 
													continue;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if (!AP_WS_Server()->Connected(
 | 
												auto SerialNumberInt = Utils::SerialNumberToInt(Cmd.SerialNumber);
 | 
				
			||||||
								Utils::SerialNumberToInt(Cmd.SerialNumber))) {
 | 
												if (!AP_WS_Server()->Connected(SerialNumberInt)) {
 | 
				
			||||||
								poco_trace(
 | 
													poco_trace(
 | 
				
			||||||
									MyLogger,
 | 
														MyLogger,
 | 
				
			||||||
								fmt::format(
 | 
														fmt::format("{}: Serial={} Command={} Device is not connected.",
 | 
				
			||||||
									"{}: Serial={} Command={} Device is not connected.",
 | 
					 | 
				
			||||||
												Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																	Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
 | 
													StorageService()->SetCommandLastTry(Cmd.UUID);
 | 
				
			||||||
								continue;
 | 
													continue;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						std::string ExecutingCommand, ExecutingUUID;
 | 
												std::string ExecutingUUID;
 | 
				
			||||||
						if (CommandRunningForDevice(Utils::SerialNumberToInt(Cmd.SerialNumber),
 | 
												APCommands::Commands ExecutingCommand = APCommands::Commands::unknown;
 | 
				
			||||||
													ExecutingUUID, ExecutingCommand)) {
 | 
												if (CommandRunningForDevice(SerialNumberInt, ExecutingUUID,
 | 
				
			||||||
 | 
																			ExecutingCommand)) {
 | 
				
			||||||
								poco_trace(
 | 
													poco_trace(
 | 
				
			||||||
									MyLogger,
 | 
														MyLogger,
 | 
				
			||||||
								fmt::format(
 | 
														fmt::format("{}: Serial={} Command={} Device is already busy "
 | 
				
			||||||
									"{}: Serial={} Command={} Device is already busy with command {} (Command={})."
 | 
																	"with command {} (Command={}).",
 | 
				
			||||||
									, Cmd.UUID, Cmd.SerialNumber, Cmd.Command,ExecutingUUID, ExecutingCommand));
 | 
																	Cmd.UUID, Cmd.SerialNumber, Cmd.Command,
 | 
				
			||||||
 | 
																	ExecutingUUID,
 | 
				
			||||||
 | 
																	APCommands::to_string(ExecutingCommand)));
 | 
				
			||||||
								continue;
 | 
													continue;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							Poco::JSON::Parser P;
 | 
												Poco::JSON::Parser P;
 | 
				
			||||||
							bool Sent;
 | 
												bool Sent;
 | 
				
			||||||
						poco_information(MyLogger, fmt::format("{}: Serial={} Command={} Preparing execution.",
 | 
												poco_information(
 | 
				
			||||||
 | 
													MyLogger,
 | 
				
			||||||
 | 
													fmt::format("{}: Serial={} Command={} Preparing execution.",
 | 
				
			||||||
											Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
							auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
 | 
												auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
 | 
				
			||||||
						auto Result = PostCommandDisk(NextRPCId(), Cmd.SerialNumber, Cmd.Command,
 | 
												auto Result = PostCommandDisk(
 | 
				
			||||||
													  *Params, Cmd.UUID, Sent);
 | 
													Next_RPC_ID(), APCommands::to_apcommand(Cmd.Command.c_str()),
 | 
				
			||||||
 | 
													Cmd.SerialNumber, Cmd.Command, *Params, Cmd.UUID, Sent);
 | 
				
			||||||
							if (Sent) {
 | 
												if (Sent) {
 | 
				
			||||||
								StorageService()->SetCommandExecuted(Cmd.UUID);
 | 
													StorageService()->SetCommandExecuted(Cmd.UUID);
 | 
				
			||||||
								poco_debug(MyLogger,
 | 
													poco_debug(MyLogger,
 | 
				
			||||||
								fmt::format("{}: Serial={} Command={} Sent.",
 | 
															   fmt::format("{}: Serial={} Command={} Sent.", Cmd.UUID,
 | 
				
			||||||
									 Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																		   Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
							} else {
 | 
												} else {
 | 
				
			||||||
							poco_debug(MyLogger,
 | 
													poco_debug(
 | 
				
			||||||
 | 
														MyLogger,
 | 
				
			||||||
									fmt::format("{}: Serial={} Command={} Re-queued command.",
 | 
														fmt::format("{}: Serial={} Command={} Re-queued command.",
 | 
				
			||||||
												Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																	Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
 | 
													StorageService()->SetCommandLastTry(Cmd.UUID);
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						} catch (const Poco::Exception &E) {
 | 
											} catch (const Poco::Exception &E) {
 | 
				
			||||||
						poco_debug(MyLogger,
 | 
												poco_debug(
 | 
				
			||||||
							fmt::format("{}: Serial={} Command={} Failed. Command marked as completed.",
 | 
													MyLogger,
 | 
				
			||||||
 | 
													fmt::format(
 | 
				
			||||||
 | 
														"{}: Serial={} Command={} Failed. Command marked as completed.",
 | 
				
			||||||
									Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
														Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
							MyLogger.log(E);
 | 
												MyLogger.log(E);
 | 
				
			||||||
							StorageService()->SetCommandExecuted(Cmd.UUID);
 | 
												StorageService()->SetCommandExecuted(Cmd.UUID);
 | 
				
			||||||
						} catch (...) {
 | 
											} catch (...) {
 | 
				
			||||||
							poco_debug(MyLogger,
 | 
												poco_debug(MyLogger,
 | 
				
			||||||
							 fmt::format("{}: Serial={} Command={} Hard failure. Command marked as completed.",
 | 
														   fmt::format("{}: Serial={} Command={} Hard failure. "
 | 
				
			||||||
 | 
																	   "Command marked as completed.",
 | 
				
			||||||
												   Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
																	   Cmd.UUID, Cmd.SerialNumber, Cmd.Command));
 | 
				
			||||||
							StorageService()->SetCommandExecuted(Cmd.UUID);
 | 
												StorageService()->SetCommandExecuted(Cmd.UUID);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										offset += Commands.size();
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										Done=true;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
		} catch (Poco::Exception &E) {
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							catch (Poco::Exception &E) {
 | 
				
			||||||
			MyLogger.log(E);
 | 
								MyLogger.log(E);
 | 
				
			||||||
		} catch (...) {
 | 
							}
 | 
				
			||||||
 | 
							catch (...) {
 | 
				
			||||||
			poco_warning(MyLogger, "Exception during command processing.");
 | 
								poco_warning(MyLogger, "Exception during command processing.");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		poco_trace(MyLogger, "Scheduler done.");
 | 
							poco_trace(MyLogger, "Scheduler done.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(
 | 
						std::shared_ptr<CommandManager::promise_type_t> CommandManager::PostCommand(
 | 
				
			||||||
		uint64_t RPCID,
 | 
							uint64_t RPC_ID, APCommands::Commands Command, const std::string &SerialNumber,
 | 
				
			||||||
		const std::string &SerialNumber,
 | 
							const std::string &CommandStr, const Poco::JSON::Object &Params, const std::string &UUID,
 | 
				
			||||||
		const std::string &Command,
 | 
							bool oneway_rpc, [[maybe_unused]] bool disk_only, bool &Sent, bool rpc, bool Deferred) {
 | 
				
			||||||
		const Poco::JSON::Object &Params,
 | 
					 | 
				
			||||||
		const std::string &UUID,
 | 
					 | 
				
			||||||
		bool oneway_rpc,
 | 
					 | 
				
			||||||
		bool disk_only,
 | 
					 | 
				
			||||||
		bool & Sent) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto SerialNumberInt = Utils::SerialNumberToInt(SerialNumber);
 | 
							auto SerialNumberInt = Utils::SerialNumberToInt(SerialNumber);
 | 
				
			||||||
		Sent = false;
 | 
							Sent = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::stringstream ToSend;
 | 
							std::stringstream ToSend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		CommandInfo		Idx;
 | 
							CommandInfo CInfo;
 | 
				
			||||||
		Idx.Id = oneway_rpc ? 1 : RPCID;
 | 
							CInfo.Id = oneway_rpc ? 1 : RPC_ID;
 | 
				
			||||||
		Idx.SerialNumber = SerialNumberInt;
 | 
							CInfo.SerialNumber = SerialNumberInt;
 | 
				
			||||||
		Idx.Command = Command;
 | 
							CInfo.Command = Command;
 | 
				
			||||||
		Idx.UUID = UUID;
 | 
							CInfo.Deferred = Deferred;
 | 
				
			||||||
 | 
							CInfo.UUID = UUID;
 | 
				
			||||||
 | 
							if (Command == APCommands::Commands::script && Deferred) {
 | 
				
			||||||
 | 
								CInfo.State = 2;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								CInfo.State = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Poco::JSON::Object CompleteRPC;
 | 
							Poco::JSON::Object CompleteRPC;
 | 
				
			||||||
		CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
 | 
							CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
 | 
				
			||||||
		CompleteRPC.set(uCentralProtocol::ID, RPCID);
 | 
							CompleteRPC.set(uCentralProtocol::ID, RPC_ID);
 | 
				
			||||||
		CompleteRPC.set(uCentralProtocol::METHOD, Command);
 | 
							CompleteRPC.set(uCentralProtocol::METHOD, CommandStr);
 | 
				
			||||||
		CompleteRPC.set(uCentralProtocol::PARAMS, Params);
 | 
							CompleteRPC.set(uCentralProtocol::PARAMS, Params);
 | 
				
			||||||
		Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
 | 
							Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
 | 
				
			||||||
		Idx.rpc_entry = disk_only ? nullptr : std::make_shared<CommandManager::promise_type_t>();
 | 
							CInfo.rpc_entry = rpc ? std::make_shared<CommandManager::promise_type_t>() : nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		poco_debug(Logger(), fmt::format("{}: Sending command. ID: {}", UUID, RPCID));
 | 
							poco_debug(Logger(), fmt::format("{}: Sending command {} to {}. ID: {}", UUID, CommandStr,
 | 
				
			||||||
		if(AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())) {
 | 
															 SerialNumber, RPC_ID));
 | 
				
			||||||
 | 
							//	Do not change the order. It is possible that an RPC completes before it is entered in
 | 
				
			||||||
 | 
							// the map. So we insert it 	first, even if we may need to remove it later upon failure.
 | 
				
			||||||
		if (!oneway_rpc) {
 | 
							if (!oneway_rpc) {
 | 
				
			||||||
			std::lock_guard M(Mutex_);
 | 
								std::lock_guard M(Mutex_);
 | 
				
			||||||
				OutStandingRequests_[RPCID] = Idx;
 | 
								OutStandingRequests_[RPC_ID] = CInfo;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
			poco_debug(Logger(), fmt::format("{}: Sent command. ID: {}", UUID, RPCID));
 | 
							if (AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())) {
 | 
				
			||||||
 | 
								poco_debug(Logger(), fmt::format("{}: Sent command. ID: {}", UUID, RPC_ID));
 | 
				
			||||||
			Sent = true;
 | 
								Sent = true;
 | 
				
			||||||
			return Idx.rpc_entry;
 | 
								return CInfo.rpc_entry;
 | 
				
			||||||
 | 
							} else if (!oneway_rpc) {
 | 
				
			||||||
 | 
								std::lock_guard M(Mutex_);
 | 
				
			||||||
 | 
								OutStandingRequests_.erase(RPC_ID);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPCID));
 | 
							poco_warning(Logger(), fmt::format("{}: Failed to send command. ID: {}", UUID, RPC_ID));
 | 
				
			||||||
		return nullptr;
 | 
							return nullptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}  // namespace
 | 
					
 | 
				
			||||||
 | 
						bool CommandManager::FireAndForget(const std::string &SerialNumber, const std::string &Method, const Poco::JSON::Object &Params) {
 | 
				
			||||||
 | 
							Poco::JSON::Object CompleteRPC;
 | 
				
			||||||
 | 
							CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
 | 
				
			||||||
 | 
							CompleteRPC.set(uCentralProtocol::ID, 0);
 | 
				
			||||||
 | 
							CompleteRPC.set(uCentralProtocol::METHOD, Method);
 | 
				
			||||||
 | 
							CompleteRPC.set(uCentralProtocol::PARAMS, Params);
 | 
				
			||||||
 | 
							std::stringstream ToSend;
 | 
				
			||||||
 | 
							CompleteRPC.stringify(ToSend);
 | 
				
			||||||
 | 
							poco_debug(Logger(), fmt::format("{}: Fire and forget command {}.", SerialNumber, Method));
 | 
				
			||||||
 | 
							return AP_WS_Server()->SendFrame(SerialNumber, ToSend.str())>0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -9,127 +9,100 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
#include <future>
 | 
					#include <future>
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <shared_mutex>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerRequest.h"
 | 
					#include "Poco/Net/HTTPServerRequest.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerResponse.h"
 | 
					#include "Poco/Net/HTTPServerResponse.h"
 | 
				
			||||||
 | 
					#include "Poco/Notification.h"
 | 
				
			||||||
 | 
					#include "Poco/NotificationQueue.h"
 | 
				
			||||||
#include "Poco/Timer.h"
 | 
					#include "Poco/Timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTObjects/RESTAPI_GWobjects.h"
 | 
					#include "RESTObjects/RESTAPI_GWobjects.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class RPCResponseNotification : public Poco::Notification {
 | 
						class RPCResponseNotification : public Poco::Notification {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		RPCResponseNotification(const std::string &ser,
 | 
							RPCResponseNotification(std::uint64_t ser, Poco::JSON::Object::Ptr pl)
 | 
				
			||||||
								const Poco::JSON::Object &pl) :
 | 
								: SerialNumber_(ser), Payload_(std::move(pl)) {}
 | 
				
			||||||
 			SerialNumber_(ser),
 | 
							std::uint64_t SerialNumber_;
 | 
				
			||||||
			Payload_(pl)
 | 
							Poco::JSON::Object::Ptr Payload_;
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		std::string			SerialNumber_;
 | 
					 | 
				
			||||||
		Poco::JSON::Object	Payload_;
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	class CommandManager : public SubSystemServer, Poco::Runnable {
 | 
						class CommandManager : public SubSystemServer, Poco::Runnable {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		  	typedef Poco::JSON::Object 		objtype_t;
 | 
							using objtype_t = Poco::JSON::Object::Ptr;
 | 
				
			||||||
		  	typedef std::promise<objtype_t> promise_type_t;
 | 
							using promise_type_t = std::promise<objtype_t>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct CommandInfo {
 | 
							struct CommandInfo {
 | 
				
			||||||
			std::uint64_t Id = 0;
 | 
								std::uint64_t Id = 0;
 | 
				
			||||||
			std::uint64_t SerialNumber = 0;
 | 
								std::uint64_t SerialNumber = 0;
 | 
				
			||||||
				std::string 	Command;
 | 
								APCommands::Commands Command;
 | 
				
			||||||
			std::string UUID;
 | 
								std::string UUID;
 | 
				
			||||||
				std::chrono::time_point<std::chrono::high_resolution_clock> submitted = std::chrono::high_resolution_clock::now();
 | 
								std::uint64_t State = 1;
 | 
				
			||||||
 | 
								std::chrono::time_point<std::chrono::high_resolution_clock> submitted =
 | 
				
			||||||
 | 
									std::chrono::high_resolution_clock::now();
 | 
				
			||||||
			std::shared_ptr<promise_type_t> rpc_entry;
 | 
								std::shared_ptr<promise_type_t> rpc_entry;
 | 
				
			||||||
 | 
								bool Deferred = false;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct RPCResponse {
 | 
							struct RPCResponse {
 | 
				
			||||||
				std::string 			serialNumber;
 | 
								std::uint64_t serialNumber;
 | 
				
			||||||
				Poco::JSON::Object		payload;
 | 
								Poco::JSON::Object::Ptr payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				explicit RPCResponse(const std::string &ser, const Poco::JSON::Object &pl)
 | 
								explicit RPCResponse(std::uint64_t ser, Poco::JSON::Object::Ptr pl)
 | 
				
			||||||
					:
 | 
									: serialNumber(ser), payload(std::move(pl)) {}
 | 
				
			||||||
						serialNumber(ser),
 | 
					 | 
				
			||||||
						payload(pl) {
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int Start() override;
 | 
							int Start() override;
 | 
				
			||||||
		void Stop() override;
 | 
							void Stop() override;
 | 
				
			||||||
		void WakeUp();
 | 
							void WakeUp();
 | 
				
			||||||
			inline void PostCommandResult(const std::string &SerialNumber, const Poco::JSON::Object &Obj) {
 | 
							inline void PostCommandResult(const std::string &SerialNumber,
 | 
				
			||||||
				// RPCResponseQueue_->Write(RPCResponse{.serialNumber=SerialNumber, .payload = Obj});
 | 
														  Poco::JSON::Object::Ptr Obj) {
 | 
				
			||||||
				ResponseQueue_.enqueueNotification(new RPCResponseNotification(SerialNumber,Obj));
 | 
								ResponseQueue_.enqueueNotification(new RPCResponseNotification(
 | 
				
			||||||
 | 
									Utils::SerialNumberToInt(SerialNumber), std::move(Obj)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPCID,
 | 
							std::shared_ptr<promise_type_t> PostCommandOneWayDisk(uint64_t RPC_ID,
 | 
				
			||||||
 | 
																				  APCommands::Commands Command,
 | 
				
			||||||
															  const std::string &SerialNumber,
 | 
																				  const std::string &SerialNumber,
 | 
				
			||||||
															  const std::string &Method,
 | 
																				  const std::string &Method,
 | 
				
			||||||
															  const Poco::JSON::Object &Params,
 | 
																				  const Poco::JSON::Object &Params,
 | 
				
			||||||
				const std::string &UUID,
 | 
																				  const std::string &UUID, bool &Sent) {
 | 
				
			||||||
				bool & Sent) {
 | 
								return PostCommand(RPC_ID, Command, SerialNumber, Method, Params, UUID, true, true,
 | 
				
			||||||
					return 	PostCommand(RPCID, SerialNumber,
 | 
												   Sent, false);
 | 
				
			||||||
									Method,
 | 
					 | 
				
			||||||
									Params,
 | 
					 | 
				
			||||||
									UUID,
 | 
					 | 
				
			||||||
								   	true, true, Sent );
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::shared_ptr<promise_type_t> PostCommandDisk(
 | 
							std::shared_ptr<promise_type_t>
 | 
				
			||||||
				uint64_t RPCID,
 | 
							PostCommandDisk(uint64_t RPC_ID, APCommands::Commands Command,
 | 
				
			||||||
				const std::string &SerialNumber,
 | 
											const std::string &SerialNumber, const std::string &Method,
 | 
				
			||||||
				const std::string &Method,
 | 
											const Poco::JSON::Object &Params, const std::string &UUID, bool &Sent) {
 | 
				
			||||||
				const Poco::JSON::Object &Params,
 | 
								return PostCommand(RPC_ID, Command, SerialNumber, Method, Params, UUID, false, true,
 | 
				
			||||||
				const std::string &UUID,
 | 
												   Sent, false);
 | 
				
			||||||
				bool & Sent) {
 | 
					 | 
				
			||||||
					return 	PostCommand(RPCID,
 | 
					 | 
				
			||||||
								   SerialNumber,
 | 
					 | 
				
			||||||
								   Method,
 | 
					 | 
				
			||||||
								   Params,
 | 
					 | 
				
			||||||
								   UUID,
 | 
					 | 
				
			||||||
								   false, true, Sent  );
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::shared_ptr<promise_type_t> PostCommand(
 | 
							std::shared_ptr<promise_type_t>
 | 
				
			||||||
				uint64_t RPCID,
 | 
							PostCommand(uint64_t RPC_ID, APCommands::Commands Command, const std::string &SerialNumber,
 | 
				
			||||||
				const std::string &SerialNumber,
 | 
										const std::string &Method, const Poco::JSON::Object &Params,
 | 
				
			||||||
				const std::string &Method,
 | 
										const std::string &UUID, bool &Sent, bool rpc, bool Deferred) {
 | 
				
			||||||
				const Poco::JSON::Object &Params,
 | 
								return PostCommand(RPC_ID, Command, SerialNumber, Method, Params, UUID, false, false,
 | 
				
			||||||
				const std::string &UUID,
 | 
												   Sent, rpc, Deferred);
 | 
				
			||||||
				bool & Sent) {
 | 
					 | 
				
			||||||
					return 	PostCommand(RPCID, SerialNumber,
 | 
					 | 
				
			||||||
								   Method,
 | 
					 | 
				
			||||||
								   Params,
 | 
					 | 
				
			||||||
								   UUID,
 | 
					 | 
				
			||||||
								   false,
 | 
					 | 
				
			||||||
								   false, Sent );
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::shared_ptr<promise_type_t> PostCommandOneWay(
 | 
							std::shared_ptr<promise_type_t>
 | 
				
			||||||
				uint64_t RPCID,
 | 
							PostCommandOneWay(uint64_t RPC_ID, APCommands::Commands Command,
 | 
				
			||||||
				const std::string &SerialNumber,
 | 
											  const std::string &SerialNumber, const std::string &Method,
 | 
				
			||||||
				const std::string &Method,
 | 
											  const Poco::JSON::Object &Params, const std::string &UUID, bool &Sent) {
 | 
				
			||||||
				const Poco::JSON::Object &Params,
 | 
								return PostCommand(RPC_ID, Command, SerialNumber, Method, Params, UUID, true, false,
 | 
				
			||||||
				const std::string &UUID,
 | 
												   Sent, false);
 | 
				
			||||||
				bool & Sent) {
 | 
					 | 
				
			||||||
					return 	PostCommand(RPCID,
 | 
					 | 
				
			||||||
								   SerialNumber,
 | 
					 | 
				
			||||||
								   Method,
 | 
					 | 
				
			||||||
								   Params,
 | 
					 | 
				
			||||||
								   UUID,
 | 
					 | 
				
			||||||
								   true,
 | 
					 | 
				
			||||||
								   false, Sent  );
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool IsCommandRunning(const std::string &C);
 | 
							bool IsCommandRunning(const std::string &C);
 | 
				
			||||||
@@ -144,15 +117,15 @@ namespace OpenWifi {
 | 
				
			|||||||
		inline bool Running() const { return Running_; }
 | 
							inline bool Running() const { return Running_; }
 | 
				
			||||||
		void onJanitorTimer(Poco::Timer &timer);
 | 
							void onJanitorTimer(Poco::Timer &timer);
 | 
				
			||||||
		void onCommandRunnerTimer(Poco::Timer &timer);
 | 
							void onCommandRunnerTimer(Poco::Timer &timer);
 | 
				
			||||||
			void onRPCAnswer(bool& b);
 | 
							inline uint64_t Next_RPC_ID() { return ++Id_; }
 | 
				
			||||||
			inline uint64_t NextRPCId() { return ++Id_; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void RemovePendingCommand(std::uint64_t Id) {
 | 
							void RemovePendingCommand(std::uint64_t Id) {
 | 
				
			||||||
			std::unique_lock Lock(LocalMutex_);
 | 
								std::unique_lock Lock(LocalMutex_);
 | 
				
			||||||
			OutStandingRequests_.erase(Id);
 | 
								OutStandingRequests_.erase(Id);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			inline bool CommandRunningForDevice(std::uint64_t SerialNumber, std::string & uuid, std::string &command) {
 | 
							inline bool CommandRunningForDevice(std::uint64_t SerialNumber, std::string &uuid,
 | 
				
			||||||
 | 
																APCommands::Commands &command) {
 | 
				
			||||||
			std::lock_guard Lock(LocalMutex_);
 | 
								std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (const auto &[Request, Command] : OutStandingRequests_) {
 | 
								for (const auto &[Request, Command] : OutStandingRequests_) {
 | 
				
			||||||
@@ -167,7 +140,8 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		inline void ClearQueue(std::uint64_t SerialNumber) {
 | 
							inline void ClearQueue(std::uint64_t SerialNumber) {
 | 
				
			||||||
			std::lock_guard Lock(LocalMutex_);
 | 
								std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
				for(auto Request = OutStandingRequests_.begin(); Request != OutStandingRequests_.end() ; ) {
 | 
								for (auto Request = OutStandingRequests_.begin();
 | 
				
			||||||
 | 
									 Request != OutStandingRequests_.end();) {
 | 
				
			||||||
				if (Request->second.SerialNumber == SerialNumber)
 | 
									if (Request->second.SerialNumber == SerialNumber)
 | 
				
			||||||
					Request = OutStandingRequests_.erase(Request);
 | 
										Request = OutStandingRequests_.erase(Request);
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
@@ -175,8 +149,23 @@ namespace OpenWifi {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline void RemoveCommand(const std::string &UUID) {
 | 
				
			||||||
 | 
								std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
 | 
								for (const auto &[Id, Cmd] : OutStandingRequests_) {
 | 
				
			||||||
 | 
									if (Cmd.UUID == UUID) {
 | 
				
			||||||
 | 
										OutStandingRequests_.erase(Id);
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inline auto CommandTimeout() const { return commandTimeOut_; }
 | 
				
			||||||
 | 
							inline auto CommandRetry() const { return commandRetry_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool FireAndForget(const std::string &SerialNumber, const std::string &Method,
 | 
				
			||||||
 | 
											   const Poco::JSON::Object &Params);
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		  	mutable std::recursive_mutex			LocalMutex_;
 | 
							mutable std::mutex LocalMutex_;
 | 
				
			||||||
		std::atomic_bool Running_ = false;
 | 
							std::atomic_bool Running_ = false;
 | 
				
			||||||
		Poco::Thread ManagerThread;
 | 
							Poco::Thread ManagerThread;
 | 
				
			||||||
		std::atomic_uint64_t Id_ = 3; //	do not start @1. We ignore ID=1 & 0 is illegal..
 | 
							std::atomic_uint64_t Id_ = 3; //	do not start @1. We ignore ID=1 & 0 is illegal..
 | 
				
			||||||
@@ -186,23 +175,28 @@ namespace OpenWifi {
 | 
				
			|||||||
		Poco::Timer CommandRunnerTimer_;
 | 
							Poco::Timer CommandRunnerTimer_;
 | 
				
			||||||
		std::unique_ptr<Poco::TimerCallback<CommandManager>> CommandRunnerCallback_;
 | 
							std::unique_ptr<Poco::TimerCallback<CommandManager>> CommandRunnerCallback_;
 | 
				
			||||||
		Poco::NotificationQueue ResponseQueue_;
 | 
							Poco::NotificationQueue ResponseQueue_;
 | 
				
			||||||
 | 
							std::uint64_t commandTimeOut_ = 0;
 | 
				
			||||||
 | 
							std::uint64_t commandRetry_ = 0;
 | 
				
			||||||
 | 
							std::uint64_t janitorInterval_ = 0;
 | 
				
			||||||
 | 
							std::uint64_t queueInterval_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::shared_ptr<promise_type_t> PostCommand(
 | 
							std::shared_ptr<promise_type_t>
 | 
				
			||||||
				uint64_t RPCID,
 | 
							PostCommand(uint64_t RPCID, APCommands::Commands Command, const std::string &SerialNumber,
 | 
				
			||||||
				const std::string &SerialNumber,
 | 
										const std::string &Method, const Poco::JSON::Object &Params,
 | 
				
			||||||
				const std::string &Method,
 | 
										const std::string &UUID, bool oneway_rpc, bool disk_only, bool &Sent,
 | 
				
			||||||
				const Poco::JSON::Object &Params,
 | 
										bool rpc_call, bool Deferred = false);
 | 
				
			||||||
				const std::string &UUID,
 | 
					 | 
				
			||||||
				bool oneway_rpc,
 | 
					 | 
				
			||||||
				bool disk_only,
 | 
					 | 
				
			||||||
				bool & Sent);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			CommandManager() noexcept:
 | 
							bool CompleteScriptCommand(CommandInfo &Command, const Poco::JSON::Object::Ptr &Payload,
 | 
				
			||||||
				SubSystemServer("CommandManager", "CMD-MGR", "command.manager") {
 | 
													   std::chrono::duration<double, std::milli> rpc_execution_time);
 | 
				
			||||||
			}
 | 
							bool CompleteTelemetryCommand(CommandInfo &Command, const Poco::JSON::Object::Ptr &Payload,
 | 
				
			||||||
 | 
														  std::chrono::duration<double, std::milli> rpc_execution_time);
 | 
				
			||||||
 | 
							bool CompleteConfigureCommand(CommandInfo &Command, const Poco::JSON::Object::Ptr &Payload,
 | 
				
			||||||
 | 
														  std::chrono::duration<double, std::milli> rpc_execution_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CommandManager() noexcept
 | 
				
			||||||
 | 
								: SubSystemServer("CommandManager", "CMD-MGR", "command.manager") {}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline auto CommandManager() { return CommandManager::instance(); }
 | 
						inline auto CommandManager() { return CommandManager::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,14 +5,12 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	class ConfigurationCache {
 | 
						class ConfigurationCache {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
		static ConfigurationCache &instance() {
 | 
							static ConfigurationCache &instance() {
 | 
				
			||||||
			static ConfigurationCache instance;
 | 
								static ConfigurationCache instance;
 | 
				
			||||||
			return instance;
 | 
								return instance;
 | 
				
			||||||
@@ -47,4 +45,4 @@ namespace OpenWifi {
 | 
				
			|||||||
	inline void SetCurrentConfigurationID(uint64_t SerialNumber, uint64_t ID) {
 | 
						inline void SetCurrentConfigurationID(uint64_t SerialNumber, uint64_t ID) {
 | 
				
			||||||
		return ConfigurationCache::instance().Add(SerialNumber, ID);
 | 
							return ConfigurationCache::instance().Add(SerialNumber, ID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										105
									
								
								src/Daemon.cpp
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								src/Daemon.cpp
									
									
									
									
									
								
							@@ -6,13 +6,14 @@
 | 
				
			|||||||
//	Arilia Wireless Inc.
 | 
					//	Arilia Wireless Inc.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/Util/Application.h"
 | 
					 | 
				
			||||||
#include "Poco/Util/Option.h"
 | 
					 | 
				
			||||||
#include "Poco/Environment.h"
 | 
					#include "Poco/Environment.h"
 | 
				
			||||||
#include "Poco/Net/SSLManager.h"
 | 
					#include "Poco/Net/SSLManager.h"
 | 
				
			||||||
 | 
					#include "Poco/Util/Application.h"
 | 
				
			||||||
 | 
					#include "Poco/Util/Option.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <framework/ConfigurationValidator.h>
 | 
				
			||||||
 | 
					#include <framework/UI_WebSocketClientServer.h>
 | 
				
			||||||
 | 
					#include <framework/default_device_types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					#include "AP_WS_Server.h"
 | 
				
			||||||
#include "CommandManager.h"
 | 
					#include "CommandManager.h"
 | 
				
			||||||
@@ -20,91 +21,71 @@
 | 
				
			|||||||
#include "FileUploader.h"
 | 
					#include "FileUploader.h"
 | 
				
			||||||
#include "FindCountry.h"
 | 
					#include "FindCountry.h"
 | 
				
			||||||
#include "OUIServer.h"
 | 
					#include "OUIServer.h"
 | 
				
			||||||
 | 
					#include "RADIUSSessionTracker.h"
 | 
				
			||||||
#include "RADIUS_proxy_server.h"
 | 
					#include "RADIUS_proxy_server.h"
 | 
				
			||||||
 | 
					#include "RegulatoryInfo.h"
 | 
				
			||||||
 | 
					#include "ScriptManager.h"
 | 
				
			||||||
#include "SerialNumberCache.h"
 | 
					#include "SerialNumberCache.h"
 | 
				
			||||||
 | 
					#include "SignatureMgr.h"
 | 
				
			||||||
#include "StorageArchiver.h"
 | 
					#include "StorageArchiver.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "TelemetryStream.h"
 | 
					#include "TelemetryStream.h"
 | 
				
			||||||
 | 
					#include "GenericScheduler.h"
 | 
				
			||||||
 | 
					#include "UI_GW_WebSocketNotifications.h"
 | 
				
			||||||
#include "VenueBroadcaster.h"
 | 
					#include "VenueBroadcaster.h"
 | 
				
			||||||
#include "framework/ConfigurationValidator.h"
 | 
					#include "AP_WS_ConfigAutoUpgrader.h"
 | 
				
			||||||
#include "rttys/RTTYS_server.h"
 | 
					#include "rttys/RTTYS_server.h"
 | 
				
			||||||
 | 
					#include "firmware_revision_cache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	class Daemon *Daemon::instance() {
 | 
						class Daemon *Daemon::instance() {
 | 
				
			||||||
	    static Daemon instance(vDAEMON_PROPERTIES_FILENAME,
 | 
							static Daemon instance(
 | 
				
			||||||
								   vDAEMON_ROOT_ENV_VAR,
 | 
								vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR, vDAEMON_CONFIG_ENV_VAR,
 | 
				
			||||||
								   vDAEMON_CONFIG_ENV_VAR,
 | 
								vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
 | 
				
			||||||
								   vDAEMON_APP_NAME,
 | 
								SubSystemVec{GenericScheduler(), StorageService(), SerialNumberCache(), ConfigurationValidator(),
 | 
				
			||||||
								   vDAEMON_BUS_TIMER,
 | 
									UI_WebSocketClientServer(), OUIServer(), FindCountryFromIP(),
 | 
				
			||||||
								   SubSystemVec{
 | 
									CommandManager(), FileUploader(), StorageArchiver(), TelemetryStream(),
 | 
				
			||||||
										StorageService(),
 | 
									RTTYS_server(), RADIUS_proxy_server(), VenueBroadcaster(), ScriptManager(),
 | 
				
			||||||
										SerialNumberCache(),
 | 
									SignatureManager(), AP_WS_Server(),
 | 
				
			||||||
										ConfigurationValidator(),
 | 
									RegulatoryInfo(),
 | 
				
			||||||
								   		WebSocketClientServer(),
 | 
									RADIUSSessionTracker(),
 | 
				
			||||||
										OUIServer(),
 | 
									AP_WS_ConfigAutoUpgrader(),
 | 
				
			||||||
										FindCountryFromIP(),
 | 
									FirmwareRevisionCache()
 | 
				
			||||||
//										DeviceRegistry(),
 | 
					 | 
				
			||||||
										CommandManager(),
 | 
					 | 
				
			||||||
										FileUploader(),
 | 
					 | 
				
			||||||
										StorageArchiver(),
 | 
					 | 
				
			||||||
										TelemetryStream(),
 | 
					 | 
				
			||||||
										RTTYS_server(),
 | 
					 | 
				
			||||||
								   		RADIUS_proxy_server(),
 | 
					 | 
				
			||||||
								   		VenueBroadcaster(),
 | 
					 | 
				
			||||||
									   	AP_WS_Server()
 | 
					 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		return &instance;
 | 
							return &instance;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static const std::vector<std::pair<std::string,std::string>>		DefaultDeviceTypes{
 | 
						static std::string ALBHealthCallback() {
 | 
				
			||||||
		{"cig_wf160d","AP"},
 | 
							uint64_t Connections, AverageConnectionTime, NumberOfConnectingDevices;
 | 
				
			||||||
		{"cig_wf188","AP"},
 | 
							AP_WS_Server()->AverageDeviceStatistics(Connections, AverageConnectionTime,
 | 
				
			||||||
		{"cig_wf188n","AP"},
 | 
													NumberOfConnectingDevices);
 | 
				
			||||||
		{"cig_wf194c","AP"},
 | 
							std::ostringstream os;
 | 
				
			||||||
		{"cig_wf194c4","AP"},
 | 
							os << 	"Connections: " << Connections << std::endl <<
 | 
				
			||||||
		{"edgecore_eap101","AP"},
 | 
									"ConnectingDevices: " << NumberOfConnectingDevices << std::endl <<
 | 
				
			||||||
		{"edgecore_eap102","AP"},
 | 
									"ConnectionTime: " << AverageConnectionTime << std::endl;
 | 
				
			||||||
		{"edgecore_ecs4100-12ph","AP"},
 | 
							return os.str();
 | 
				
			||||||
		{"edgecore_ecw5211","AP"},
 | 
						}
 | 
				
			||||||
		{"edgecore_ecw5410","AP"},
 | 
					 | 
				
			||||||
		{"edgecore_oap100","AP"},
 | 
					 | 
				
			||||||
		{"edgecore_spw2ac1200","SWITCH"},
 | 
					 | 
				
			||||||
		{"edgecore_spw2ac1200-lan-poe","SWITCH"},
 | 
					 | 
				
			||||||
		{"edgecore_ssw2ac2600","SWITCH"},
 | 
					 | 
				
			||||||
		{"hfcl_ion4","AP"},
 | 
					 | 
				
			||||||
		{"indio_um-305ac","AP"},
 | 
					 | 
				
			||||||
		{"linksys_e8450-ubi","AP"},
 | 
					 | 
				
			||||||
		{"linksys_ea6350","AP"},
 | 
					 | 
				
			||||||
		{"linksys_ea6350-v4","AP"},
 | 
					 | 
				
			||||||
		{"linksys_ea8300","AP"},
 | 
					 | 
				
			||||||
		{"mikrotik_nand","AP"},
 | 
					 | 
				
			||||||
		{"tp-link_ec420-g1","AP"},
 | 
					 | 
				
			||||||
		{"tplink_cpe210_v3","AP"},
 | 
					 | 
				
			||||||
		{"tplink_cpe510_v3","AP"},
 | 
					 | 
				
			||||||
		{"tplink_eap225_outdoor_v1","AP"},
 | 
					 | 
				
			||||||
		{"tplink_ec420","AP"},
 | 
					 | 
				
			||||||
		{"tplink_ex227","AP"},
 | 
					 | 
				
			||||||
		{"tplink_ex228","AP"},
 | 
					 | 
				
			||||||
		{"tplink_ex447","AP"},
 | 
					 | 
				
			||||||
		{"wallys_dr40x9","AP"}
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
 | 
						void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
 | 
				
			||||||
		AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false);
 | 
							AutoProvisioning_ = config().getBool("openwifi.autoprovisioning", false);
 | 
				
			||||||
        DeviceTypes_ = DefaultDeviceTypes;
 | 
							DeviceTypes_ = DefaultDeviceTypeList;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
 | 
							WebSocketProcessor_ = std::make_unique<GwWebSocketClient>(logger());
 | 
				
			||||||
 | 
							MicroServiceALBCallback(ALBHealthCallback);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string &Id) const {
 | 
						[[nodiscard]] std::string Daemon::IdentifyDevice(const std::string &Id) const {
 | 
				
			||||||
	    for(const auto &[DeviceType,Type]:DeviceTypes_)
 | 
							for (const auto &[DeviceType, Type] : DeviceTypes_) {
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
			if (Id == DeviceType)
 | 
								if (Id == DeviceType)
 | 
				
			||||||
				return Type;
 | 
									return Type;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return "AP";
 | 
							return "AP";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
				
			||||||
 | 
							Daemon()->PostInitialization(self);
 | 
				
			||||||
 | 
							GWWebSocketNotifications::Register();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv) {
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
	int ExitCode;
 | 
						int ExitCode;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								src/Daemon.h
									
									
									
									
									
								
							@@ -9,26 +9,17 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <cstdlib>
 | 
					#include <cstdlib>
 | 
				
			||||||
#include <vector>
 | 
					#include <iostream>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceNames.h"
 | 
				
			||||||
#include "Poco/Util/Application.h"
 | 
					 | 
				
			||||||
#include "Poco/Util/ServerApplication.h"
 | 
					 | 
				
			||||||
#include "Poco/Util/Option.h"
 | 
					 | 
				
			||||||
#include "Poco/Util/OptionSet.h"
 | 
					 | 
				
			||||||
#include "Poco/UUIDGenerator.h"
 | 
					 | 
				
			||||||
#include "Poco/ErrorHandler.h"
 | 
					 | 
				
			||||||
#include "Poco/Crypto/RSAKey.h"
 | 
					 | 
				
			||||||
#include "Poco/Crypto/CipherFactory.h"
 | 
					 | 
				
			||||||
#include "Poco/Crypto/Cipher.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Dashboard.h"
 | 
					#include "Dashboard.h"
 | 
				
			||||||
#include "framework/OpenWifiTypes.h"
 | 
					 | 
				
			||||||
#include "GwWebSocketClient.h"
 | 
					#include "GwWebSocketClient.h"
 | 
				
			||||||
 | 
					#include "framework/OpenWifiTypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,13 +31,10 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	class Daemon : public MicroService {
 | 
						class Daemon : public MicroService {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
			explicit Daemon(const std::string & PropFile,
 | 
							explicit Daemon(const std::string &PropFile, const std::string &RootEnv,
 | 
				
			||||||
							const std::string & RootEnv,
 | 
											const std::string &ConfigEnv, const std::string &AppName, uint64_t BusTimer,
 | 
				
			||||||
							const std::string & ConfigEnv,
 | 
											const SubSystemVec &SubSystems)
 | 
				
			||||||
							const std::string & AppName,
 | 
								: MicroService(PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems){};
 | 
				
			||||||
						  	uint64_t 	BusTimer,
 | 
					 | 
				
			||||||
							const SubSystemVec & SubSystems) :
 | 
					 | 
				
			||||||
				MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool AutoProvisioning() const { return AutoProvisioning_; }
 | 
							bool AutoProvisioning() const { return AutoProvisioning_; }
 | 
				
			||||||
		[[nodiscard]] std::string IdentifyDevice(const std::string &Compatible) const;
 | 
							[[nodiscard]] std::string IdentifyDevice(const std::string &Compatible) const;
 | 
				
			||||||
@@ -54,6 +42,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		inline DeviceDashboard &GetDashboard() { return DB_; }
 | 
							inline DeviceDashboard &GetDashboard() { return DB_; }
 | 
				
			||||||
		Poco::Logger &Log() { return Poco::Logger::get(AppName()); }
 | 
							Poco::Logger &Log() { return Poco::Logger::get(AppName()); }
 | 
				
			||||||
		void PostInitialization(Poco::Util::Application &self);
 | 
							void PostInitialization(Poco::Util::Application &self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		bool AutoProvisioning_ = false;
 | 
							bool AutoProvisioning_ = false;
 | 
				
			||||||
		std::vector<std::pair<std::string, std::string>> DeviceTypes_;
 | 
							std::vector<std::pair<std::string, std::string>> DeviceTypes_;
 | 
				
			||||||
@@ -62,8 +51,5 @@ namespace OpenWifi {
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline Daemon *Daemon() { return Daemon::instance(); }
 | 
						inline Daemon *Daemon() { return Daemon::instance(); }
 | 
				
			||||||
	inline void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
						void DaemonPostInitialization(Poco::Util::Application &self);
 | 
				
			||||||
		Daemon()->PostInitialization(self);
 | 
					} // namespace OpenWifi
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,16 +4,47 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "Dashboard.h"
 | 
					#include "Dashboard.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	void DeviceDashboard::Create() {
 | 
					 | 
				
			||||||
		uint64_t Now = OpenWifi::Now();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(LastRun_==0 || (Now-LastRun_)>120) {
 | 
						bool DeviceDashboard::Get(GWObjects::Dashboard &D, Poco::Logger &Logger) {
 | 
				
			||||||
			DB_.reset();
 | 
							uint64_t Now = Utils::Now();
 | 
				
			||||||
			StorageService()->AnalyzeCommands(DB_.commands);
 | 
							if (!ValidDashboard_ || LastRun_ == 0 || (Now - LastRun_) > 120) {
 | 
				
			||||||
			StorageService()->AnalyzeDevices(DB_);
 | 
								Generate(D, Logger);
 | 
				
			||||||
			LastRun_ = Now;
 | 
							} else {
 | 
				
			||||||
		}
 | 
								std::lock_guard G(DataMutex_);
 | 
				
			||||||
 | 
								D = DB_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ValidDashboard_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void DeviceDashboard::Generate(GWObjects::Dashboard &D, Poco::Logger &Logger) {
 | 
				
			||||||
 | 
							if (GeneratingDashboard_.load()) {
 | 
				
			||||||
 | 
								// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
 | 
				
			||||||
 | 
								while (GeneratingDashboard_.load()) {
 | 
				
			||||||
 | 
									Poco::Thread::trySleep(100);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								std::lock_guard G(DataMutex_);
 | 
				
			||||||
 | 
								D = DB_;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								GeneratingDashboard_ = true;
 | 
				
			||||||
 | 
								ValidDashboard_ = false;
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									// std::cout << "Generating dashboard." << std::endl;
 | 
				
			||||||
 | 
									poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
 | 
				
			||||||
 | 
									GWObjects::Dashboard NewData;
 | 
				
			||||||
 | 
									StorageService()->AnalyzeCommands(NewData.commands);
 | 
				
			||||||
 | 
									StorageService()->AnalyzeDevices(NewData);
 | 
				
			||||||
 | 
									LastRun_ = Utils::Now();
 | 
				
			||||||
 | 
									NewData.snapshot = LastRun_;
 | 
				
			||||||
 | 
									D = NewData;
 | 
				
			||||||
 | 
									std::lock_guard G(DataMutex_);
 | 
				
			||||||
 | 
									DB_ = NewData;
 | 
				
			||||||
 | 
									ValidDashboard_ = true;
 | 
				
			||||||
 | 
								} catch (...) {
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								GeneratingDashboard_ = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,19 +4,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/Logger.h"
 | 
				
			||||||
#include "RESTObjects//RESTAPI_GWobjects.h"
 | 
					#include "RESTObjects//RESTAPI_GWobjects.h"
 | 
				
			||||||
#include "framework/OpenWifiTypes.h"
 | 
					#include "framework/OpenWifiTypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	class DeviceDashboard {
 | 
						class DeviceDashboard {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
			DeviceDashboard() { DB_.reset(); }
 | 
							bool Get(GWObjects::Dashboard &D, Poco::Logger &Logger);
 | 
				
			||||||
			void Create();
 | 
					
 | 
				
			||||||
			[[nodiscard]] const GWObjects::Dashboard & Report() const { return DB_;}
 | 
					 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
 | 
							std::mutex DataMutex_;
 | 
				
			||||||
 | 
							volatile std::atomic_bool GeneratingDashboard_ = false;
 | 
				
			||||||
 | 
							volatile bool ValidDashboard_ = false;
 | 
				
			||||||
		GWObjects::Dashboard DB_;
 | 
							GWObjects::Dashboard DB_;
 | 
				
			||||||
		uint64_t LastRun_ = 0;
 | 
							uint64_t LastRun_ = 0;
 | 
				
			||||||
			inline void Reset() { DB_.reset(); }
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void Generate(GWObjects::Dashboard &D, Poco::Logger &Logger);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,264 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//	License type: BSD 3-Clause License
 | 
					 | 
				
			||||||
//	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//	Created by Stephane Bourque on 2021-03-04.
 | 
					 | 
				
			||||||
//	Arilia Wireless Inc.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					 | 
				
			||||||
#include "DeviceRegistry.h"
 | 
					 | 
				
			||||||
#include "CommandManager.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "framework/WebSocketClientNotifications.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace OpenWifi {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int DeviceRegistry::Start() {
 | 
					 | 
				
			||||||
		std::lock_guard		Guard(Mutex_);
 | 
					 | 
				
			||||||
		poco_notice(Logger(),"Starting");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ArchiverCallback_ = std::make_unique<Poco::TimerCallback<DeviceRegistry>>(*this,&DeviceRegistry::onConnectionJanitor);
 | 
					 | 
				
			||||||
		Timer_.setStartInterval(60 * 1000);
 | 
					 | 
				
			||||||
		Timer_.setPeriodicInterval(20 * 1000); // every minute
 | 
					 | 
				
			||||||
		Timer_.start(*ArchiverCallback_, MicroService::instance().TimerPool());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void DeviceRegistry::Stop() {
 | 
					 | 
				
			||||||
		poco_notice(Logger(),"Stopping...");
 | 
					 | 
				
			||||||
		std::lock_guard		Guard(Mutex_);
 | 
					 | 
				
			||||||
		Timer_.stop();
 | 
					 | 
				
			||||||
		poco_notice(Logger(),"Stopped...");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::onConnectionJanitor([[maybe_unused]] Poco::Timer &timer) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		static std::uint64_t last_log = OpenWifi::Now();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::shared_lock Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		NumberOfConnectedDevices_ = 0;
 | 
					 | 
				
			||||||
		NumberOfConnectingDevices_ = 0;
 | 
					 | 
				
			||||||
		AverageDeviceConnectionTime_ = 0;
 | 
					 | 
				
			||||||
		std::uint64_t	total_connected_time=0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto now = OpenWifi::Now();
 | 
					 | 
				
			||||||
		for (auto connection=SerialNumbers_.begin(); connection!=SerialNumbers_.end();) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(connection->second.second== nullptr) {
 | 
					 | 
				
			||||||
				connection++;
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (connection->second.second->State_.Connected) {
 | 
					 | 
				
			||||||
				NumberOfConnectedDevices_++;
 | 
					 | 
				
			||||||
				total_connected_time += (now - connection->second.second->State_.started);
 | 
					 | 
				
			||||||
				connection++;
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				NumberOfConnectingDevices_++;
 | 
					 | 
				
			||||||
				connection++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		AverageDeviceConnectionTime_ = (NumberOfConnectedDevices_!=0) ? total_connected_time/NumberOfConnectedDevices_ : 0;
 | 
					 | 
				
			||||||
		if((now-last_log)>120) {
 | 
					 | 
				
			||||||
			last_log = now;
 | 
					 | 
				
			||||||
			poco_information(Logger(),
 | 
					 | 
				
			||||||
				fmt::format("Active AP connections: {} Connecting: {} Average connection time: {} seconds",
 | 
					 | 
				
			||||||
							NumberOfConnectedDevices_, NumberOfConnectingDevices_, AverageDeviceConnectionTime_));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		WebSocketClientNotificationNumberOfConnections(NumberOfConnectedDevices_,
 | 
					 | 
				
			||||||
													   AverageDeviceConnectionTime_,
 | 
					 | 
				
			||||||
													   NumberOfConnectingDevices_);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool DeviceRegistry::GetStatistics(uint64_t SerialNumber, std::string & Statistics) const {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
        auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
        if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		Statistics = Device->second.second->LastStats_;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool DeviceRegistry::GetState(uint64_t SerialNumber, GWObjects::ConnectionState & State) const {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
        auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
        if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		State = Device->second.second->State_;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool DeviceRegistry::GetHealthcheck(uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device == SerialNumbers_.end() || Device->second.second==nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		CheckData = Device->second.second->LastHealthcheck_;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool DeviceRegistry::EndSession(std::uint64_t connection_id, std::uint64_t serial_number) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_lock G(LocalMutex_);
 | 
					 | 
				
			||||||
		auto Connection = SerialNumbers_.find(serial_number);
 | 
					 | 
				
			||||||
		if (Connection == end(SerialNumbers_)) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (Connection->second.first != connection_id) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		SerialNumbers_.erase(Connection);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber) {
 | 
					 | 
				
			||||||
		auto Connection = AP_WS_Server()->FindConnection(connection_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(Connection== nullptr)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_lock	G(LocalMutex_);
 | 
					 | 
				
			||||||
		auto CurrentSerialNumber = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(	(CurrentSerialNumber==SerialNumbers_.end())	||
 | 
					 | 
				
			||||||
			(CurrentSerialNumber->second.first<connection_id)) {
 | 
					 | 
				
			||||||
			SerialNumbers_[SerialNumber] = std::make_pair(connection_id, Connection);
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool DeviceRegistry::Connected(uint64_t SerialNumber) const {
 | 
					 | 
				
			||||||
		std::shared_lock Guard(LocalMutex_);
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return  Device->second.second->State_.Connected;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool DeviceRegistry::SendFrame(uint64_t SerialNumber, const std::string & Payload) const {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			// std::cout << "Device connection pointer: " << (std::uint64_t) Device->second.second << std::endl;
 | 
					 | 
				
			||||||
			return Device->second.second->Send(Payload);
 | 
					 | 
				
			||||||
		} catch (...) {
 | 
					 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendFrame: Could not send data to device '{}'", Utils::IntToSerialNumber(SerialNumber)));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		Device->second.second->StopWebSocketTelemetry(RPCID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second==nullptr)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		Device->second.second->SetWebSocketTelemetryReporting(RPCID, Interval, Lifetime);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		Device->second.second->SetKafkaTelemetryReporting(RPCID, Interval, Lifetime);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==end(SerialNumbers_) || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		Device->second.second->StopKafkaTelemetry(RPCID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void DeviceRegistry::GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryInterval,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryWebSocketTimer,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryKafkaTimer,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryWebSocketCount,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryKafkaCount,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryWebSocketPackets,
 | 
					 | 
				
			||||||
								uint64_t & TelemetryKafkaPackets) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto Device = SerialNumbers_.find(SerialNumber);
 | 
					 | 
				
			||||||
		if(Device==end(SerialNumbers_)|| Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		Device->second.second->GetTelemetryParameters(TelemetryRunning,
 | 
					 | 
				
			||||||
													  TelemetryInterval,
 | 
					 | 
				
			||||||
													  TelemetryWebSocketTimer,
 | 
					 | 
				
			||||||
													  TelemetryKafkaTimer,
 | 
					 | 
				
			||||||
													  TelemetryWebSocketCount,
 | 
					 | 
				
			||||||
													  TelemetryKafkaCount,
 | 
					 | 
				
			||||||
													  TelemetryWebSocketPackets,
 | 
					 | 
				
			||||||
													  TelemetryKafkaPackets);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool DeviceRegistry::SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
		auto Device = 		SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
 | 
					 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			return Device->second.second->SendRadiusAccountingData(buffer,size);
 | 
					 | 
				
			||||||
		} catch (...) {
 | 
					 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool DeviceRegistry::SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
		auto Device = 		SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
 | 
					 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			return Device->second.second->SendRadiusAuthenticationData(buffer,size);
 | 
					 | 
				
			||||||
		} catch (...) {
 | 
					 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendRadiusAuthenticationData: Could not send data to device '{}'", SerialNumber));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool DeviceRegistry::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
 | 
					 | 
				
			||||||
		std::shared_lock	Guard(LocalMutex_);
 | 
					 | 
				
			||||||
		auto Device = 		SerialNumbers_.find(Utils::SerialNumberToInt(SerialNumber));
 | 
					 | 
				
			||||||
		if(Device==SerialNumbers_.end() || Device->second.second== nullptr)
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			return Device->second.second->SendRadiusCoAData(buffer,size);
 | 
					 | 
				
			||||||
		} catch (...) {
 | 
					 | 
				
			||||||
			poco_debug(Logger(),fmt::format(": SendRadiusCoAData: Could not send data to device '{}'", SerialNumber));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
@@ -1,104 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//	License type: BSD 3-Clause License
 | 
					 | 
				
			||||||
//	License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//	Created by Stephane Bourque on 2021-03-04.
 | 
					 | 
				
			||||||
//	Arilia Wireless Inc.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <shared_mutex>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					 | 
				
			||||||
#include "Poco/Timer.h"
 | 
					 | 
				
			||||||
#include "RESTObjects//RESTAPI_GWobjects.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace OpenWifi {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	class AP_WS_Connection;
 | 
					 | 
				
			||||||
    class DeviceRegistry : public SubSystemServer {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		DeviceRegistry() noexcept:
 | 
					 | 
				
			||||||
			SubSystemServer("DeviceRegistry", "DevStatus", "devicestatus") {
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static auto instance() {
 | 
					 | 
				
			||||||
            static auto instance_ = new DeviceRegistry;
 | 
					 | 
				
			||||||
            return instance_;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int Start() override;
 | 
					 | 
				
			||||||
		void Stop() override;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		inline bool GetStatistics(const std::string &SerialNumber, std::string & Statistics) const {
 | 
					 | 
				
			||||||
			return GetStatistics(Utils::SerialNumberToInt(SerialNumber),Statistics);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		bool GetStatistics(std::uint64_t SerialNumber, std::string & Statistics) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		inline bool GetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) const {
 | 
					 | 
				
			||||||
			return GetState(Utils::SerialNumberToInt(SerialNumber), State);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		bool GetState(std::uint64_t SerialNumber, GWObjects::ConnectionState & State) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		inline bool GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) const {
 | 
					 | 
				
			||||||
			return GetHealthcheck(Utils::SerialNumberToInt(SerialNumber), CheckData);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		bool GetHealthcheck(std::uint64_t SerialNumber, GWObjects::HealthCheck & CheckData) const ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool Connected(uint64_t SerialNumber) const ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		inline bool SendFrame(const std::string & SerialNumber, const std::string & Payload) const {
 | 
					 | 
				
			||||||
			return SendFrame(Utils::SerialNumberToInt(SerialNumber), Payload);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool SendFrame(std::uint64_t SerialNumber, const std::string & Payload) const ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
 | 
					 | 
				
			||||||
		bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
 | 
					 | 
				
			||||||
		bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		void SetSessionDetails(std::uint64_t connection_id, uint64_t SerialNumber);
 | 
					 | 
				
			||||||
		bool EndSession(std::uint64_t connection_id, std::uint64_t serial_number);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		void SetWebSocketTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
 | 
					 | 
				
			||||||
		void StopWebSocketTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
 | 
					 | 
				
			||||||
		void SetKafkaTelemetryReporting(std::uint64_t RPCID, uint64_t SerialNumber, uint64_t Interval, uint64_t Lifetime);
 | 
					 | 
				
			||||||
		void StopKafkaTelemetry(std::uint64_t RPCID, uint64_t SerialNumber);
 | 
					 | 
				
			||||||
		void GetTelemetryParameters(uint64_t SerialNumber , bool & TelemetryRunning,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryInterval,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryWebSocketTimer,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryKafkaTimer,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryWebSocketCount,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryKafkaCount,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryWebSocketPackets,
 | 
					 | 
				
			||||||
									uint64_t & TelemetryKafkaPackets);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		void onConnectionJanitor(Poco::Timer & timer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		inline void AverageDeviceStatistics( std::uint64_t & Connections, std::uint64_t & AverageConnectionTime, std::uint64_t & NumberOfConnectingDevices) const {
 | 
					 | 
				
			||||||
			Connections = NumberOfConnectedDevices_;
 | 
					 | 
				
			||||||
			AverageConnectionTime = AverageDeviceConnectionTime_;
 | 
					 | 
				
			||||||
			NumberOfConnectingDevices = NumberOfConnectingDevices_;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  private:
 | 
					 | 
				
			||||||
		mutable std::shared_mutex									LocalMutex_;
 | 
					 | 
				
			||||||
		std::map<std::uint64_t, std::pair<std::uint64_t,std::shared_ptr<AP_WS_Connection>>>	SerialNumbers_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::unique_ptr<Poco::TimerCallback<DeviceRegistry>>   ArchiverCallback_;
 | 
					 | 
				
			||||||
		Poco::Timer                     		Timer_;
 | 
					 | 
				
			||||||
		Poco::Thread							ConnectionJanitor_;
 | 
					 | 
				
			||||||
		std::atomic_uint64_t 					NumberOfConnectedDevices_=0;
 | 
					 | 
				
			||||||
		std::atomic_uint64_t 					AverageDeviceConnectionTime_=0;
 | 
					 | 
				
			||||||
		std::atomic_uint64_t 					NumberOfConnectingDevices_=0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inline auto DeviceRegistry() { return DeviceRegistry::instance(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -8,20 +8,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "Poco/CountingStream.h"
 | 
				
			||||||
 | 
					#include "Poco/DynamicAny.h"
 | 
				
			||||||
 | 
					#include "Poco/Exception.h"
 | 
				
			||||||
 | 
					#include "Poco/File.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerParams.h"
 | 
					#include "Poco/Net/HTTPServerParams.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerResponse.h"
 | 
					#include "Poco/Net/HTTPServerResponse.h"
 | 
				
			||||||
#include "Poco/DynamicAny.h"
 | 
					 | 
				
			||||||
#include "Poco/Net/PartHandler.h"
 | 
					 | 
				
			||||||
#include "Poco/Net/MessageHeader.h"
 | 
					#include "Poco/Net/MessageHeader.h"
 | 
				
			||||||
#include "Poco/Net/MultipartReader.h"
 | 
					#include "Poco/Net/MultipartReader.h"
 | 
				
			||||||
#include "Poco/CountingStream.h"
 | 
					#include "Poco/Net/PartHandler.h"
 | 
				
			||||||
#include "Poco/StreamCopier.h"
 | 
					#include "Poco/StreamCopier.h"
 | 
				
			||||||
#include "Poco/Exception.h"
 | 
					#include "Poco/StringTokenizer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "FileUploader.h"
 | 
					#include "FileUploader.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +35,7 @@ namespace OpenWifi {
 | 
				
			|||||||
	int FileUploader::Start() {
 | 
						int FileUploader::Start() {
 | 
				
			||||||
		poco_notice(Logger(), "Starting.");
 | 
							poco_notice(Logger(), "Starting.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::File UploadsDir(MicroService::instance().ConfigPath("openwifi.fileuploader.path","/tmp"));
 | 
							Poco::File UploadsDir(MicroServiceConfigPath("openwifi.fileuploader.path", "/tmp"));
 | 
				
			||||||
		Path_ = UploadsDir.path();
 | 
							Path_ = UploadsDir.path();
 | 
				
			||||||
		if (!UploadsDir.exists()) {
 | 
							if (!UploadsDir.exists()) {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
@@ -42,7 +47,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (const auto &Svr : ConfigServersList_) {
 | 
							for (const auto &Svr : ConfigServersList_) {
 | 
				
			||||||
			if(MicroService::instance().NoAPISecurity()) {
 | 
								if (MicroServiceNoAPISecurity()) {
 | 
				
			||||||
				poco_notice(Logger(), fmt::format("Starting: {}:{}", Svr.Address(), Svr.Port()));
 | 
									poco_notice(Logger(), fmt::format("Starting: {}:{}", Svr.Address(), Svr.Port()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				auto Sock{Svr.CreateSocket(Logger())};
 | 
									auto Sock{Svr.CreateSocket(Logger())};
 | 
				
			||||||
@@ -54,7 +59,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				if (FullName_.empty()) {
 | 
									if (FullName_.empty()) {
 | 
				
			||||||
					std::string TmpName =
 | 
										std::string TmpName =
 | 
				
			||||||
						MicroService::instance().ConfigGetString("openwifi.fileuploader.uri", "");
 | 
											MicroServiceConfigGetString("openwifi.fileuploader.uri", "");
 | 
				
			||||||
					if (TmpName.empty()) {
 | 
										if (TmpName.empty()) {
 | 
				
			||||||
						FullName_ =
 | 
											FullName_ =
 | 
				
			||||||
							"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
 | 
												"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
 | 
				
			||||||
@@ -87,7 +92,7 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				if (FullName_.empty()) {
 | 
									if (FullName_.empty()) {
 | 
				
			||||||
					std::string TmpName =
 | 
										std::string TmpName =
 | 
				
			||||||
						MicroService::instance().ConfigGetString("openwifi.fileuploader.uri", "");
 | 
											MicroServiceConfigGetString("openwifi.fileuploader.uri", "");
 | 
				
			||||||
					if (TmpName.empty()) {
 | 
										if (TmpName.empty()) {
 | 
				
			||||||
						FullName_ =
 | 
											FullName_ =
 | 
				
			||||||
							"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
 | 
												"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
 | 
				
			||||||
@@ -104,66 +109,60 @@ namespace OpenWifi {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MaxSize_ = 1000 * MicroService::instance().ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
 | 
							MaxSize_ = 1000 * MicroServiceConfigGetInt("openwifi.fileuploader.maxsize", 10000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
 | 
						void FileUploader::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
 | 
				
			||||||
		MicroService::instance().LoadConfigurationFile();
 | 
							MicroServiceLoadConfigurationFile();
 | 
				
			||||||
		poco_information(Logger(), "Reinitializing.");
 | 
							poco_information(Logger(), "Reinitializing.");
 | 
				
			||||||
		Stop();
 | 
							Stop();
 | 
				
			||||||
		Start();
 | 
							Start();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const std::string & FileUploader::FullName() {
 | 
						const std::string &FileUploader::FullName() { return FullName_; }
 | 
				
			||||||
        return FullName_;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//  if you pass in an empty UUID, it will just clean the list and not add it.
 | 
						//  if you pass in an empty UUID, it will just clean the list and not add it.
 | 
				
			||||||
    bool FileUploader::AddUUID( const std::string & UUID) {
 | 
						bool FileUploader::AddUUID(const std::string &UUID, std::chrono::seconds WaitTimeInSeconds,
 | 
				
			||||||
 | 
												   const std::string &Type) {
 | 
				
			||||||
		std::lock_guard Guard(Mutex_);
 | 
							std::lock_guard Guard(Mutex_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t now = OpenWifi::Now();
 | 
							uint64_t now = Utils::Now();
 | 
				
			||||||
 | 
							auto Func = [now](const UploadId &I) -> bool { return (now > I.Expires); };
 | 
				
			||||||
        // remove old stuff...
 | 
							OutStandingUploads_.erase(
 | 
				
			||||||
        for(auto i=OutStandingUploads_.begin();i!=OutStandingUploads_.end();) {
 | 
								std::remove_if(OutStandingUploads_.begin(), OutStandingUploads_.end(), Func),
 | 
				
			||||||
            if ((now-i->second) > (60 * 30))
 | 
								OutStandingUploads_.end());
 | 
				
			||||||
                i = OutStandingUploads_.erase(i);
 | 
							OutStandingUploads_.emplace_back(UploadId{UUID, now + WaitTimeInSeconds.count(), Type});
 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                ++i;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(!UUID.empty())
 | 
					 | 
				
			||||||
            OutStandingUploads_[UUID] = now;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool FileUploader::ValidRequest(const std::string &UUID) {
 | 
						bool FileUploader::ValidRequest(const std::string &UUID) {
 | 
				
			||||||
		std::lock_guard Guard(Mutex_);
 | 
							std::lock_guard Guard(Mutex_);
 | 
				
			||||||
 | 
							auto Func = [UUID](const UploadId &P) -> bool { return (P.UUID == UUID); };
 | 
				
			||||||
        return OutStandingUploads_.find(UUID)!=OutStandingUploads_.end();
 | 
							return std::find_if(OutStandingUploads_.begin(), OutStandingUploads_.end(), Func) !=
 | 
				
			||||||
 | 
								   end(OutStandingUploads_);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void FileUploader::RemoveRequest(const std::string &UUID) {
 | 
						void FileUploader::RemoveRequest(const std::string &UUID) {
 | 
				
			||||||
		std::lock_guard Guard(Mutex_);
 | 
							std::lock_guard Guard(Mutex_);
 | 
				
			||||||
        OutStandingUploads_.erase(UUID);
 | 
							auto Func = [UUID](const UploadId &P) -> bool { return (P.UUID == UUID); };
 | 
				
			||||||
 | 
							OutStandingUploads_.erase(
 | 
				
			||||||
 | 
								std::remove_if(OutStandingUploads_.begin(), OutStandingUploads_.end(), Func),
 | 
				
			||||||
 | 
								OutStandingUploads_.end());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class FileUploaderPartHandler2 : public Poco::Net::PartHandler {
 | 
						class FileUploaderPartHandler2 : public Poco::Net::PartHandler {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		FileUploaderPartHandler2(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
 | 
							FileUploaderPartHandler2(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
 | 
				
			||||||
																						  Id_(std::move(Id)),
 | 
								: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
 | 
				
			||||||
																						  Logger_(Logger),
 | 
					 | 
				
			||||||
																						  OutputStream_(ofs){
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
 | 
							void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
 | 
				
			||||||
			FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
								FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
				
			||||||
			if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
								if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
				
			||||||
				std::string Disposition;
 | 
									std::string Disposition;
 | 
				
			||||||
				Poco::Net::NameValueCollection Parameters;
 | 
									Poco::Net::NameValueCollection Parameters;
 | 
				
			||||||
				Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
 | 
									Poco::Net::MessageHeader::splitParameters(
 | 
				
			||||||
 | 
										Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
 | 
				
			||||||
				Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
									Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			Poco::CountingInputStream InputStream(Stream);
 | 
								Poco::CountingInputStream InputStream(Stream);
 | 
				
			||||||
@@ -185,22 +184,20 @@ namespace OpenWifi {
 | 
				
			|||||||
		inline Poco::Logger &Logger() { return Logger_; };
 | 
							inline Poco::Logger &Logger() { return Logger_; };
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class FormRequestHandler: public Poco::Net::HTTPRequestHandler
 | 
						class FormRequestHandler : public Poco::Net::HTTPRequestHandler {
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
        explicit FormRequestHandler(std::string UUID, Poco::Logger & L):
 | 
							explicit FormRequestHandler(std::string UUID, Poco::Logger &L, const std::string &Type)
 | 
				
			||||||
            UUID_(std::move(UUID)),
 | 
								: UUID_(std::move(UUID)), Logger_(L), Type_(Type) {}
 | 
				
			||||||
            Logger_(L)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) final {
 | 
							void handleRequest(Poco::Net::HTTPServerRequest &Request,
 | 
				
			||||||
 | 
											   Poco::Net::HTTPServerResponse &Response) final {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Utils::SetThreadName("FileUploader");
 | 
								Utils::SetThreadName("FileUploader");
 | 
				
			||||||
			const auto ContentType = Request.getContentType();
 | 
								const auto ContentType = Request.getContentType();
 | 
				
			||||||
			const auto Tokens = Poco::StringTokenizer(ContentType,";",Poco::StringTokenizer::TOK_TRIM);
 | 
								const auto Tokens =
 | 
				
			||||||
 | 
									Poco::StringTokenizer(ContentType, ";", Poco::StringTokenizer::TOK_TRIM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			poco_debug(Logger(),fmt::format("{}: Preparing to upload trace file.",UUID_));
 | 
								poco_debug(Logger(), fmt::format("{}: Preparing to upload a file.", UUID_));
 | 
				
			||||||
			Poco::JSON::Object Answer;
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
@@ -225,8 +222,9 @@ namespace OpenWifi {
 | 
				
			|||||||
								Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
 | 
													Poco::StreamCopier::copyStream(Reader.stream(), FileContent);
 | 
				
			||||||
								Answer.set("filename", UUID_);
 | 
													Answer.set("filename", UUID_);
 | 
				
			||||||
								Answer.set("error", 0);
 | 
													Answer.set("error", 0);
 | 
				
			||||||
								poco_debug(Logger(),fmt::format("{}: Trace file uploaded.", UUID_));
 | 
													poco_debug(Logger(), fmt::format("{}: File uploaded.", UUID_));
 | 
				
			||||||
								StorageService()->AttachFileDataToCommand(UUID_, FileContent);
 | 
													StorageService()->AttachFileDataToCommand(UUID_, FileContent,
 | 
				
			||||||
 | 
																							  Type_);
 | 
				
			||||||
								std::ostream &ResponseStream = Response.send();
 | 
													std::ostream &ResponseStream = Response.send();
 | 
				
			||||||
								Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
 | 
													Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
 | 
				
			||||||
								return;
 | 
													return;
 | 
				
			||||||
@@ -243,11 +241,11 @@ namespace OpenWifi {
 | 
				
			|||||||
			} catch (const Poco::Exception &E) {
 | 
								} catch (const Poco::Exception &E) {
 | 
				
			||||||
				Logger().log(E);
 | 
									Logger().log(E);
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
				poco_debug(Logger(),"Exception while receiving trace file.");
 | 
									poco_debug(Logger(), "Exception while receiving uploaded file.");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			poco_debug(Logger(),fmt::format("{}: Failed to upload trace file.",UUID_));
 | 
								poco_debug(Logger(), fmt::format("{}: Failed to upload a file.", UUID_));
 | 
				
			||||||
			std::string Error{"Trace file rejected"};
 | 
								std::string Error{"File rejected"};
 | 
				
			||||||
			StorageService()->CancelWaitFile(UUID_, Error);
 | 
								StorageService()->CancelWaitFile(UUID_, Error);
 | 
				
			||||||
			Answer.set("filename", UUID_);
 | 
								Answer.set("filename", UUID_);
 | 
				
			||||||
			Answer.set("error", 13);
 | 
								Answer.set("error", 13);
 | 
				
			||||||
@@ -262,38 +260,53 @@ namespace OpenWifi {
 | 
				
			|||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::string UUID_;
 | 
							std::string UUID_;
 | 
				
			||||||
		Poco::Logger &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
 | 
							std::string Type_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
 | 
						Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(
 | 
				
			||||||
 | 
							const Poco::Net::HTTPServerRequest &Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		poco_debug(Logger(),fmt::format("REQUEST({}): {} {}", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
 | 
							poco_debug(Logger(), fmt::format("REQUEST({}): {} {}",
 | 
				
			||||||
 | 
															 Utils::FormatIPv6(Request.clientAddress().toString()),
 | 
				
			||||||
 | 
															 Request.getMethod(), Request.getURI()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (Request.getMethod() != Poco::Net::HTTPRequest::HTTP_POST ||
 | 
							if (Request.getMethod() != Poco::Net::HTTPRequest::HTTP_POST ||
 | 
				
			||||||
			Request.getURI().size() < (URI_BASE.size() + 36)) {
 | 
								Request.getURI().size() < (URI_BASE.size() + 36)) {
 | 
				
			||||||
			poco_warning(Logger(),fmt::format("ILLEGAL-REQUEST({}): {} {}. Dropped.", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
 | 
								poco_warning(Logger(),
 | 
				
			||||||
 | 
											 fmt::format("ILLEGAL-REQUEST({}): {} {}. Dropped.",
 | 
				
			||||||
 | 
														 Utils::FormatIPv6(Request.clientAddress().toString()),
 | 
				
			||||||
 | 
														 Request.getMethod(), Request.getURI()));
 | 
				
			||||||
			return nullptr;
 | 
								return nullptr;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//  The UUID should be after the /v1/upload/ part...
 | 
							//  The UUID should be after the /v1/upload/ part...
 | 
				
			||||||
		auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
 | 
							auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if( UUIDLocation != std::string::npos )
 | 
							if (UUIDLocation != std::string::npos) {
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
			auto UUID = Request.getURI().substr(UUIDLocation + URI_BASE.size());
 | 
								auto UUID = Request.getURI().substr(UUIDLocation + URI_BASE.size());
 | 
				
			||||||
            if(FileUploader()->ValidRequest(UUID))
 | 
					
 | 
				
			||||||
            {
 | 
								FileUploader::UploadId E;
 | 
				
			||||||
                //  make sure we do not allow anyone else to overwrite our file
 | 
								if (FileUploader()->Find(UUID, E)) {
 | 
				
			||||||
				FileUploader()->RemoveRequest(UUID);
 | 
									FileUploader()->RemoveRequest(UUID);
 | 
				
			||||||
                return new FormRequestHandler(UUID,Logger());
 | 
									return new FormRequestHandler(UUID, Logger(), E.Type);
 | 
				
			||||||
            }
 | 
								} else {
 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
				poco_warning(Logger(), fmt::format("Unknown UUID={}", UUID));
 | 
									poco_warning(Logger(), fmt::format("Unknown UUID={}", UUID));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nullptr;
 | 
							return nullptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool FileUploader::Find(const std::string &UUID, UploadId &V) {
 | 
				
			||||||
 | 
							std::lock_guard G(Mutex_);
 | 
				
			||||||
 | 
							for (const auto &E : OutStandingUploads_) {
 | 
				
			||||||
 | 
								if (E.UUID == UUID) {
 | 
				
			||||||
 | 
									V = E;
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void FileUploader::Stop() {
 | 
						void FileUploader::Stop() {
 | 
				
			||||||
		poco_notice(Logger(), "Stopping...");
 | 
							poco_notice(Logger(), "Stopping...");
 | 
				
			||||||
		for (const auto &svr : Servers_)
 | 
							for (const auto &svr : Servers_)
 | 
				
			||||||
@@ -302,4 +315,4 @@ namespace OpenWifi {
 | 
				
			|||||||
		poco_notice(Logger(), "Stopped...");
 | 
							poco_notice(Logger(), "Stopped...");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  //  Namespace
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -8,23 +8,29 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/Net/HTTPRequestHandler.h"
 | 
					#include "Poco/Net/HTTPRequestHandler.h"
 | 
				
			||||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
 | 
					#include "Poco/Net/HTTPRequestHandlerFactory.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServer.h"
 | 
					#include "Poco/Net/HTTPServer.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerRequest.h"
 | 
					#include "Poco/Net/HTTPServerRequest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class FileUploader : public SubSystemServer {
 | 
						class FileUploader : public SubSystemServer {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
 | 
							struct UploadId {
 | 
				
			||||||
 | 
								std::string UUID;
 | 
				
			||||||
 | 
								std::uint64_t Expires;
 | 
				
			||||||
 | 
								std::string Type;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int Start() override;
 | 
							int Start() override;
 | 
				
			||||||
		void Stop() override;
 | 
							void Stop() override;
 | 
				
			||||||
		void reinitialize(Poco::Util::Application &self) override;
 | 
							void reinitialize(Poco::Util::Application &self) override;
 | 
				
			||||||
		const std::string &FullName();
 | 
							const std::string &FullName();
 | 
				
			||||||
		bool AddUUID( const std::string & UUID);
 | 
							bool AddUUID(const std::string &UUID, std::chrono::seconds WaitTimeInSecond,
 | 
				
			||||||
 | 
										 const std::string &Type);
 | 
				
			||||||
		bool ValidRequest(const std::string &UUID);
 | 
							bool ValidRequest(const std::string &UUID);
 | 
				
			||||||
		void RemoveRequest(const std::string &UUID);
 | 
							void RemoveRequest(const std::string &UUID);
 | 
				
			||||||
		const std::string &Path() { return Path_; };
 | 
							const std::string &Path() { return Path_; };
 | 
				
			||||||
@@ -36,30 +42,30 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]] inline uint64_t MaxSize() const { return MaxSize_; }
 | 
							[[nodiscard]] inline uint64_t MaxSize() const { return MaxSize_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool Find(const std::string &UUID, UploadId &V);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
 | 
							std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
 | 
				
			||||||
		std::string FullName_;
 | 
							std::string FullName_;
 | 
				
			||||||
        std::map<std::string,uint64_t>  OutStandingUploads_;
 | 
							std::list<UploadId> OutStandingUploads_;
 | 
				
			||||||
		std::string Path_;
 | 
							std::string Path_;
 | 
				
			||||||
		uint64_t MaxSize_ = 10000000;
 | 
							uint64_t MaxSize_ = 10000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		explicit FileUploader() noexcept:
 | 
							explicit FileUploader() noexcept
 | 
				
			||||||
			SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader")
 | 
								: SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader") {}
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class FileUpLoaderRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
 | 
						class FileUpLoaderRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
        explicit FileUpLoaderRequestHandlerFactory(Poco::Logger &L) :
 | 
							explicit FileUpLoaderRequestHandlerFactory(Poco::Logger &L) : Logger_(L) {}
 | 
				
			||||||
                Logger_(L){}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
 | 
							Poco::Net::HTTPRequestHandler *
 | 
				
			||||||
 | 
							createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
 | 
				
			||||||
		inline Poco::Logger &Logger() { return Logger_; }
 | 
							inline Poco::Logger &Logger() { return Logger_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		Poco::Logger &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline auto FileUploader() { return FileUploader::instance(); }
 | 
						inline auto FileUploader() { return FileUploader::instance(); }
 | 
				
			||||||
} //   namespace
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/Net/IPAddress.h"
 | 
					#include "Poco/Net/IPAddress.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "nlohmann/json.hpp"
 | 
					#include "nlohmann/json.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
@@ -16,15 +18,14 @@ namespace OpenWifi {
 | 
				
			|||||||
		virtual bool Init() = 0;
 | 
							virtual bool Init() = 0;
 | 
				
			||||||
		virtual Poco::URI URI(const std::string &IPAddress) = 0;
 | 
							virtual Poco::URI URI(const std::string &IPAddress) = 0;
 | 
				
			||||||
		virtual std::string Country(const std::string &Response) = 0;
 | 
							virtual std::string Country(const std::string &Response) = 0;
 | 
				
			||||||
		virtual ~IPToCountryProvider() {
 | 
							virtual ~IPToCountryProvider(){};
 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class IPInfo : public IPToCountryProvider {
 | 
						class IPInfo : public IPToCountryProvider {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		static std::string Name() { return "ipinfo"; }
 | 
							static std::string Name() { return "ipinfo"; }
 | 
				
			||||||
		inline bool Init() override {
 | 
							inline bool Init() override {
 | 
				
			||||||
			Key_ = MicroService::instance().ConfigGetString("iptocountry.ipinfo.token", "");
 | 
								Key_ = MicroServiceConfigGetString("iptocountry.ipinfo.token", "");
 | 
				
			||||||
			return !Key_.empty();
 | 
								return !Key_.empty();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,21 +43,19 @@ namespace OpenWifi {
 | 
				
			|||||||
					return IPInfo["country"];
 | 
										return IPInfo["country"];
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return "";
 | 
								return "";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::string Key_;
 | 
							std::string Key_;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class IPData : public IPToCountryProvider {
 | 
						class IPData : public IPToCountryProvider {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		static std::string Name() { return "ipdata"; }
 | 
							static std::string Name() { return "ipdata"; }
 | 
				
			||||||
		inline bool Init() override {
 | 
							inline bool Init() override {
 | 
				
			||||||
			Key_ = MicroService::instance().ConfigGetString("iptocountry.ipdata.apikey", "");
 | 
								Key_ = MicroServiceConfigGetString("iptocountry.ipdata.apikey", "");
 | 
				
			||||||
			return !Key_.empty();
 | 
								return !Key_.empty();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,10 +73,10 @@ namespace OpenWifi {
 | 
				
			|||||||
					return IPInfo["country_code"];
 | 
										return IPInfo["country_code"];
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return "";
 | 
								return "";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::string Key_;
 | 
							std::string Key_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
@@ -86,7 +85,7 @@ namespace OpenWifi {
 | 
				
			|||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		static std::string Name() { return "ip2location"; }
 | 
							static std::string Name() { return "ip2location"; }
 | 
				
			||||||
		inline bool Init() override {
 | 
							inline bool Init() override {
 | 
				
			||||||
			Key_ = MicroService::instance().ConfigGetString("iptocountry.ip2location.apikey", "");
 | 
								Key_ = MicroServiceConfigGetString("iptocountry.ip2location.apikey", "");
 | 
				
			||||||
			return !Key_.empty();
 | 
								return !Key_.empty();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,10 +105,10 @@ namespace OpenWifi {
 | 
				
			|||||||
					return IPInfo["country_code"];
 | 
										return IPInfo["country_code"];
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return "";
 | 
								return "";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::string Key_;
 | 
							std::string Key_;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
@@ -135,14 +134,15 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		inline int Start() final {
 | 
							inline int Start() final {
 | 
				
			||||||
			poco_notice(Logger(), "Starting...");
 | 
								poco_notice(Logger(), "Starting...");
 | 
				
			||||||
			ProviderName_ = MicroService::instance().ConfigGetString("iptocountry.provider","");
 | 
								ProviderName_ = MicroServiceConfigGetString("iptocountry.provider", "");
 | 
				
			||||||
			if (!ProviderName_.empty()) {
 | 
								if (!ProviderName_.empty()) {
 | 
				
			||||||
				Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(ProviderName_);
 | 
									Provider_ = IPLocationProvider<IPToCountryProvider, IPInfo, IPData, IP2Location>(
 | 
				
			||||||
 | 
										ProviderName_);
 | 
				
			||||||
				if (Provider_ != nullptr) {
 | 
									if (Provider_ != nullptr) {
 | 
				
			||||||
					Enabled_ = Provider_->Init();
 | 
										Enabled_ = Provider_->Init();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			Default_ = MicroService::instance().ConfigGetString("iptocountry.default", "US");
 | 
								Default_ = MicroServiceConfigGetString("iptocountry.default", "US");
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,10 +152,8 @@ namespace OpenWifi {
 | 
				
			|||||||
			poco_notice(Logger(), "Stopped...");
 | 
								poco_notice(Logger(), "Stopped...");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]] static inline std::string ReformatAddress(const std::string & I )
 | 
							[[nodiscard]] static inline std::string ReformatAddress(const std::string &I) {
 | 
				
			||||||
		{
 | 
								if (I.substr(0, 7) == "::ffff:") {
 | 
				
			||||||
			if(I.substr(0,7) == "::ffff:")
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				std::string ip = I.substr(7);
 | 
									std::string ip = I.substr(7);
 | 
				
			||||||
				return ip;
 | 
									return ip;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -192,12 +190,9 @@ namespace OpenWifi {
 | 
				
			|||||||
		std::unique_ptr<IPToCountryProvider> Provider_;
 | 
							std::unique_ptr<IPToCountryProvider> Provider_;
 | 
				
			||||||
		std::string ProviderName_;
 | 
							std::string ProviderName_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		FindCountryFromIP() noexcept:
 | 
							FindCountryFromIP() noexcept : SubSystemServer("IpToCountry", "IPTOC-SVR", "iptocountry") {}
 | 
				
			||||||
			SubSystemServer("IpToCountry", "IPTOC-SVR", "iptocountry")
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline auto FindCountryFromIP() { return FindCountryFromIP::instance(); }
 | 
						inline auto FindCountryFromIP() { return FindCountryFromIP::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								src/GWKafkaEvents.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/GWKafkaEvents.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-02-03.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "GWKafkaEvents.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void GWKafkaEvents::Send() {
 | 
				
			||||||
 | 
							if (KafkaManager()->Enabled()) {
 | 
				
			||||||
 | 
								Poco::JSON::Object Event;
 | 
				
			||||||
 | 
								Event.set("type", type_);
 | 
				
			||||||
 | 
								Event.set("timestamp", timestamp_);
 | 
				
			||||||
 | 
								Event.set("payload", payload_);
 | 
				
			||||||
 | 
								KafkaManager()->PostMessage(KafkaTopics::DEVICE_EVENT_QUEUE, Utils::IntToSerialNumber(serialNumber_), Event);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										106
									
								
								src/GWKafkaEvents.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/GWKafkaEvents.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-02-03.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <Poco/JSON/Object.h>
 | 
				
			||||||
 | 
					#include <RESTObjects/RESTAPI_GWobjects.h>
 | 
				
			||||||
 | 
					#include <framework/KafkaManager.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class GWKafkaEvents {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							GWKafkaEvents(std::uint64_t serialNumber, const std::string &type,
 | 
				
			||||||
 | 
										  std::uint64_t timestamp)
 | 
				
			||||||
 | 
								: serialNumber_(serialNumber), type_(type), timestamp_(timestamp) {
 | 
				
			||||||
 | 
								payload_ = Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							void Send();
 | 
				
			||||||
 | 
							[[nodiscard]] inline std::uint64_t Serial() const { return serialNumber_;};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  protected:
 | 
				
			||||||
 | 
							std::uint64_t serialNumber_;
 | 
				
			||||||
 | 
							std::string type_;
 | 
				
			||||||
 | 
							std::uint64_t timestamp_ = 0;
 | 
				
			||||||
 | 
							Poco::JSON::Object::Ptr payload_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class DeviceFirmwareChangeKafkaEvent : public GWKafkaEvents {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							DeviceFirmwareChangeKafkaEvent(std::uint64_t serialNumber, std::uint64_t timestamp,
 | 
				
			||||||
 | 
														   const std::string &oldFirmware,
 | 
				
			||||||
 | 
														   const std::string &newFirmware)
 | 
				
			||||||
 | 
								: GWKafkaEvents(serialNumber, "unit.firmware_change", timestamp),
 | 
				
			||||||
 | 
								  oldFirmware_(oldFirmware), newFirmware_(newFirmware) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							~DeviceFirmwareChangeKafkaEvent() {
 | 
				
			||||||
 | 
								payload_->set("oldFirmware", oldFirmware_);
 | 
				
			||||||
 | 
								payload_->set("newFirmware", newFirmware_);
 | 
				
			||||||
 | 
								Send();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							std::string oldFirmware_, newFirmware_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class DeviceConfigurationChangeKafkaEvent : public GWKafkaEvents {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							DeviceConfigurationChangeKafkaEvent(std::uint64_t serialNumber,
 | 
				
			||||||
 | 
																std::uint64_t timestamp, const Poco::JSON::Object::Ptr config)
 | 
				
			||||||
 | 
								: GWKafkaEvents(serialNumber, "unit.configuration_change", timestamp), config_(config) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							~DeviceConfigurationChangeKafkaEvent() {
 | 
				
			||||||
 | 
								payload_->set("configuration", *config_);
 | 
				
			||||||
 | 
								Send();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							Poco::JSON::Object::Ptr config_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class DeviceBlacklistedKafkaEvent : public GWKafkaEvents {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							explicit DeviceBlacklistedKafkaEvent(std::uint64_t serialNumber,
 | 
				
			||||||
 | 
																 std::uint64_t timestamp, const std::string &reason,
 | 
				
			||||||
 | 
																 const std::string &author, std::uint64_t created,
 | 
				
			||||||
 | 
																 std::string &IP)
 | 
				
			||||||
 | 
								: GWKafkaEvents(serialNumber, "blacklisted_device", timestamp), reason_(reason),
 | 
				
			||||||
 | 
								  author_(author), created_(created), IP_(IP) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							~DeviceBlacklistedKafkaEvent() {
 | 
				
			||||||
 | 
								payload_->set("reason", reason_);
 | 
				
			||||||
 | 
								payload_->set("author", author_);
 | 
				
			||||||
 | 
								payload_->set("created", created_);
 | 
				
			||||||
 | 
								payload_->set("ipaddress", IP_);
 | 
				
			||||||
 | 
								Send();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							std::string reason_, author_;
 | 
				
			||||||
 | 
							std::uint64_t created_;
 | 
				
			||||||
 | 
							std::string IP_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class DeviceLogKafkaEvent : public GWKafkaEvents {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							explicit DeviceLogKafkaEvent( const GWObjects::DeviceLog &L)
 | 
				
			||||||
 | 
								: GWKafkaEvents(Utils::MACToInt(L.SerialNumber), "device_log", L.Recorded),
 | 
				
			||||||
 | 
								  DL_(L)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							~DeviceLogKafkaEvent() {
 | 
				
			||||||
 | 
								DL_.to_json(*payload_);
 | 
				
			||||||
 | 
								Send();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							GWObjects::DeviceLog	DL_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/GenericScheduler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/GenericScheduler.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-04-19.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "GenericScheduler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int GenericScheduler::Start() {
 | 
				
			||||||
 | 
							poco_information(Logger(),"Starting...");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void GenericScheduler::Stop() {
 | 
				
			||||||
 | 
							poco_information(Logger(),"Stopping...");
 | 
				
			||||||
 | 
							poco_information(Logger(),"Stopped...");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										37
									
								
								src/GenericScheduler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/GenericScheduler.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2023-04-19.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <framework/SubSystemServer.h>
 | 
				
			||||||
 | 
					#include <libs/Scheduler.h>
 | 
				
			||||||
 | 
					#include <Poco/Environment.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class GenericScheduler : public SubSystemServer {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static auto instance() {
 | 
				
			||||||
 | 
								static auto instance_ = new GenericScheduler;
 | 
				
			||||||
 | 
								return instance_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int Start() override;
 | 
				
			||||||
 | 
							void Stop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto & Scheduler() { return Scheduler_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							GenericScheduler() noexcept
 | 
				
			||||||
 | 
								: SubSystemServer("Scheduler", "SCHEDULER", "scheduler"),
 | 
				
			||||||
 | 
								  Scheduler_(Poco::Environment::processorCount()*2) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Bosma::Scheduler	Scheduler_;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline auto GenericScheduler() { return GenericScheduler::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -7,16 +7,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GwWebSocketClient::GwWebSocketClient(Poco::Logger &Logger):
 | 
						GwWebSocketClient::GwWebSocketClient(Poco::Logger &Logger) : Logger_(Logger) {
 | 
				
			||||||
		 Logger_(Logger){
 | 
							UI_WebSocketClientServer()->SetProcessor(this);
 | 
				
			||||||
		WebSocketClientServer()->SetProcessor(this);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GwWebSocketClient::~GwWebSocketClient() {
 | 
						GwWebSocketClient::~GwWebSocketClient() { UI_WebSocketClientServer()->SetProcessor(nullptr); }
 | 
				
			||||||
		WebSocketClientServer()->SetProcessor(nullptr);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void GwWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) {
 | 
						void GwWebSocketClient::Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer,
 | 
				
			||||||
 | 
														  bool &Done,
 | 
				
			||||||
 | 
														  [[maybe_unused]] const SecurityObjects::UserInfo &UserInfo) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			if (O->has("command")) {
 | 
								if (O->has("command")) {
 | 
				
			||||||
				auto Command = O->get("command").toString();
 | 
									auto Command = O->get("command").toString();
 | 
				
			||||||
@@ -51,16 +50,15 @@ namespace OpenWifi {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void GwWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
 | 
						void GwWebSocketClient::ws_command_exit([[maybe_unused]] const Poco::JSON::Object::Ptr &O,
 | 
				
			||||||
 | 
																bool &Done, std::string &Answer) {
 | 
				
			||||||
		Done = true;
 | 
							Done = true;
 | 
				
			||||||
		Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit";
 | 
							Answer = R"lit({ "closing" : "Goodbye! Aurevoir! Hasta la vista!" })lit";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void GwWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer) {
 | 
						void GwWebSocketClient::ws_command_invalid([[maybe_unused]] const Poco::JSON::Object::Ptr &O,
 | 
				
			||||||
 | 
																   bool &Done, std::string &Answer) {
 | 
				
			||||||
		Done = false;
 | 
							Done = false;
 | 
				
			||||||
		Answer = std::string{R"lit({ "error" : "invalid command" })lit"};
 | 
							Answer = std::string{R"lit({ "error" : "invalid command" })lit"};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -4,15 +4,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/UI_WebSocketClientServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	class GwWebSocketClient : public WebSocketClientProcessor {
 | 
						class GwWebSocketClient : public UI_WebSocketClientProcessor {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		explicit GwWebSocketClient(Poco::Logger &Logger);
 | 
							explicit GwWebSocketClient(Poco::Logger &Logger);
 | 
				
			||||||
		virtual ~GwWebSocketClient();
 | 
							virtual ~GwWebSocketClient();
 | 
				
			||||||
		virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done );
 | 
							virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done,
 | 
				
			||||||
		void ws_command_serial_number_search( const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
 | 
												   const SecurityObjects::UserInfo &UserInfo);
 | 
				
			||||||
 | 
							void ws_command_serial_number_search(const Poco::JSON::Object::Ptr &O, bool &Done,
 | 
				
			||||||
 | 
																 std::string &Answer);
 | 
				
			||||||
		void ws_command_exit(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
 | 
							void ws_command_exit(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
 | 
				
			||||||
		void ws_command_invalid(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
 | 
							void ws_command_invalid(const Poco::JSON::Object::Ptr &O, bool &Done, std::string &Answer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,4 +22,4 @@ namespace OpenWifi {
 | 
				
			|||||||
		Poco::Logger &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
		inline Poco::Logger &Logger() { return Logger_; }
 | 
							inline Poco::Logger &Logger() { return Logger_; }
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,48 +1,52 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// Created by stephane bourque on 2021-06-17.
 | 
					// Created by stephane bourque on 2021-06-17.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/File.h"
 | 
				
			||||||
 | 
					#include "Poco/StreamCopier.h"
 | 
				
			||||||
#include "Poco/String.h"
 | 
					#include "Poco/String.h"
 | 
				
			||||||
#include "Poco/StringTokenizer.h"
 | 
					#include "Poco/StringTokenizer.h"
 | 
				
			||||||
#include "Poco/URIStreamOpener.h"
 | 
					#include "Poco/URIStreamOpener.h"
 | 
				
			||||||
#include "Poco/StreamCopier.h"
 | 
					
 | 
				
			||||||
#include "Poco/File.h"
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "OUIServer.h"
 | 
					#include "OUIServer.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int OUIServer::Start() {
 | 
						int OUIServer::Start() {
 | 
				
			||||||
		Running_ = true;
 | 
							Running_ = true;
 | 
				
			||||||
		LatestOUIFileName_ =  MicroService::instance().DataDir() + "/newOUIFile.txt";
 | 
							LatestOUIFileName_ = MicroServiceDataDirectory() + "/newOUIFile.txt";
 | 
				
			||||||
		CurrentOUIFileName_ = MicroService::instance().DataDir() + "/current_oui.txt";
 | 
							CurrentOUIFileName_ = MicroServiceDataDirectory() + "/current_oui.txt";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool Recovered = false;
 | 
							bool Recovered = false;
 | 
				
			||||||
		Poco::File OuiFile(CurrentOUIFileName_);
 | 
							Poco::File OuiFile(CurrentOUIFileName_);
 | 
				
			||||||
		if (OuiFile.exists()) {
 | 
							if (OuiFile.exists()) {
 | 
				
			||||||
			std::unique_lock	Lock(LocalMutex_);
 | 
								std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
			Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
 | 
								Recovered = ProcessFile(CurrentOUIFileName_, OUIs_);
 | 
				
			||||||
			if (Recovered) {
 | 
								if (Recovered) {
 | 
				
			||||||
				poco_notice(Logger(),
 | 
									poco_notice(Logger(),
 | 
				
			||||||
							fmt::format("Recovered last OUI file - {}", CurrentOUIFileName_));
 | 
												fmt::format("Recovered last OUI file - {}", CurrentOUIFileName_));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			poco_notice(Logger(),
 | 
								poco_notice(Logger(), fmt::format("No existing OUIFile.", CurrentOUIFileName_));
 | 
				
			||||||
							 fmt::format("No existing OUIFile.", CurrentOUIFileName_));
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		UpdaterCallBack_ = std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
 | 
							UpdaterCallBack_ =
 | 
				
			||||||
 | 
								std::make_unique<Poco::TimerCallback<OUIServer>>(*this, &OUIServer::onTimer);
 | 
				
			||||||
		if (Recovered) {
 | 
							if (Recovered) {
 | 
				
			||||||
			Timer_.setStartInterval(60 * 60 * 1000); // first run in 1 hour
 | 
								Timer_.setStartInterval(60 * 60 * 1000); // first run in 1 hour
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
 | 
								Timer_.setStartInterval(30 * 1000); // first run in 5 minutes
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
 | 
							Timer_.setPeriodicInterval(7 * 24 * 60 * 60 * 1000);
 | 
				
			||||||
		Timer_.start(*UpdaterCallBack_, MicroService::instance().TimerPool());
 | 
							Timer_.start(*UpdaterCallBack_, MicroServiceTimerPool());
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,7 +58,7 @@ namespace OpenWifi {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void OUIServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
 | 
						void OUIServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
 | 
				
			||||||
		MicroService::instance().LoadConfigurationFile();
 | 
							MicroServiceLoadConfigurationFile();
 | 
				
			||||||
		poco_information(Logger(), "Reinitializing.");
 | 
							poco_information(Logger(), "Reinitializing.");
 | 
				
			||||||
		Stop();
 | 
							Stop();
 | 
				
			||||||
		Start();
 | 
							Start();
 | 
				
			||||||
@@ -62,15 +66,19 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	bool OUIServer::GetFile(const std::string &FileName) {
 | 
						bool OUIServer::GetFile(const std::string &FileName) {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			LastUpdate_ = OpenWifi::Now();
 | 
								LastUpdate_ = Utils::Now();
 | 
				
			||||||
			poco_information(Logger(), fmt::format("Start: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
 | 
								poco_information(Logger(),
 | 
				
			||||||
			std::unique_ptr<std::istream> pStr(
 | 
												 fmt::format("Start: Retrieving OUI file: {}",
 | 
				
			||||||
				Poco::URIStreamOpener::defaultOpener().open(MicroService::instance().ConfigGetString("oui.download.uri")));
 | 
															 MicroServiceConfigGetString("oui.download.uri", "")));
 | 
				
			||||||
 | 
								std::unique_ptr<std::istream> pStr(Poco::URIStreamOpener::defaultOpener().open(
 | 
				
			||||||
 | 
									MicroServiceConfigGetString("oui.download.uri", "")));
 | 
				
			||||||
			std::ofstream OS;
 | 
								std::ofstream OS;
 | 
				
			||||||
			OS.open(FileName);
 | 
								OS.open(FileName);
 | 
				
			||||||
			Poco::StreamCopier::copyStream(*pStr, OS);
 | 
								Poco::StreamCopier::copyStream(*pStr, OS);
 | 
				
			||||||
			OS.close();
 | 
								OS.close();
 | 
				
			||||||
			poco_information(Logger(), fmt::format("Done: Retrieving OUI file: {}",MicroService::instance().ConfigGetString("oui.download.uri")));
 | 
								poco_information(Logger(),
 | 
				
			||||||
 | 
												 fmt::format("Done: Retrieving OUI file: {}",
 | 
				
			||||||
 | 
															 MicroServiceConfigGetString("oui.download.uri", "")));
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
			Logger().log(E);
 | 
								Logger().log(E);
 | 
				
			||||||
@@ -125,7 +133,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		//	fetch data from server, if not available, just use the file we already have.
 | 
							//	fetch data from server, if not available, just use the file we already have.
 | 
				
			||||||
		Poco::File Current(CurrentOUIFileName_);
 | 
							Poco::File Current(CurrentOUIFileName_);
 | 
				
			||||||
		if (Current.exists()) {
 | 
							if (Current.exists()) {
 | 
				
			||||||
			if((OpenWifi::Now()-Current.getLastModified().epochTime()) < (7*24*60*60)) {
 | 
								if ((Utils::Now() - Current.getLastModified().epochTime()) < (7 * 24 * 60 * 60)) {
 | 
				
			||||||
				if (!Initialized_) {
 | 
									if (!Initialized_) {
 | 
				
			||||||
					if (ProcessFile(CurrentOUIFileName_, OUIs_)) {
 | 
										if (ProcessFile(CurrentOUIFileName_, OUIs_)) {
 | 
				
			||||||
						Initialized_ = true;
 | 
											Initialized_ = true;
 | 
				
			||||||
@@ -142,19 +150,20 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		OUIMap TmpOUIs;
 | 
							OUIMap TmpOUIs;
 | 
				
			||||||
		if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
 | 
							if (GetFile(LatestOUIFileName_) && ProcessFile(LatestOUIFileName_, TmpOUIs)) {
 | 
				
			||||||
			std::unique_lock G(LocalMutex_);
 | 
								std::lock_guard G(LocalMutex_);
 | 
				
			||||||
			OUIs_ = std::move(TmpOUIs);
 | 
								OUIs_ = std::move(TmpOUIs);
 | 
				
			||||||
			LastUpdate_ = OpenWifi::Now();
 | 
								LastUpdate_ = Utils::Now();
 | 
				
			||||||
			Poco::File F1(CurrentOUIFileName_);
 | 
								Poco::File F1(CurrentOUIFileName_);
 | 
				
			||||||
			if (F1.exists())
 | 
								if (F1.exists())
 | 
				
			||||||
				F1.remove();
 | 
									F1.remove();
 | 
				
			||||||
			Poco::File F2(LatestOUIFileName_);
 | 
								Poco::File F2(LatestOUIFileName_);
 | 
				
			||||||
			F2.renameTo(CurrentOUIFileName_);
 | 
								F2.renameTo(CurrentOUIFileName_);
 | 
				
			||||||
			poco_information(Logger(), fmt::format("New OUI file {} downloaded.",LatestOUIFileName_));
 | 
								poco_information(Logger(),
 | 
				
			||||||
 | 
												 fmt::format("New OUI file {} downloaded.", LatestOUIFileName_));
 | 
				
			||||||
		} else if (OUIs_.empty()) {
 | 
							} else if (OUIs_.empty()) {
 | 
				
			||||||
			if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
 | 
								if (ProcessFile(CurrentOUIFileName_, TmpOUIs)) {
 | 
				
			||||||
				LastUpdate_ = OpenWifi::Now();
 | 
									LastUpdate_ = Utils::Now();
 | 
				
			||||||
				std::unique_lock G(LocalMutex_);
 | 
									std::lock_guard G(LocalMutex_);
 | 
				
			||||||
				OUIs_ = std::move(TmpOUIs);
 | 
									OUIs_ = std::move(TmpOUIs);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -164,11 +173,11 @@ namespace OpenWifi {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::string OUIServer::GetManufacturer(const std::string &MAC) {
 | 
						std::string OUIServer::GetManufacturer(const std::string &MAC) {
 | 
				
			||||||
		std::shared_lock 	Lock(LocalMutex_);
 | 
							std::lock_guard Lock(LocalMutex_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
 | 
							auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
 | 
				
			||||||
		if (Manufacturer != OUIs_.end())
 | 
							if (Manufacturer != OUIs_.end())
 | 
				
			||||||
			return Manufacturer->second;
 | 
								return Manufacturer->second;
 | 
				
			||||||
		return "";
 | 
							return "";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					}; // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,16 +4,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <shared_mutex>
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
#include "Poco/Timer.h"
 | 
					#include "Poco/Timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class OUIServer : public SubSystemServer {
 | 
						class OUIServer : public SubSystemServer {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
		typedef std::map<uint64_t, std::string> OUIMap;
 | 
							typedef std::map<uint64_t, std::string> OUIMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static auto instance() {
 | 
							static auto instance() {
 | 
				
			||||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
 | 
							[[nodiscard]] bool ProcessFile(const std::string &FileName, OUIMap &Map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  private:
 | 
						  private:
 | 
				
			||||||
		std::shared_mutex	LocalMutex_;
 | 
							std::mutex LocalMutex_;
 | 
				
			||||||
		uint64_t LastUpdate_ = 0;
 | 
							uint64_t LastUpdate_ = 0;
 | 
				
			||||||
		bool Initialized_ = false;
 | 
							bool Initialized_ = false;
 | 
				
			||||||
		OUIMap OUIs_;
 | 
							OUIMap OUIs_;
 | 
				
			||||||
@@ -42,13 +42,9 @@ namespace OpenWifi {
 | 
				
			|||||||
		std::unique_ptr<Poco::TimerCallback<OUIServer>> UpdaterCallBack_;
 | 
							std::unique_ptr<Poco::TimerCallback<OUIServer>> UpdaterCallBack_;
 | 
				
			||||||
		std::string LatestOUIFileName_, CurrentOUIFileName_;
 | 
							std::string LatestOUIFileName_, CurrentOUIFileName_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		OUIServer() noexcept:
 | 
							OUIServer() noexcept : SubSystemServer("OUIServer", "OUI-SVR", "ouiserver") {}
 | 
				
			||||||
			SubSystemServer("OUIServer", "OUI-SVR", "ouiserver")
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline auto OUIServer() { return OUIServer::instance(); }
 | 
						inline auto OUIServer() { return OUIServer::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user