From 43e57ce5e11e9052f5a7db66f2e8613f1784f919 Mon Sep 17 00:00:00 2001 From: Frederic Robra Date: Tue, 25 Jun 2019 17:03:28 +0200 Subject: first version of dnbd3-ng --- src/shared/crc32.c | 621 ++++++++++++++++++++++++++++++++++ src/shared/crc32.h | 9 + src/shared/fdsignal.c | 14 + src/shared/fdsignal.h | 57 ++++ src/shared/fdsignal.inc/eventfd.c | 74 ++++ src/shared/fdsignal.inc/pipe64.c | 88 +++++ src/shared/fdsignal.inc/pipe_malloc.c | 89 +++++ src/shared/log.c | 204 +++++++++++ src/shared/log.h | 65 ++++ src/shared/protocol.h | 159 +++++++++ src/shared/sockhelper.c | 430 +++++++++++++++++++++++ src/shared/sockhelper.h | 120 +++++++ src/shared/timing.c | 21 ++ src/shared/timing.h | 162 +++++++++ 14 files changed, 2113 insertions(+) create mode 100644 src/shared/crc32.c create mode 100644 src/shared/crc32.h create mode 100644 src/shared/fdsignal.c create mode 100644 src/shared/fdsignal.h create mode 100644 src/shared/fdsignal.inc/eventfd.c create mode 100644 src/shared/fdsignal.inc/pipe64.c create mode 100644 src/shared/fdsignal.inc/pipe_malloc.c create mode 100644 src/shared/log.c create mode 100644 src/shared/log.h create mode 100644 src/shared/protocol.h create mode 100644 src/shared/sockhelper.c create mode 100644 src/shared/sockhelper.h create mode 100644 src/shared/timing.c create mode 100644 src/shared/timing.h (limited to 'src/shared') diff --git a/src/shared/crc32.c b/src/shared/crc32.c new file mode 100644 index 0000000..db941d3 --- /dev/null +++ b/src/shared/crc32.c @@ -0,0 +1,621 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * + * Modified for use in dnbd3 + * Original comment: + * + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + * + * Original zlib.h license text: + * + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +*/ + +#include "../types.h" +#include + +#define FAR +#define OF(args) args +#define local static + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) +# define BYFOUR +#endif +#ifdef BYFOUR +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +local const uint32_t crc_table[TBLS][256] = +{ + { + 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, + 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, + 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, + 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, + 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, + 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, + 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, + 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, + 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, + 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, + 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, + 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, + 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, + 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, + 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, + 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, + 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, + 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, + 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, + 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, + 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, + 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, + 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, + 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, + 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, + 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, + 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, + 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, + 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, + 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, + 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, + 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, + 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, + 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, + 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, + 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, + 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, + 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, + 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, + 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, + 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, + 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, + 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, + 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, + 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, + 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, + 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, + 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, + 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, + 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, + 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, + 0x2d02ef8dU +#ifdef BYFOUR + }, + { + 0x00000000U, 0x191b3141U, 0x32366282U, 0x2b2d53c3U, 0x646cc504U, + 0x7d77f445U, 0x565aa786U, 0x4f4196c7U, 0xc8d98a08U, 0xd1c2bb49U, + 0xfaefe88aU, 0xe3f4d9cbU, 0xacb54f0cU, 0xb5ae7e4dU, 0x9e832d8eU, + 0x87981ccfU, 0x4ac21251U, 0x53d92310U, 0x78f470d3U, 0x61ef4192U, + 0x2eaed755U, 0x37b5e614U, 0x1c98b5d7U, 0x05838496U, 0x821b9859U, + 0x9b00a918U, 0xb02dfadbU, 0xa936cb9aU, 0xe6775d5dU, 0xff6c6c1cU, + 0xd4413fdfU, 0xcd5a0e9eU, 0x958424a2U, 0x8c9f15e3U, 0xa7b24620U, + 0xbea97761U, 0xf1e8e1a6U, 0xe8f3d0e7U, 0xc3de8324U, 0xdac5b265U, + 0x5d5daeaaU, 0x44469febU, 0x6f6bcc28U, 0x7670fd69U, 0x39316baeU, + 0x202a5aefU, 0x0b07092cU, 0x121c386dU, 0xdf4636f3U, 0xc65d07b2U, + 0xed705471U, 0xf46b6530U, 0xbb2af3f7U, 0xa231c2b6U, 0x891c9175U, + 0x9007a034U, 0x179fbcfbU, 0x0e848dbaU, 0x25a9de79U, 0x3cb2ef38U, + 0x73f379ffU, 0x6ae848beU, 0x41c51b7dU, 0x58de2a3cU, 0xf0794f05U, + 0xe9627e44U, 0xc24f2d87U, 0xdb541cc6U, 0x94158a01U, 0x8d0ebb40U, + 0xa623e883U, 0xbf38d9c2U, 0x38a0c50dU, 0x21bbf44cU, 0x0a96a78fU, + 0x138d96ceU, 0x5ccc0009U, 0x45d73148U, 0x6efa628bU, 0x77e153caU, + 0xbabb5d54U, 0xa3a06c15U, 0x888d3fd6U, 0x91960e97U, 0xded79850U, + 0xc7cca911U, 0xece1fad2U, 0xf5facb93U, 0x7262d75cU, 0x6b79e61dU, + 0x4054b5deU, 0x594f849fU, 0x160e1258U, 0x0f152319U, 0x243870daU, + 0x3d23419bU, 0x65fd6ba7U, 0x7ce65ae6U, 0x57cb0925U, 0x4ed03864U, + 0x0191aea3U, 0x188a9fe2U, 0x33a7cc21U, 0x2abcfd60U, 0xad24e1afU, + 0xb43fd0eeU, 0x9f12832dU, 0x8609b26cU, 0xc94824abU, 0xd05315eaU, + 0xfb7e4629U, 0xe2657768U, 0x2f3f79f6U, 0x362448b7U, 0x1d091b74U, + 0x04122a35U, 0x4b53bcf2U, 0x52488db3U, 0x7965de70U, 0x607eef31U, + 0xe7e6f3feU, 0xfefdc2bfU, 0xd5d0917cU, 0xcccba03dU, 0x838a36faU, + 0x9a9107bbU, 0xb1bc5478U, 0xa8a76539U, 0x3b83984bU, 0x2298a90aU, + 0x09b5fac9U, 0x10aecb88U, 0x5fef5d4fU, 0x46f46c0eU, 0x6dd93fcdU, + 0x74c20e8cU, 0xf35a1243U, 0xea412302U, 0xc16c70c1U, 0xd8774180U, + 0x9736d747U, 0x8e2de606U, 0xa500b5c5U, 0xbc1b8484U, 0x71418a1aU, + 0x685abb5bU, 0x4377e898U, 0x5a6cd9d9U, 0x152d4f1eU, 0x0c367e5fU, + 0x271b2d9cU, 0x3e001cddU, 0xb9980012U, 0xa0833153U, 0x8bae6290U, + 0x92b553d1U, 0xddf4c516U, 0xc4eff457U, 0xefc2a794U, 0xf6d996d5U, + 0xae07bce9U, 0xb71c8da8U, 0x9c31de6bU, 0x852aef2aU, 0xca6b79edU, + 0xd37048acU, 0xf85d1b6fU, 0xe1462a2eU, 0x66de36e1U, 0x7fc507a0U, + 0x54e85463U, 0x4df36522U, 0x02b2f3e5U, 0x1ba9c2a4U, 0x30849167U, + 0x299fa026U, 0xe4c5aeb8U, 0xfdde9ff9U, 0xd6f3cc3aU, 0xcfe8fd7bU, + 0x80a96bbcU, 0x99b25afdU, 0xb29f093eU, 0xab84387fU, 0x2c1c24b0U, + 0x350715f1U, 0x1e2a4632U, 0x07317773U, 0x4870e1b4U, 0x516bd0f5U, + 0x7a468336U, 0x635db277U, 0xcbfad74eU, 0xd2e1e60fU, 0xf9ccb5ccU, + 0xe0d7848dU, 0xaf96124aU, 0xb68d230bU, 0x9da070c8U, 0x84bb4189U, + 0x03235d46U, 0x1a386c07U, 0x31153fc4U, 0x280e0e85U, 0x674f9842U, + 0x7e54a903U, 0x5579fac0U, 0x4c62cb81U, 0x8138c51fU, 0x9823f45eU, + 0xb30ea79dU, 0xaa1596dcU, 0xe554001bU, 0xfc4f315aU, 0xd7626299U, + 0xce7953d8U, 0x49e14f17U, 0x50fa7e56U, 0x7bd72d95U, 0x62cc1cd4U, + 0x2d8d8a13U, 0x3496bb52U, 0x1fbbe891U, 0x06a0d9d0U, 0x5e7ef3ecU, + 0x4765c2adU, 0x6c48916eU, 0x7553a02fU, 0x3a1236e8U, 0x230907a9U, + 0x0824546aU, 0x113f652bU, 0x96a779e4U, 0x8fbc48a5U, 0xa4911b66U, + 0xbd8a2a27U, 0xf2cbbce0U, 0xebd08da1U, 0xc0fdde62U, 0xd9e6ef23U, + 0x14bce1bdU, 0x0da7d0fcU, 0x268a833fU, 0x3f91b27eU, 0x70d024b9U, + 0x69cb15f8U, 0x42e6463bU, 0x5bfd777aU, 0xdc656bb5U, 0xc57e5af4U, + 0xee530937U, 0xf7483876U, 0xb809aeb1U, 0xa1129ff0U, 0x8a3fcc33U, + 0x9324fd72U + }, + { + 0x00000000U, 0x01c26a37U, 0x0384d46eU, 0x0246be59U, 0x0709a8dcU, + 0x06cbc2ebU, 0x048d7cb2U, 0x054f1685U, 0x0e1351b8U, 0x0fd13b8fU, + 0x0d9785d6U, 0x0c55efe1U, 0x091af964U, 0x08d89353U, 0x0a9e2d0aU, + 0x0b5c473dU, 0x1c26a370U, 0x1de4c947U, 0x1fa2771eU, 0x1e601d29U, + 0x1b2f0bacU, 0x1aed619bU, 0x18abdfc2U, 0x1969b5f5U, 0x1235f2c8U, + 0x13f798ffU, 0x11b126a6U, 0x10734c91U, 0x153c5a14U, 0x14fe3023U, + 0x16b88e7aU, 0x177ae44dU, 0x384d46e0U, 0x398f2cd7U, 0x3bc9928eU, + 0x3a0bf8b9U, 0x3f44ee3cU, 0x3e86840bU, 0x3cc03a52U, 0x3d025065U, + 0x365e1758U, 0x379c7d6fU, 0x35dac336U, 0x3418a901U, 0x3157bf84U, + 0x3095d5b3U, 0x32d36beaU, 0x331101ddU, 0x246be590U, 0x25a98fa7U, + 0x27ef31feU, 0x262d5bc9U, 0x23624d4cU, 0x22a0277bU, 0x20e69922U, + 0x2124f315U, 0x2a78b428U, 0x2bbade1fU, 0x29fc6046U, 0x283e0a71U, + 0x2d711cf4U, 0x2cb376c3U, 0x2ef5c89aU, 0x2f37a2adU, 0x709a8dc0U, + 0x7158e7f7U, 0x731e59aeU, 0x72dc3399U, 0x7793251cU, 0x76514f2bU, + 0x7417f172U, 0x75d59b45U, 0x7e89dc78U, 0x7f4bb64fU, 0x7d0d0816U, + 0x7ccf6221U, 0x798074a4U, 0x78421e93U, 0x7a04a0caU, 0x7bc6cafdU, + 0x6cbc2eb0U, 0x6d7e4487U, 0x6f38fadeU, 0x6efa90e9U, 0x6bb5866cU, + 0x6a77ec5bU, 0x68315202U, 0x69f33835U, 0x62af7f08U, 0x636d153fU, + 0x612bab66U, 0x60e9c151U, 0x65a6d7d4U, 0x6464bde3U, 0x662203baU, + 0x67e0698dU, 0x48d7cb20U, 0x4915a117U, 0x4b531f4eU, 0x4a917579U, + 0x4fde63fcU, 0x4e1c09cbU, 0x4c5ab792U, 0x4d98dda5U, 0x46c49a98U, + 0x4706f0afU, 0x45404ef6U, 0x448224c1U, 0x41cd3244U, 0x400f5873U, + 0x4249e62aU, 0x438b8c1dU, 0x54f16850U, 0x55330267U, 0x5775bc3eU, + 0x56b7d609U, 0x53f8c08cU, 0x523aaabbU, 0x507c14e2U, 0x51be7ed5U, + 0x5ae239e8U, 0x5b2053dfU, 0x5966ed86U, 0x58a487b1U, 0x5deb9134U, + 0x5c29fb03U, 0x5e6f455aU, 0x5fad2f6dU, 0xe1351b80U, 0xe0f771b7U, + 0xe2b1cfeeU, 0xe373a5d9U, 0xe63cb35cU, 0xe7fed96bU, 0xe5b86732U, + 0xe47a0d05U, 0xef264a38U, 0xeee4200fU, 0xeca29e56U, 0xed60f461U, + 0xe82fe2e4U, 0xe9ed88d3U, 0xebab368aU, 0xea695cbdU, 0xfd13b8f0U, + 0xfcd1d2c7U, 0xfe976c9eU, 0xff5506a9U, 0xfa1a102cU, 0xfbd87a1bU, + 0xf99ec442U, 0xf85cae75U, 0xf300e948U, 0xf2c2837fU, 0xf0843d26U, + 0xf1465711U, 0xf4094194U, 0xf5cb2ba3U, 0xf78d95faU, 0xf64fffcdU, + 0xd9785d60U, 0xd8ba3757U, 0xdafc890eU, 0xdb3ee339U, 0xde71f5bcU, + 0xdfb39f8bU, 0xddf521d2U, 0xdc374be5U, 0xd76b0cd8U, 0xd6a966efU, + 0xd4efd8b6U, 0xd52db281U, 0xd062a404U, 0xd1a0ce33U, 0xd3e6706aU, + 0xd2241a5dU, 0xc55efe10U, 0xc49c9427U, 0xc6da2a7eU, 0xc7184049U, + 0xc25756ccU, 0xc3953cfbU, 0xc1d382a2U, 0xc011e895U, 0xcb4dafa8U, + 0xca8fc59fU, 0xc8c97bc6U, 0xc90b11f1U, 0xcc440774U, 0xcd866d43U, + 0xcfc0d31aU, 0xce02b92dU, 0x91af9640U, 0x906dfc77U, 0x922b422eU, + 0x93e92819U, 0x96a63e9cU, 0x976454abU, 0x9522eaf2U, 0x94e080c5U, + 0x9fbcc7f8U, 0x9e7eadcfU, 0x9c381396U, 0x9dfa79a1U, 0x98b56f24U, + 0x99770513U, 0x9b31bb4aU, 0x9af3d17dU, 0x8d893530U, 0x8c4b5f07U, + 0x8e0de15eU, 0x8fcf8b69U, 0x8a809decU, 0x8b42f7dbU, 0x89044982U, + 0x88c623b5U, 0x839a6488U, 0x82580ebfU, 0x801eb0e6U, 0x81dcdad1U, + 0x8493cc54U, 0x8551a663U, 0x8717183aU, 0x86d5720dU, 0xa9e2d0a0U, + 0xa820ba97U, 0xaa6604ceU, 0xaba46ef9U, 0xaeeb787cU, 0xaf29124bU, + 0xad6fac12U, 0xacadc625U, 0xa7f18118U, 0xa633eb2fU, 0xa4755576U, + 0xa5b73f41U, 0xa0f829c4U, 0xa13a43f3U, 0xa37cfdaaU, 0xa2be979dU, + 0xb5c473d0U, 0xb40619e7U, 0xb640a7beU, 0xb782cd89U, 0xb2cddb0cU, + 0xb30fb13bU, 0xb1490f62U, 0xb08b6555U, 0xbbd72268U, 0xba15485fU, + 0xb853f606U, 0xb9919c31U, 0xbcde8ab4U, 0xbd1ce083U, 0xbf5a5edaU, + 0xbe9834edU + }, + { + 0x00000000U, 0xb8bc6765U, 0xaa09c88bU, 0x12b5afeeU, 0x8f629757U, + 0x37def032U, 0x256b5fdcU, 0x9dd738b9U, 0xc5b428efU, 0x7d084f8aU, + 0x6fbde064U, 0xd7018701U, 0x4ad6bfb8U, 0xf26ad8ddU, 0xe0df7733U, + 0x58631056U, 0x5019579fU, 0xe8a530faU, 0xfa109f14U, 0x42acf871U, + 0xdf7bc0c8U, 0x67c7a7adU, 0x75720843U, 0xcdce6f26U, 0x95ad7f70U, + 0x2d111815U, 0x3fa4b7fbU, 0x8718d09eU, 0x1acfe827U, 0xa2738f42U, + 0xb0c620acU, 0x087a47c9U, 0xa032af3eU, 0x188ec85bU, 0x0a3b67b5U, + 0xb28700d0U, 0x2f503869U, 0x97ec5f0cU, 0x8559f0e2U, 0x3de59787U, + 0x658687d1U, 0xdd3ae0b4U, 0xcf8f4f5aU, 0x7733283fU, 0xeae41086U, + 0x525877e3U, 0x40edd80dU, 0xf851bf68U, 0xf02bf8a1U, 0x48979fc4U, + 0x5a22302aU, 0xe29e574fU, 0x7f496ff6U, 0xc7f50893U, 0xd540a77dU, + 0x6dfcc018U, 0x359fd04eU, 0x8d23b72bU, 0x9f9618c5U, 0x272a7fa0U, + 0xbafd4719U, 0x0241207cU, 0x10f48f92U, 0xa848e8f7U, 0x9b14583dU, + 0x23a83f58U, 0x311d90b6U, 0x89a1f7d3U, 0x1476cf6aU, 0xaccaa80fU, + 0xbe7f07e1U, 0x06c36084U, 0x5ea070d2U, 0xe61c17b7U, 0xf4a9b859U, + 0x4c15df3cU, 0xd1c2e785U, 0x697e80e0U, 0x7bcb2f0eU, 0xc377486bU, + 0xcb0d0fa2U, 0x73b168c7U, 0x6104c729U, 0xd9b8a04cU, 0x446f98f5U, + 0xfcd3ff90U, 0xee66507eU, 0x56da371bU, 0x0eb9274dU, 0xb6054028U, + 0xa4b0efc6U, 0x1c0c88a3U, 0x81dbb01aU, 0x3967d77fU, 0x2bd27891U, + 0x936e1ff4U, 0x3b26f703U, 0x839a9066U, 0x912f3f88U, 0x299358edU, + 0xb4446054U, 0x0cf80731U, 0x1e4da8dfU, 0xa6f1cfbaU, 0xfe92dfecU, + 0x462eb889U, 0x549b1767U, 0xec277002U, 0x71f048bbU, 0xc94c2fdeU, + 0xdbf98030U, 0x6345e755U, 0x6b3fa09cU, 0xd383c7f9U, 0xc1366817U, + 0x798a0f72U, 0xe45d37cbU, 0x5ce150aeU, 0x4e54ff40U, 0xf6e89825U, + 0xae8b8873U, 0x1637ef16U, 0x048240f8U, 0xbc3e279dU, 0x21e91f24U, + 0x99557841U, 0x8be0d7afU, 0x335cb0caU, 0xed59b63bU, 0x55e5d15eU, + 0x47507eb0U, 0xffec19d5U, 0x623b216cU, 0xda874609U, 0xc832e9e7U, + 0x708e8e82U, 0x28ed9ed4U, 0x9051f9b1U, 0x82e4565fU, 0x3a58313aU, + 0xa78f0983U, 0x1f336ee6U, 0x0d86c108U, 0xb53aa66dU, 0xbd40e1a4U, + 0x05fc86c1U, 0x1749292fU, 0xaff54e4aU, 0x322276f3U, 0x8a9e1196U, + 0x982bbe78U, 0x2097d91dU, 0x78f4c94bU, 0xc048ae2eU, 0xd2fd01c0U, + 0x6a4166a5U, 0xf7965e1cU, 0x4f2a3979U, 0x5d9f9697U, 0xe523f1f2U, + 0x4d6b1905U, 0xf5d77e60U, 0xe762d18eU, 0x5fdeb6ebU, 0xc2098e52U, + 0x7ab5e937U, 0x680046d9U, 0xd0bc21bcU, 0x88df31eaU, 0x3063568fU, + 0x22d6f961U, 0x9a6a9e04U, 0x07bda6bdU, 0xbf01c1d8U, 0xadb46e36U, + 0x15080953U, 0x1d724e9aU, 0xa5ce29ffU, 0xb77b8611U, 0x0fc7e174U, + 0x9210d9cdU, 0x2aacbea8U, 0x38191146U, 0x80a57623U, 0xd8c66675U, + 0x607a0110U, 0x72cfaefeU, 0xca73c99bU, 0x57a4f122U, 0xef189647U, + 0xfdad39a9U, 0x45115eccU, 0x764dee06U, 0xcef18963U, 0xdc44268dU, + 0x64f841e8U, 0xf92f7951U, 0x41931e34U, 0x5326b1daU, 0xeb9ad6bfU, + 0xb3f9c6e9U, 0x0b45a18cU, 0x19f00e62U, 0xa14c6907U, 0x3c9b51beU, + 0x842736dbU, 0x96929935U, 0x2e2efe50U, 0x2654b999U, 0x9ee8defcU, + 0x8c5d7112U, 0x34e11677U, 0xa9362eceU, 0x118a49abU, 0x033fe645U, + 0xbb838120U, 0xe3e09176U, 0x5b5cf613U, 0x49e959fdU, 0xf1553e98U, + 0x6c820621U, 0xd43e6144U, 0xc68bceaaU, 0x7e37a9cfU, 0xd67f4138U, + 0x6ec3265dU, 0x7c7689b3U, 0xc4caeed6U, 0x591dd66fU, 0xe1a1b10aU, + 0xf3141ee4U, 0x4ba87981U, 0x13cb69d7U, 0xab770eb2U, 0xb9c2a15cU, + 0x017ec639U, 0x9ca9fe80U, 0x241599e5U, 0x36a0360bU, 0x8e1c516eU, + 0x866616a7U, 0x3eda71c2U, 0x2c6fde2cU, 0x94d3b949U, 0x090481f0U, + 0xb1b8e695U, 0xa30d497bU, 0x1bb12e1eU, 0x43d23e48U, 0xfb6e592dU, + 0xe9dbf6c3U, 0x516791a6U, 0xccb0a91fU, 0x740cce7aU, 0x66b96194U, + 0xde0506f1U + }, + { + 0x00000000U, 0x96300777U, 0x2c610eeeU, 0xba510999U, 0x19c46d07U, + 0x8ff46a70U, 0x35a563e9U, 0xa395649eU, 0x3288db0eU, 0xa4b8dc79U, + 0x1ee9d5e0U, 0x88d9d297U, 0x2b4cb609U, 0xbd7cb17eU, 0x072db8e7U, + 0x911dbf90U, 0x6410b71dU, 0xf220b06aU, 0x4871b9f3U, 0xde41be84U, + 0x7dd4da1aU, 0xebe4dd6dU, 0x51b5d4f4U, 0xc785d383U, 0x56986c13U, + 0xc0a86b64U, 0x7af962fdU, 0xecc9658aU, 0x4f5c0114U, 0xd96c0663U, + 0x633d0ffaU, 0xf50d088dU, 0xc8206e3bU, 0x5e10694cU, 0xe44160d5U, + 0x727167a2U, 0xd1e4033cU, 0x47d4044bU, 0xfd850dd2U, 0x6bb50aa5U, + 0xfaa8b535U, 0x6c98b242U, 0xd6c9bbdbU, 0x40f9bcacU, 0xe36cd832U, + 0x755cdf45U, 0xcf0dd6dcU, 0x593dd1abU, 0xac30d926U, 0x3a00de51U, + 0x8051d7c8U, 0x1661d0bfU, 0xb5f4b421U, 0x23c4b356U, 0x9995bacfU, + 0x0fa5bdb8U, 0x9eb80228U, 0x0888055fU, 0xb2d90cc6U, 0x24e90bb1U, + 0x877c6f2fU, 0x114c6858U, 0xab1d61c1U, 0x3d2d66b6U, 0x9041dc76U, + 0x0671db01U, 0xbc20d298U, 0x2a10d5efU, 0x8985b171U, 0x1fb5b606U, + 0xa5e4bf9fU, 0x33d4b8e8U, 0xa2c90778U, 0x34f9000fU, 0x8ea80996U, + 0x18980ee1U, 0xbb0d6a7fU, 0x2d3d6d08U, 0x976c6491U, 0x015c63e6U, + 0xf4516b6bU, 0x62616c1cU, 0xd8306585U, 0x4e0062f2U, 0xed95066cU, + 0x7ba5011bU, 0xc1f40882U, 0x57c40ff5U, 0xc6d9b065U, 0x50e9b712U, + 0xeab8be8bU, 0x7c88b9fcU, 0xdf1ddd62U, 0x492dda15U, 0xf37cd38cU, + 0x654cd4fbU, 0x5861b24dU, 0xce51b53aU, 0x7400bca3U, 0xe230bbd4U, + 0x41a5df4aU, 0xd795d83dU, 0x6dc4d1a4U, 0xfbf4d6d3U, 0x6ae96943U, + 0xfcd96e34U, 0x468867adU, 0xd0b860daU, 0x732d0444U, 0xe51d0333U, + 0x5f4c0aaaU, 0xc97c0dddU, 0x3c710550U, 0xaa410227U, 0x10100bbeU, + 0x86200cc9U, 0x25b56857U, 0xb3856f20U, 0x09d466b9U, 0x9fe461ceU, + 0x0ef9de5eU, 0x98c9d929U, 0x2298d0b0U, 0xb4a8d7c7U, 0x173db359U, + 0x810db42eU, 0x3b5cbdb7U, 0xad6cbac0U, 0x2083b8edU, 0xb6b3bf9aU, + 0x0ce2b603U, 0x9ad2b174U, 0x3947d5eaU, 0xaf77d29dU, 0x1526db04U, + 0x8316dc73U, 0x120b63e3U, 0x843b6494U, 0x3e6a6d0dU, 0xa85a6a7aU, + 0x0bcf0ee4U, 0x9dff0993U, 0x27ae000aU, 0xb19e077dU, 0x44930ff0U, + 0xd2a30887U, 0x68f2011eU, 0xfec20669U, 0x5d5762f7U, 0xcb676580U, + 0x71366c19U, 0xe7066b6eU, 0x761bd4feU, 0xe02bd389U, 0x5a7ada10U, + 0xcc4add67U, 0x6fdfb9f9U, 0xf9efbe8eU, 0x43beb717U, 0xd58eb060U, + 0xe8a3d6d6U, 0x7e93d1a1U, 0xc4c2d838U, 0x52f2df4fU, 0xf167bbd1U, + 0x6757bca6U, 0xdd06b53fU, 0x4b36b248U, 0xda2b0dd8U, 0x4c1b0aafU, + 0xf64a0336U, 0x607a0441U, 0xc3ef60dfU, 0x55df67a8U, 0xef8e6e31U, + 0x79be6946U, 0x8cb361cbU, 0x1a8366bcU, 0xa0d26f25U, 0x36e26852U, + 0x95770cccU, 0x03470bbbU, 0xb9160222U, 0x2f260555U, 0xbe3bbac5U, + 0x280bbdb2U, 0x925ab42bU, 0x046ab35cU, 0xa7ffd7c2U, 0x31cfd0b5U, + 0x8b9ed92cU, 0x1daede5bU, 0xb0c2649bU, 0x26f263ecU, 0x9ca36a75U, + 0x0a936d02U, 0xa906099cU, 0x3f360eebU, 0x85670772U, 0x13570005U, + 0x824abf95U, 0x147ab8e2U, 0xae2bb17bU, 0x381bb60cU, 0x9b8ed292U, + 0x0dbed5e5U, 0xb7efdc7cU, 0x21dfdb0bU, 0xd4d2d386U, 0x42e2d4f1U, + 0xf8b3dd68U, 0x6e83da1fU, 0xcd16be81U, 0x5b26b9f6U, 0xe177b06fU, + 0x7747b718U, 0xe65a0888U, 0x706a0fffU, 0xca3b0666U, 0x5c0b0111U, + 0xff9e658fU, 0x69ae62f8U, 0xd3ff6b61U, 0x45cf6c16U, 0x78e20aa0U, + 0xeed20dd7U, 0x5483044eU, 0xc2b30339U, 0x612667a7U, 0xf71660d0U, + 0x4d476949U, 0xdb776e3eU, 0x4a6ad1aeU, 0xdc5ad6d9U, 0x660bdf40U, + 0xf03bd837U, 0x53aebca9U, 0xc59ebbdeU, 0x7fcfb247U, 0xe9ffb530U, + 0x1cf2bdbdU, 0x8ac2bacaU, 0x3093b353U, 0xa6a3b424U, 0x0536d0baU, + 0x9306d7cdU, 0x2957de54U, 0xbf67d923U, 0x2e7a66b3U, 0xb84a61c4U, + 0x021b685dU, 0x942b6f2aU, 0x37be0bb4U, 0xa18e0cc3U, 0x1bdf055aU, + 0x8def022dU + }, + { + 0x00000000U, 0x41311b19U, 0x82623632U, 0xc3532d2bU, 0x04c56c64U, + 0x45f4777dU, 0x86a75a56U, 0xc796414fU, 0x088ad9c8U, 0x49bbc2d1U, + 0x8ae8effaU, 0xcbd9f4e3U, 0x0c4fb5acU, 0x4d7eaeb5U, 0x8e2d839eU, + 0xcf1c9887U, 0x5112c24aU, 0x1023d953U, 0xd370f478U, 0x9241ef61U, + 0x55d7ae2eU, 0x14e6b537U, 0xd7b5981cU, 0x96848305U, 0x59981b82U, + 0x18a9009bU, 0xdbfa2db0U, 0x9acb36a9U, 0x5d5d77e6U, 0x1c6c6cffU, + 0xdf3f41d4U, 0x9e0e5acdU, 0xa2248495U, 0xe3159f8cU, 0x2046b2a7U, + 0x6177a9beU, 0xa6e1e8f1U, 0xe7d0f3e8U, 0x2483dec3U, 0x65b2c5daU, + 0xaaae5d5dU, 0xeb9f4644U, 0x28cc6b6fU, 0x69fd7076U, 0xae6b3139U, + 0xef5a2a20U, 0x2c09070bU, 0x6d381c12U, 0xf33646dfU, 0xb2075dc6U, + 0x715470edU, 0x30656bf4U, 0xf7f32abbU, 0xb6c231a2U, 0x75911c89U, + 0x34a00790U, 0xfbbc9f17U, 0xba8d840eU, 0x79dea925U, 0x38efb23cU, + 0xff79f373U, 0xbe48e86aU, 0x7d1bc541U, 0x3c2ade58U, 0x054f79f0U, + 0x447e62e9U, 0x872d4fc2U, 0xc61c54dbU, 0x018a1594U, 0x40bb0e8dU, + 0x83e823a6U, 0xc2d938bfU, 0x0dc5a038U, 0x4cf4bb21U, 0x8fa7960aU, + 0xce968d13U, 0x0900cc5cU, 0x4831d745U, 0x8b62fa6eU, 0xca53e177U, + 0x545dbbbaU, 0x156ca0a3U, 0xd63f8d88U, 0x970e9691U, 0x5098d7deU, + 0x11a9ccc7U, 0xd2fae1ecU, 0x93cbfaf5U, 0x5cd76272U, 0x1de6796bU, + 0xdeb55440U, 0x9f844f59U, 0x58120e16U, 0x1923150fU, 0xda703824U, + 0x9b41233dU, 0xa76bfd65U, 0xe65ae67cU, 0x2509cb57U, 0x6438d04eU, + 0xa3ae9101U, 0xe29f8a18U, 0x21cca733U, 0x60fdbc2aU, 0xafe124adU, + 0xeed03fb4U, 0x2d83129fU, 0x6cb20986U, 0xab2448c9U, 0xea1553d0U, + 0x29467efbU, 0x687765e2U, 0xf6793f2fU, 0xb7482436U, 0x741b091dU, + 0x352a1204U, 0xf2bc534bU, 0xb38d4852U, 0x70de6579U, 0x31ef7e60U, + 0xfef3e6e7U, 0xbfc2fdfeU, 0x7c91d0d5U, 0x3da0cbccU, 0xfa368a83U, + 0xbb07919aU, 0x7854bcb1U, 0x3965a7a8U, 0x4b98833bU, 0x0aa99822U, + 0xc9fab509U, 0x88cbae10U, 0x4f5def5fU, 0x0e6cf446U, 0xcd3fd96dU, + 0x8c0ec274U, 0x43125af3U, 0x022341eaU, 0xc1706cc1U, 0x804177d8U, + 0x47d73697U, 0x06e62d8eU, 0xc5b500a5U, 0x84841bbcU, 0x1a8a4171U, + 0x5bbb5a68U, 0x98e87743U, 0xd9d96c5aU, 0x1e4f2d15U, 0x5f7e360cU, + 0x9c2d1b27U, 0xdd1c003eU, 0x120098b9U, 0x533183a0U, 0x9062ae8bU, + 0xd153b592U, 0x16c5f4ddU, 0x57f4efc4U, 0x94a7c2efU, 0xd596d9f6U, + 0xe9bc07aeU, 0xa88d1cb7U, 0x6bde319cU, 0x2aef2a85U, 0xed796bcaU, + 0xac4870d3U, 0x6f1b5df8U, 0x2e2a46e1U, 0xe136de66U, 0xa007c57fU, + 0x6354e854U, 0x2265f34dU, 0xe5f3b202U, 0xa4c2a91bU, 0x67918430U, + 0x26a09f29U, 0xb8aec5e4U, 0xf99fdefdU, 0x3accf3d6U, 0x7bfde8cfU, + 0xbc6ba980U, 0xfd5ab299U, 0x3e099fb2U, 0x7f3884abU, 0xb0241c2cU, + 0xf1150735U, 0x32462a1eU, 0x73773107U, 0xb4e17048U, 0xf5d06b51U, + 0x3683467aU, 0x77b25d63U, 0x4ed7facbU, 0x0fe6e1d2U, 0xccb5ccf9U, + 0x8d84d7e0U, 0x4a1296afU, 0x0b238db6U, 0xc870a09dU, 0x8941bb84U, + 0x465d2303U, 0x076c381aU, 0xc43f1531U, 0x850e0e28U, 0x42984f67U, + 0x03a9547eU, 0xc0fa7955U, 0x81cb624cU, 0x1fc53881U, 0x5ef42398U, + 0x9da70eb3U, 0xdc9615aaU, 0x1b0054e5U, 0x5a314ffcU, 0x996262d7U, + 0xd85379ceU, 0x174fe149U, 0x567efa50U, 0x952dd77bU, 0xd41ccc62U, + 0x138a8d2dU, 0x52bb9634U, 0x91e8bb1fU, 0xd0d9a006U, 0xecf37e5eU, + 0xadc26547U, 0x6e91486cU, 0x2fa05375U, 0xe836123aU, 0xa9070923U, + 0x6a542408U, 0x2b653f11U, 0xe479a796U, 0xa548bc8fU, 0x661b91a4U, + 0x272a8abdU, 0xe0bccbf2U, 0xa18dd0ebU, 0x62defdc0U, 0x23efe6d9U, + 0xbde1bc14U, 0xfcd0a70dU, 0x3f838a26U, 0x7eb2913fU, 0xb924d070U, + 0xf815cb69U, 0x3b46e642U, 0x7a77fd5bU, 0xb56b65dcU, 0xf45a7ec5U, + 0x370953eeU, 0x763848f7U, 0xb1ae09b8U, 0xf09f12a1U, 0x33cc3f8aU, + 0x72fd2493U + }, + { + 0x00000000U, 0x376ac201U, 0x6ed48403U, 0x59be4602U, 0xdca80907U, + 0xebc2cb06U, 0xb27c8d04U, 0x85164f05U, 0xb851130eU, 0x8f3bd10fU, + 0xd685970dU, 0xe1ef550cU, 0x64f91a09U, 0x5393d808U, 0x0a2d9e0aU, + 0x3d475c0bU, 0x70a3261cU, 0x47c9e41dU, 0x1e77a21fU, 0x291d601eU, + 0xac0b2f1bU, 0x9b61ed1aU, 0xc2dfab18U, 0xf5b56919U, 0xc8f23512U, + 0xff98f713U, 0xa626b111U, 0x914c7310U, 0x145a3c15U, 0x2330fe14U, + 0x7a8eb816U, 0x4de47a17U, 0xe0464d38U, 0xd72c8f39U, 0x8e92c93bU, + 0xb9f80b3aU, 0x3cee443fU, 0x0b84863eU, 0x523ac03cU, 0x6550023dU, + 0x58175e36U, 0x6f7d9c37U, 0x36c3da35U, 0x01a91834U, 0x84bf5731U, + 0xb3d59530U, 0xea6bd332U, 0xdd011133U, 0x90e56b24U, 0xa78fa925U, + 0xfe31ef27U, 0xc95b2d26U, 0x4c4d6223U, 0x7b27a022U, 0x2299e620U, + 0x15f32421U, 0x28b4782aU, 0x1fdeba2bU, 0x4660fc29U, 0x710a3e28U, + 0xf41c712dU, 0xc376b32cU, 0x9ac8f52eU, 0xada2372fU, 0xc08d9a70U, + 0xf7e75871U, 0xae591e73U, 0x9933dc72U, 0x1c259377U, 0x2b4f5176U, + 0x72f11774U, 0x459bd575U, 0x78dc897eU, 0x4fb64b7fU, 0x16080d7dU, + 0x2162cf7cU, 0xa4748079U, 0x931e4278U, 0xcaa0047aU, 0xfdcac67bU, + 0xb02ebc6cU, 0x87447e6dU, 0xdefa386fU, 0xe990fa6eU, 0x6c86b56bU, + 0x5bec776aU, 0x02523168U, 0x3538f369U, 0x087faf62U, 0x3f156d63U, + 0x66ab2b61U, 0x51c1e960U, 0xd4d7a665U, 0xe3bd6464U, 0xba032266U, + 0x8d69e067U, 0x20cbd748U, 0x17a11549U, 0x4e1f534bU, 0x7975914aU, + 0xfc63de4fU, 0xcb091c4eU, 0x92b75a4cU, 0xa5dd984dU, 0x989ac446U, + 0xaff00647U, 0xf64e4045U, 0xc1248244U, 0x4432cd41U, 0x73580f40U, + 0x2ae64942U, 0x1d8c8b43U, 0x5068f154U, 0x67023355U, 0x3ebc7557U, + 0x09d6b756U, 0x8cc0f853U, 0xbbaa3a52U, 0xe2147c50U, 0xd57ebe51U, + 0xe839e25aU, 0xdf53205bU, 0x86ed6659U, 0xb187a458U, 0x3491eb5dU, + 0x03fb295cU, 0x5a456f5eU, 0x6d2fad5fU, 0x801b35e1U, 0xb771f7e0U, + 0xeecfb1e2U, 0xd9a573e3U, 0x5cb33ce6U, 0x6bd9fee7U, 0x3267b8e5U, + 0x050d7ae4U, 0x384a26efU, 0x0f20e4eeU, 0x569ea2ecU, 0x61f460edU, + 0xe4e22fe8U, 0xd388ede9U, 0x8a36abebU, 0xbd5c69eaU, 0xf0b813fdU, + 0xc7d2d1fcU, 0x9e6c97feU, 0xa90655ffU, 0x2c101afaU, 0x1b7ad8fbU, + 0x42c49ef9U, 0x75ae5cf8U, 0x48e900f3U, 0x7f83c2f2U, 0x263d84f0U, + 0x115746f1U, 0x944109f4U, 0xa32bcbf5U, 0xfa958df7U, 0xcdff4ff6U, + 0x605d78d9U, 0x5737bad8U, 0x0e89fcdaU, 0x39e33edbU, 0xbcf571deU, + 0x8b9fb3dfU, 0xd221f5ddU, 0xe54b37dcU, 0xd80c6bd7U, 0xef66a9d6U, + 0xb6d8efd4U, 0x81b22dd5U, 0x04a462d0U, 0x33cea0d1U, 0x6a70e6d3U, + 0x5d1a24d2U, 0x10fe5ec5U, 0x27949cc4U, 0x7e2adac6U, 0x494018c7U, + 0xcc5657c2U, 0xfb3c95c3U, 0xa282d3c1U, 0x95e811c0U, 0xa8af4dcbU, + 0x9fc58fcaU, 0xc67bc9c8U, 0xf1110bc9U, 0x740744ccU, 0x436d86cdU, + 0x1ad3c0cfU, 0x2db902ceU, 0x4096af91U, 0x77fc6d90U, 0x2e422b92U, + 0x1928e993U, 0x9c3ea696U, 0xab546497U, 0xf2ea2295U, 0xc580e094U, + 0xf8c7bc9fU, 0xcfad7e9eU, 0x9613389cU, 0xa179fa9dU, 0x246fb598U, + 0x13057799U, 0x4abb319bU, 0x7dd1f39aU, 0x3035898dU, 0x075f4b8cU, + 0x5ee10d8eU, 0x698bcf8fU, 0xec9d808aU, 0xdbf7428bU, 0x82490489U, + 0xb523c688U, 0x88649a83U, 0xbf0e5882U, 0xe6b01e80U, 0xd1dadc81U, + 0x54cc9384U, 0x63a65185U, 0x3a181787U, 0x0d72d586U, 0xa0d0e2a9U, + 0x97ba20a8U, 0xce0466aaU, 0xf96ea4abU, 0x7c78ebaeU, 0x4b1229afU, + 0x12ac6fadU, 0x25c6adacU, 0x1881f1a7U, 0x2feb33a6U, 0x765575a4U, + 0x413fb7a5U, 0xc429f8a0U, 0xf3433aa1U, 0xaafd7ca3U, 0x9d97bea2U, + 0xd073c4b5U, 0xe71906b4U, 0xbea740b6U, 0x89cd82b7U, 0x0cdbcdb2U, + 0x3bb10fb3U, 0x620f49b1U, 0x55658bb0U, 0x6822d7bbU, 0x5f4815baU, + 0x06f653b8U, 0x319c91b9U, 0xb48adebcU, 0x83e01cbdU, 0xda5e5abfU, + 0xed3498beU + }, + { + 0x00000000U, 0x6567bcb8U, 0x8bc809aaU, 0xeeafb512U, 0x5797628fU, + 0x32f0de37U, 0xdc5f6b25U, 0xb938d79dU, 0xef28b4c5U, 0x8a4f087dU, + 0x64e0bd6fU, 0x018701d7U, 0xb8bfd64aU, 0xddd86af2U, 0x3377dfe0U, + 0x56106358U, 0x9f571950U, 0xfa30a5e8U, 0x149f10faU, 0x71f8ac42U, + 0xc8c07bdfU, 0xada7c767U, 0x43087275U, 0x266fcecdU, 0x707fad95U, + 0x1518112dU, 0xfbb7a43fU, 0x9ed01887U, 0x27e8cf1aU, 0x428f73a2U, + 0xac20c6b0U, 0xc9477a08U, 0x3eaf32a0U, 0x5bc88e18U, 0xb5673b0aU, + 0xd00087b2U, 0x6938502fU, 0x0c5fec97U, 0xe2f05985U, 0x8797e53dU, + 0xd1878665U, 0xb4e03addU, 0x5a4f8fcfU, 0x3f283377U, 0x8610e4eaU, + 0xe3775852U, 0x0dd8ed40U, 0x68bf51f8U, 0xa1f82bf0U, 0xc49f9748U, + 0x2a30225aU, 0x4f579ee2U, 0xf66f497fU, 0x9308f5c7U, 0x7da740d5U, + 0x18c0fc6dU, 0x4ed09f35U, 0x2bb7238dU, 0xc518969fU, 0xa07f2a27U, + 0x1947fdbaU, 0x7c204102U, 0x928ff410U, 0xf7e848a8U, 0x3d58149bU, + 0x583fa823U, 0xb6901d31U, 0xd3f7a189U, 0x6acf7614U, 0x0fa8caacU, + 0xe1077fbeU, 0x8460c306U, 0xd270a05eU, 0xb7171ce6U, 0x59b8a9f4U, + 0x3cdf154cU, 0x85e7c2d1U, 0xe0807e69U, 0x0e2fcb7bU, 0x6b4877c3U, + 0xa20f0dcbU, 0xc768b173U, 0x29c70461U, 0x4ca0b8d9U, 0xf5986f44U, + 0x90ffd3fcU, 0x7e5066eeU, 0x1b37da56U, 0x4d27b90eU, 0x284005b6U, + 0xc6efb0a4U, 0xa3880c1cU, 0x1ab0db81U, 0x7fd76739U, 0x9178d22bU, + 0xf41f6e93U, 0x03f7263bU, 0x66909a83U, 0x883f2f91U, 0xed589329U, + 0x546044b4U, 0x3107f80cU, 0xdfa84d1eU, 0xbacff1a6U, 0xecdf92feU, + 0x89b82e46U, 0x67179b54U, 0x027027ecU, 0xbb48f071U, 0xde2f4cc9U, + 0x3080f9dbU, 0x55e74563U, 0x9ca03f6bU, 0xf9c783d3U, 0x176836c1U, + 0x720f8a79U, 0xcb375de4U, 0xae50e15cU, 0x40ff544eU, 0x2598e8f6U, + 0x73888baeU, 0x16ef3716U, 0xf8408204U, 0x9d273ebcU, 0x241fe921U, + 0x41785599U, 0xafd7e08bU, 0xcab05c33U, 0x3bb659edU, 0x5ed1e555U, + 0xb07e5047U, 0xd519ecffU, 0x6c213b62U, 0x094687daU, 0xe7e932c8U, + 0x828e8e70U, 0xd49eed28U, 0xb1f95190U, 0x5f56e482U, 0x3a31583aU, + 0x83098fa7U, 0xe66e331fU, 0x08c1860dU, 0x6da63ab5U, 0xa4e140bdU, + 0xc186fc05U, 0x2f294917U, 0x4a4ef5afU, 0xf3762232U, 0x96119e8aU, + 0x78be2b98U, 0x1dd99720U, 0x4bc9f478U, 0x2eae48c0U, 0xc001fdd2U, + 0xa566416aU, 0x1c5e96f7U, 0x79392a4fU, 0x97969f5dU, 0xf2f123e5U, + 0x05196b4dU, 0x607ed7f5U, 0x8ed162e7U, 0xebb6de5fU, 0x528e09c2U, + 0x37e9b57aU, 0xd9460068U, 0xbc21bcd0U, 0xea31df88U, 0x8f566330U, + 0x61f9d622U, 0x049e6a9aU, 0xbda6bd07U, 0xd8c101bfU, 0x366eb4adU, + 0x53090815U, 0x9a4e721dU, 0xff29cea5U, 0x11867bb7U, 0x74e1c70fU, + 0xcdd91092U, 0xa8beac2aU, 0x46111938U, 0x2376a580U, 0x7566c6d8U, + 0x10017a60U, 0xfeaecf72U, 0x9bc973caU, 0x22f1a457U, 0x479618efU, + 0xa939adfdU, 0xcc5e1145U, 0x06ee4d76U, 0x6389f1ceU, 0x8d2644dcU, + 0xe841f864U, 0x51792ff9U, 0x341e9341U, 0xdab12653U, 0xbfd69aebU, + 0xe9c6f9b3U, 0x8ca1450bU, 0x620ef019U, 0x07694ca1U, 0xbe519b3cU, + 0xdb362784U, 0x35999296U, 0x50fe2e2eU, 0x99b95426U, 0xfcdee89eU, + 0x12715d8cU, 0x7716e134U, 0xce2e36a9U, 0xab498a11U, 0x45e63f03U, + 0x208183bbU, 0x7691e0e3U, 0x13f65c5bU, 0xfd59e949U, 0x983e55f1U, + 0x2106826cU, 0x44613ed4U, 0xaace8bc6U, 0xcfa9377eU, 0x38417fd6U, + 0x5d26c36eU, 0xb389767cU, 0xd6eecac4U, 0x6fd61d59U, 0x0ab1a1e1U, + 0xe41e14f3U, 0x8179a84bU, 0xd769cb13U, 0xb20e77abU, 0x5ca1c2b9U, + 0x39c67e01U, 0x80fea99cU, 0xe5991524U, 0x0b36a036U, 0x6e511c8eU, + 0xa7166686U, 0xc271da3eU, 0x2cde6f2cU, 0x49b9d394U, 0xf0810409U, + 0x95e6b8b1U, 0x7b490da3U, 0x1e2eb11bU, 0x483ed243U, 0x2d596efbU, + 0xc3f6dbe9U, 0xa6916751U, 0x1fa9b0ccU, 0x7ace0c74U, 0x9461b966U, + 0xf10605deU +#endif + } +}; + +#ifdef NO_ENDIAN +// Currently not in use, always use the BYFOUR method with known endianness +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +uint32_t crc32(crc, buf, len) + uint32_t crc; + const uint8_t *buf; + size_t len; +{ + if (buf == NULL) return 0; + + crc = crc ^ 0xffffffffU; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffU; +} +#endif + +#ifdef BYFOUR + +/* + This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit + integer pointer type. This violates the strict aliasing rule, where a + compiler can assume, for optimization purposes, that two pointers to + fundamentally different types won't ever point to the same memory. This can + manifest as a problem only if one of the pointers is written to. This code + only reads from those pointers. So long as this code remains isolated in + this compilation unit, there won't be a problem. For this reason, this code + should not be copied and pasted into a compilation unit in which other code + writes to the buffer that is passed to these routines. + */ + +#ifdef LITTLE_ENDIAN +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +uint32_t crc32(crc, buf, len) + uint32_t crc; + const uint8_t *buf; + size_t len; +{ + if (buf == NULL) return 0; + register uint32_t c; + register const uint32_t FAR *buf4; + + c = ~crc; + while (len && ((uintptr_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const uint32_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const uint8_t FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return c; +} +#endif + +#ifdef BIG_ENDIAN +/* ========================================================================= */ +#define DOBIG4 c ^= *buf4++; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +uint32_t crc32(crc, buf, len) + uint32_t crc; + const uint8_t *buf; + size_t len; +{ + if (buf == NULL) return 0; + register uint32_t c; + register const uint32_t FAR *buf4; + + c = ~net_order_32(crc); + while (len && ((uintptr_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const uint32_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf = (const uint8_t FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return net_order_32(c); +} +#endif + +#endif /* BYFOUR */ + diff --git a/src/shared/crc32.h b/src/shared/crc32.h new file mode 100644 index 0000000..00b8bdd --- /dev/null +++ b/src/shared/crc32.h @@ -0,0 +1,9 @@ +#ifndef _CRC32_H_ +#define _CRC32_H_ + +#include + +uint32_t crc32(uint32_t crc, const uint8_t *buf, size_t len); + +#endif + diff --git a/src/shared/fdsignal.c b/src/shared/fdsignal.c new file mode 100644 index 0000000..5e5cf7f --- /dev/null +++ b/src/shared/fdsignal.c @@ -0,0 +1,14 @@ +#include "fdsignal.h" + +#if defined(linux) || defined(__linux) || defined(__linux__) +//#warning "Using eventfd based signalling" +#include "fdsignal.inc/eventfd.c" +#elif __SIZEOF_INT__ == 4 && __SIZEOF_POINTER__ == 8 +//#warning "Using pointer-packing pipe based signalling" +#include "fdsignal.inc/pipe64.c" +#else +_Static_assert( sizeof(int) != 4 || sizeof(void*) != 8, "Something's goofy, fix preprocessor check above!" ); +//#warning "Using fallback pipe based signalling" +#include "fdsignal.inc/pipe_malloc.c" +#endif + diff --git a/src/shared/fdsignal.h b/src/shared/fdsignal.h new file mode 100644 index 0000000..960a2a9 --- /dev/null +++ b/src/shared/fdsignal.h @@ -0,0 +1,57 @@ +#ifndef _FD_SIGNAL_H_ +#define _FD_SIGNAL_H_ + +#define SIGNAL_OK (0) +#define SIGNAL_TIMEOUT (-2) +#define SIGNAL_ERROR (-1) + +typedef struct _dnbd3_signal dnbd3_signal_t; + +/** + * Create a new signal, nonblocking. + * @return NULL on error, pointer to dnbd3_signal_t on success. + */ +dnbd3_signal_t* signal_new(); + +/** + * Create a new signal, blocking. + * @return NULL on error, pointer to dnbd3_signal_t on success. + */ +dnbd3_signal_t* signal_newBlocking(); + +/** + * Trigger the given signal, so a wait or clear call will succeed. + * @return SIGNAL_OK on success, SIGNAL_ERROR on error + */ +int signal_call(const dnbd3_signal_t* const signal); + +/** + * Wait for given signal, with an optional timeout. + * If timeout == 0, just poll once. + * If timeout < 0, wait forever. + * @return > 0 telling how many times the signal was called, + * SIGNAL_TIMEOUT if the timeout was reached, + * SIGNAL_ERROR if some error occured + */ +int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs); + +/** + * Clears any pending signals on this signal. + * @return number of signals that were pending, + * SIGNAL_ERROR if some error occured + */ +int signal_clear(const dnbd3_signal_t* const signal); + +/** + * Close the given signal. + */ +void signal_close(const dnbd3_signal_t* const signal); + +/** + * Get a file descriptor for the given signal that can be + * waited on using poll or similar. + * @return -1 if the signal is invalid + */ +int signal_getWaitFd(const dnbd3_signal_t* const signal); + +#endif diff --git a/src/shared/fdsignal.inc/eventfd.c b/src/shared/fdsignal.inc/eventfd.c new file mode 100644 index 0000000..358d41c --- /dev/null +++ b/src/shared/fdsignal.inc/eventfd.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +/* + * Linux implementation of signals. + * Internally, eventfds are used for signalling, as they + * provide the least overhead. We don't allocate any struct + * ever, but cast the event fd+1 to dnbd3_signal_t* + * to save all the malloc() and free() calls. + */ + +dnbd3_signal_t* signal_new() +{ + // On error, eventfd() returns -1, so essentially we return NULL on error. + // (Yes, NULL doesn't have to be 0 everywhere, but cmon) + return (dnbd3_signal_t*)(intptr_t)( eventfd( 0, EFD_NONBLOCK ) + 1 ); +} + +dnbd3_signal_t* signal_newBlocking() +{ + return (dnbd3_signal_t*)(intptr_t)( eventfd( 0, 0 ) + 1 ); +} + +int signal_call(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + static const uint64_t one = 1; + const int signalFd = ( (int)(intptr_t)signal ) - 1; + return write( signalFd, &one, sizeof one ) == sizeof one ? SIGNAL_OK : SIGNAL_ERROR; +} + +int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + const int signalFd = ( (int)(intptr_t)signal ) - 1; + struct pollfd ps = { + .fd = signalFd, + .events = POLLIN + }; + int ret = poll( &ps, 1, timeoutMs ); + if ( ret == 0 ) return SIGNAL_TIMEOUT; + if ( ret == -1 ) return SIGNAL_ERROR; + if ( ps.revents & ( POLLERR | POLLNVAL ) ) return SIGNAL_ERROR; + return signal_clear( signal ); +} + +int signal_clear(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + uint64_t ret; + const int signalFd = ( (int)(intptr_t)signal ) - 1; + if ( read( signalFd, &ret, sizeof ret ) != sizeof ret ) { + if ( errno == EAGAIN ) return 0; + return SIGNAL_ERROR; + } + return (int)ret; +} + +void signal_close(const dnbd3_signal_t* const signal) +{ + const int signalFd = ( (int)(intptr_t)signal ) - 1; + close( signalFd ); +} + +int signal_getWaitFd(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return -1; + const int signalFd = ( (int)(intptr_t)signal ) - 1; + return signalFd; +} + diff --git a/src/shared/fdsignal.inc/pipe64.c b/src/shared/fdsignal.inc/pipe64.c new file mode 100644 index 0000000..4f0614b --- /dev/null +++ b/src/shared/fdsignal.inc/pipe64.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +#define P_READ (0) +#define P_WRITE (1) + +/* + * Generic (posix) implelentation of signals, using pipes. + * 64bit version, packing two ints into a pointer. + * This version requires that you use -fno-strict-aliasing + * since it's doing evil pointer casting. + */ + +dnbd3_signal_t* signal_new() +{ + int fds[2]; + if ( pipe( fds ) == -1 ) return NULL; + fcntl( fds[P_READ], F_SETFL, O_NONBLOCK ); + fcntl( fds[P_WRITE], F_SETFL, O_NONBLOCK ); + return (dnbd3_signal_t*)*((uintptr_t*)fds); +} + +dnbd3_signal_t* signal_newBlocking() +{ + int fds[2]; + if ( pipe( fds ) == -1 ) return NULL; + return (dnbd3_signal_t*)*((uintptr_t*)fds); +} + +int signal_call(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + static char one = 1; + const int* fds = (int*)&signal; + // Write one byte on every call, so the number of bytes read will + // match the number of events + return write( fds[P_WRITE], &one, 1 ) > 0 ? SIGNAL_OK : SIGNAL_ERROR; +} + +int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + const int* fds = (int*)&signal; + struct pollfd ps = { + .fd = fds[P_READ], + .events = POLLIN + }; + int ret = poll( &ps, 1, timeoutMs ); + if ( ret == 0 ) return SIGNAL_TIMEOUT; + if ( ret == -1 ) return SIGNAL_ERROR; + if ( ps.revents & ( POLLERR | POLLNVAL ) ) return SIGNAL_ERROR; + return signal_clear( signal ); +} + +int signal_clear(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + char throwaway[100]; + const int* fds = (int*)&signal; + ssize_t ret, total = 0; + do { + ret = read( fds[P_READ], throwaway, sizeof throwaway ); + if ( ret < 0 ) { + if ( errno == EAGAIN ) return total; + return SIGNAL_ERROR; + } + total += ret; + } while ( (size_t)ret == sizeof throwaway ); + return (int)total; +} + +void signal_close(const dnbd3_signal_t* const signal) +{ + const int* fds = (int*)&signal; + close( fds[P_READ] ); + close( fds[P_WRITE] ); +} + +int signal_getWaitFd(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return -1; + const int* fds = (int*)&signal; + return fds[P_READ]; +} + diff --git a/src/shared/fdsignal.inc/pipe_malloc.c b/src/shared/fdsignal.inc/pipe_malloc.c new file mode 100644 index 0000000..b23ddcd --- /dev/null +++ b/src/shared/fdsignal.inc/pipe_malloc.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + +struct _dnbd3_signal { + int read; + int write; +}; + +/* + * Generic (posix) implelentation of signals, using pipes. + * A struct containing both fds will be malloc()ed for each + * signal. + */ + +dnbd3_signal_t* signal_new() +{ + dnbd3_signal_t *ret = signal_newBlocking(); + if ( ret == NULL ) return NULL; + fcntl( ret->read, F_SETFL, O_NONBLOCK ); + fcntl( ret->write, F_SETFL, O_NONBLOCK ); + return ret; +} + +dnbd3_signal_t* signal_newBlocking() +{ + int fds[2]; + if ( pipe( fds ) == -1 ) return NULL; + dnbd3_signal_t* ret = malloc( sizeof(dnbd3_signal_t) ); + ret->read = fds[0]; + ret->write = fds[1]; + return ret; +} + +int signal_call(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + static char one = 1; + // Write one byte on every call, so the number of bytes read will + // match the number of events + return write( signal->write, &one, 1 ) > 0 ? SIGNAL_OK : SIGNAL_ERROR; +} + +int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + struct pollfd ps = { + .fd = signal->read, + .events = POLLIN + }; + int ret = poll( &ps, 1, timeoutMs ); + if ( ret == 0 ) return SIGNAL_TIMEOUT; + if ( ret == -1 ) return SIGNAL_ERROR; + if ( ps.revents & ( POLLERR | POLLNVAL ) ) return SIGNAL_ERROR; + return signal_clear( signal ); +} + +int signal_clear(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return SIGNAL_ERROR; + char throwaway[100]; + ssize_t ret, total = 0; + do { + ret = read( signal->read, throwaway, sizeof throwaway ); + if ( ret < 0 ) { + if ( errno == EAGAIN ) return (int)total; + return SIGNAL_ERROR; + } + total += ret; + } while ( (size_t)ret == sizeof throwaway ); + return (int)total; +} + +void signal_close(const dnbd3_signal_t* const signal) +{ + close( signal->read ); + close( signal->write ); + free( (void*)signal ); +} + +int signal_getWaitFd(const dnbd3_signal_t* const signal) +{ + if ( signal == NULL ) return -1; + return signal->read; +} + diff --git a/src/shared/log.c b/src/shared/log.c new file mode 100644 index 0000000..055acb4 --- /dev/null +++ b/src/shared/log.c @@ -0,0 +1,204 @@ +/* + * This file is part of the Distributed Network Block Device 3 + * + * Copyright(c) 2011-2012 Simon Rettberg + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "log.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LEN (800) + +static pthread_mutex_t logLock = PTHREAD_MUTEX_INITIALIZER; +static _Atomic logmask_t maskFile = 31; +static _Atomic logmask_t maskCon = 15; + +static char *logFile = NULL; +static int logFd = -1; + +static bool consoleTimestamps = false; + + +static int writeLevel(char *buffer, logmask_t level); + + +bool log_hasMask(const logmask_t mask) +{ + return ( ( maskFile | maskCon ) & mask ) == mask; +} + +void log_setFileMask(logmask_t mask) +{ + maskFile = mask; +} + +void log_setConsoleMask(logmask_t mask) +{ + maskCon = mask; +} + +void log_setConsoleTimestamps(bool on) +{ + consoleTimestamps = on; +} + +bool log_openLogFile(const char *path) +{ + pthread_mutex_lock( &logLock ); + if ( logFd >= 0 ) { + close( logFd ); + } + if ( path == NULL && logFile == NULL ) + goto unlock; + if ( path != NULL ) { + free( logFile ); + logFile = strdup( path ); + } + logFd = open( logFile, O_WRONLY | O_CREAT | O_APPEND, 0644 ); + if ( logFd < 0 ) + goto unlock; +unlock: ; + pthread_mutex_unlock( &logLock ); + return logFd >= 0; +} + +void logadd(const logmask_t mask, const char *fmt, ...) +{ + if ( ( (maskFile | maskCon) & mask ) == 0 ) + return; + va_list ap; + int ret; + time_t rawtime; + struct tm timeinfo; + char buffer[LINE_LEN]; + bool toFile = maskFile & mask; + bool toStdout = maskCon & mask; + size_t offset; + + if ( toFile || ( toStdout && consoleTimestamps ) ) { + time( &rawtime ); + localtime_r( &rawtime, &timeinfo ); + offset = strftime( buffer, LINE_LEN, "[%d.%m. %H:%M:%S] ", &timeinfo ); + } else { + offset = 0; + } + const char *stdoutLine = buffer + offset; + offset += writeLevel( buffer + offset, mask ); + va_start( ap, fmt ); + ret = vsnprintf( buffer + offset, LINE_LEN - offset, fmt, ap ); + va_end( ap ); + if ( ret < 0 ) return; + offset += ret; + if ( offset + 1 >= LINE_LEN ) { + buffer[LINE_LEN-2] = '\0'; + offset = LINE_LEN - 2; + } + if ( buffer[offset-1] != '\n' ) { + buffer[offset++] = '\n'; + buffer[offset] = '\0'; + } + if ( toFile ) { + pthread_mutex_lock( &logLock ); + if ( logFd >= 0 ) { + size_t done = 0; + while (done < offset ) { + const ssize_t wr = write( logFd, buffer + done, offset - done ); + if ( wr < 0 ) { + if ( errno == EINTR ) continue; + printf( "Logging to file failed! (errno=%d)\n", errno ); + break; + } + done += (size_t)wr; + } + } + pthread_mutex_unlock( &logLock ); + } + if ( toStdout ) { + if ( consoleTimestamps ) stdoutLine = buffer; +#ifdef AFL_MODE + fputs( stdoutLine, stderr ); + fflush( stderr ); +#else + fputs( stdoutLine, stdout ); + fflush( stdout ); +#endif + } +} + +ssize_t log_fetch(char *buffer, int size) +{ + if ( logFile == NULL || size <= 1 ) + return -1; + int fd = open( logFile, O_RDONLY ); + if ( fd < 0 ) + return -1; + off_t off = lseek( fd, 0, SEEK_END ); + if ( off == (off_t)-1 ) { + close( fd ); + return -1; + } + if ( (off_t)size <= off ) { + off -= size; + } else { + off = 0; + } + ssize_t ret = pread( fd, buffer, size - 1, off ); + close( fd ); + buffer[ret] = '\0'; + return ret; +} + +static int writeLevel(char *buffer, logmask_t level) +{ + const char *word; + char *dest = buffer; + switch ( level ) { + case LOG_ERROR: + word = "ERROR"; + break; + case LOG_WARNING: + word = "WARNING"; + break; + case LOG_MINOR: + word = "Warning"; + break; + case LOG_INFO: + word = "Info"; + break; + case LOG_DEBUG1: + word = "DEBUG1"; + break; + case LOG_DEBUG2: + word = "DEBUG2"; + break; + default: + word = "!?!?!?"; + break; + } + while ( ( *dest++ = *word++ ) ); + *--dest = ':'; + *++dest = ' '; + return (int)( dest - buffer ) + 1; +} + diff --git a/src/shared/log.h b/src/shared/log.h new file mode 100644 index 0000000..5b1e8f7 --- /dev/null +++ b/src/shared/log.h @@ -0,0 +1,65 @@ +/* + * This file is part of the Distributed Network Block Device 3 + * + * Copyright(c) 2011-2012 Simon Rettberg + * + * This file may be licensed under the terms of of the + * GNU General Public License Version 2 (the ``GPL''). + * + * Software distributed under the License is distributed + * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the GPL for the specific language + * governing rights and limitations. + * + * You should have received a copy of the GPL along with this + * program. If not, go to http://www.gnu.org/licenses/gpl.html + * or write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef LOG_H_ +#define LOG_H_ + +#include +#include + +typedef unsigned int logmask_t; +#define LOG_ERROR ((logmask_t)1) // Fatal error, server will terminate +#define LOG_WARNING ((logmask_t)2) // Major issue, something is broken but keep running +#define LOG_MINOR ((logmask_t)4) // Minor issue, more of a hickup than serious problem +#define LOG_INFO ((logmask_t)8) // Informational message +#define LOG_DEBUG1 ((logmask_t)16) // Debug information, use this for non-spammy stuff +#define LOG_DEBUG2 ((logmask_t)32) // Use this for debug messages that will show up a lot + + +/** + * Check if cansoleMask | fileMask has all of mask set. + */ +bool log_hasMask(const logmask_t mask); + +void log_setFileMask(logmask_t mask); + +void log_setConsoleMask(logmask_t mask); + +void log_setConsoleTimestamps(bool on); + +/** + * Open or reopen the log file. If path is NULL and the + * function was called with a path before, the same path + * will be used again. + */ +bool log_openLogFile(const char *path); + +/** + * Add a line to the log + */ +void logadd(const logmask_t mask, const char *text, ...) + __attribute__ ((format (printf, 2, 3))); + +/** + * Return last size bytes of log. + */ +ssize_t log_fetch(char *buffer, int size); + +#endif /* LOG_H_ */ diff --git a/src/shared/protocol.h b/src/shared/protocol.h new file mode 100644 index 0000000..d87bbd8 --- /dev/null +++ b/src/shared/protocol.h @@ -0,0 +1,159 @@ +#ifndef _PROTOCOL_H_ +#define _PROTOCOL_H_ + +#include "sockhelper.h" + +#include "../types.h" +#include "../serialize.h" + +#include +#include +#include +#include + +// Client tells server that it is another server +#define FLAGS8_SERVER (1) +// Client (which is a proxy) tells server that it has background-replication enabled +#define FLAGS8_BG_REP (2) + +// 2017-10-16: We now support hop-counting, macro to pass hop count conditinally to a function +#define COND_HOPCOUNT(vers,hopcount) ( (vers) >= 3 ? (hopcount) : 0 ) + +// 2017-11-02: Macro to set flags in select image message properly if we're a server, as BG_REP depends on global var +#define SI_SERVER_FLAGS ( FLAGS8_SERVER | (_backgroundReplication == BGR_FULL ? FLAGS8_BG_REP : 0) ) + +#define REPLY_OK (0) +#define REPLY_ERRNO (-1) +#define REPLY_AGAIN (-2) +#define REPLY_INTR (-3) +#define REPLY_CLOSED (-4) +#define REPLY_INCOMPLETE (-5) +#define REPLY_WRONGMAGIC (-6) + +static inline int dnbd3_read_reply(int sock, dnbd3_reply_t *reply, bool wait) +{ + ssize_t ret = recv( sock, reply, sizeof(*reply), (wait ? MSG_WAITALL : MSG_DONTWAIT) | MSG_NOSIGNAL ); + if ( ret == 0 ) return REPLY_CLOSED; + if ( ret < 0 ) { + if ( errno == EAGAIN || errno == EWOULDBLOCK ) return REPLY_AGAIN; + if ( errno == EINTR ) return REPLY_INTR; + return REPLY_ERRNO; + } + if ( !wait && ret != sizeof(*reply) ) ret += recv( sock, ((char*)reply) + ret, sizeof(*reply) - ret, MSG_WAITALL | MSG_NOSIGNAL ); + if ( ret != sizeof(*reply) ) return REPLY_INCOMPLETE; + fixup_reply( *reply ); + if ( reply->magic != dnbd3_packet_magic ) return REPLY_WRONGMAGIC; + return REPLY_OK; +} + +static inline bool dnbd3_get_reply(int sock, dnbd3_reply_t *reply) +{ + int ret; + do { + ret = dnbd3_read_reply( sock, reply, true ); + } while ( ret == REPLY_INTR ); + return ret == REPLY_OK; +} + +static inline bool dnbd3_select_image(int sock, const char *name, uint16_t rid, uint8_t flags8) +{ + serialized_buffer_t serialized; + dnbd3_request_t request; + struct iovec iov[2]; + serializer_reset_write( &serialized ); + serializer_put_uint16( &serialized, PROTOCOL_VERSION ); + serializer_put_string( &serialized, name ); + serializer_put_uint16( &serialized, rid ); + serializer_put_uint8( &serialized, flags8 ); + const ssize_t len = serializer_get_written_length( &serialized ); + request.magic = dnbd3_packet_magic; + request.cmd = CMD_SELECT_IMAGE; + request.size = (uint32_t)len; +#ifdef _DEBUG + request.handle = 0; + request.offset = 0; +#endif + fixup_request( request ); + iov[0].iov_base = &request; + iov[0].iov_len = sizeof(request); + iov[1].iov_base = &serialized; + iov[1].iov_len = len; + ssize_t ret; + do { + ret = writev( sock, iov, 2 ); + } while ( ret == -1 && errno == EINTR ); + return ret == len + (ssize_t)sizeof(request); +} + +static inline bool dnbd3_get_block(int sock, uint64_t offset, uint32_t size, uint64_t handle, uint8_t hopCount) +{ + dnbd3_request_t request; + request.magic = dnbd3_packet_magic; + request.handle = handle; + request.cmd = CMD_GET_BLOCK; + // When writing before "fixup", we can get away with assigning to offset instead of offset_small if we + // do it before assigning to .hops. Faster on 64bit machines (so, on everything) + request.offset = offset; + request.hops = hopCount; + request.size = size; + fixup_request( request ); + return sock_sendAll( sock, &request, sizeof(request), 2 ) == (ssize_t)sizeof(request); +} + +static inline bool dnbd3_get_crc32(int sock, uint32_t *master, void *buffer, size_t *bufferLen) +{ + dnbd3_request_t request; + dnbd3_reply_t reply; + request.magic = dnbd3_packet_magic; + request.handle = 0; + request.cmd = CMD_GET_CRC32; + request.offset = 0; + request.size = 0; + fixup_request( request ); + if ( sock_sendAll( sock, &request, sizeof(request), 2 ) != (ssize_t)sizeof(request) ) return false; + if ( !dnbd3_get_reply( sock, &reply ) ) return false; + if ( reply.size == 0 ) { + *bufferLen = 0; + return true; + } + if ( reply.size < 4 ) return false; + reply.size -= 4; + if ( reply.cmd != CMD_GET_CRC32 || reply.size > *bufferLen ) return false; + *bufferLen = reply.size; + if ( sock_recv( sock, master, sizeof(uint32_t) ) != (ssize_t)sizeof(uint32_t) ) return false; + return sock_recv( sock, buffer, reply.size ) == (ssize_t)reply.size; +} + +/** + * Pass a full serialized_buffer_t and a socket fd. Parsed data will be returned in further arguments. + * Note that all strings will point into the passed buffer, so there's no need to free them. + * This function will also read the header for you, as this message can only occur during connection, + * where no unrequested messages could arrive inbetween. + */ +static inline bool dnbd3_select_image_reply(serialized_buffer_t *buffer, int sock, uint16_t *protocol_version, char **name, uint16_t *rid, + uint64_t *imageSize) +{ + errno = 0; + dnbd3_reply_t reply; + if ( !dnbd3_get_reply( sock, &reply ) ) { + return false; + } + errno = 0; + if ( reply.cmd != CMD_SELECT_IMAGE || reply.size < 3 || reply.size > MAX_PAYLOAD ) { + return false; + } + // receive reply payload + ssize_t ret = sock_recv( sock, buffer, reply.size ); + if ( ret != (ssize_t)reply.size ) { + return false; + } + // handle/check reply payload + serializer_reset_read( buffer, reply.size ); + *protocol_version = serializer_get_uint16( buffer ); + *name = serializer_get_string( buffer ); + *rid = serializer_get_uint16( buffer ); + *imageSize = serializer_get_uint64( buffer ); + return true; +} + +#endif diff --git a/src/shared/sockhelper.c b/src/shared/sockhelper.c new file mode 100644 index 0000000..ab34aa1 --- /dev/null +++ b/src/shared/sockhelper.c @@ -0,0 +1,430 @@ +#include "sockhelper.h" +#include "log.h" +#include // inet_ntop +#include +#include +#include +#include +#include +#include +#include + +#define MAXLISTEN 20 + +struct _poll_list { + int count; + struct pollfd entry[MAXLISTEN]; +}; + +int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const int rw_ms) +{ + // TODO: Move out of here, this unit should contain general socket functions + // TODO: Abstract away from sockaddr_in* like the rest of the functions here do, + // so WITH_IPV6 can finally be removed as everything is transparent. b- but how? + struct sockaddr_storage ss; + int proto, addrlen; + memset( &ss, 0, sizeof ss ); + if ( addr->type == HOST_IP4 ) { + // Set host (IPv4) + struct sockaddr_in *addr4 = (struct sockaddr_in*)&ss; + addr4->sin_family = AF_INET; + memcpy( &addr4->sin_addr, addr->addr, 4 ); + addr4->sin_port = addr->port; + proto = PF_INET; + addrlen = sizeof *addr4; + } +#ifdef WITH_IPV6 + else if ( addr->type == HOST_IP6 ) { + // Set host (IPv6) + struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&ss; + addr6->sin6_family = AF_INET6; + memcpy( &addr6->sin6_addr, addr->addr, 16 ); + addr6->sin6_port = addr->port; + proto = PF_INET6; + addrlen = sizeof *addr6; + } +#endif + else { + logadd( LOG_DEBUG1, "Unsupported address type: %d\n", (int)addr->type ); + return -1; + } + int client_sock = socket( proto, SOCK_STREAM, IPPROTO_TCP ); + if ( client_sock == -1 ) return -1; + // Apply connect timeout + if ( connect_ms == -1 ) { + sock_set_nonblock( client_sock ); + } else { + sock_setTimeout( client_sock, connect_ms ); + } + for ( int i = 0; i < 5; ++i ) { + int ret = connect( client_sock, (struct sockaddr *)&ss, addrlen ); + if ( ret != -1 || errno == EINPROGRESS || errno == EISCONN ) break; + if ( errno == EINTR ) { + // http://www.madore.org/~david/computers/connect-intr.html +#ifdef __linux__ + continue; +#else + struct pollfd unix_really_sucks = { .fd = client_sock, .events = POLLOUT | POLLIN }; + while ( i-- > 0 ) { + int pr = poll( &unix_really_sucks, 1, connect_ms == 0 ? -1 : connect_ms ); + if ( pr == 1 && ( unix_really_sucks.revents & POLLOUT ) ) break; + if ( pr == -1 && errno == EINTR ) continue; + close( client_sock ); + return -1; + } + sockaddr_storage junk; + socklen_t more_junk = sizeof(junk); + if ( getpeername( client_sock, (struct sockaddr*)&junk, &more_junk ) == -1 ) { + close( client_sock ); + return -1; + } + break; +#endif + } // EINTR + close( client_sock ); + return -1; + } + if ( connect_ms != -1 && connect_ms != rw_ms ) { + // Apply read/write timeout + sock_setTimeout( client_sock, rw_ms ); + } + return client_sock; +} + +// TODO: Pretty much same as in server/* +int sock_resolveToDnbd3Host(const char * const address, dnbd3_host_t * const dest, const int count) +{ + if ( count <= 0 ) + return 0; + struct addrinfo hints, *res, *ptr; + char bufferAddr[100], bufferPort[6]; + char *addr = bufferAddr; + const char *portStr = NULL; + int addCount = 0; + + // See if we have a port + snprintf( bufferAddr, sizeof bufferAddr, "%s", address ); + char *c1, *c2; + c1 = strchr( addr, ':' ); + if ( c1 != NULL ) { + c2 = strchr( c1 + 1, ':' ); + if ( c2 == NULL ) { + *c1 = '\0'; + portStr = c1 + 1; + } else if ( *addr == '[' ) { + // IPv6 - support [1:2::3]:123 + do { + c1 = strchr( c2 + 1, ':' ); + if ( c1 != NULL ) c2 = c1; + } while ( c1 != NULL ); + if ( *(c2 - 1 ) == ']' ) { + *( c2 - 1 ) = '\0'; + *c2 = '\0'; + addr += 1; + portStr = c2 + 1; + } + } + } + if ( portStr == NULL ) { + portStr = bufferPort; + snprintf( bufferPort, sizeof bufferPort, "%d", (int)PORT ); + } + + // Set hints for local addresses. + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ( getaddrinfo( addr, portStr, &hints, &res ) != 0 || res == NULL ) { + return 0; + } + for ( ptr = res; ptr != NULL && count > 0; ptr = ptr->ai_next ) { + if ( sock_sockaddrToDnbd3( ptr->ai_addr, &dest[addCount] ) ) { + addCount += 1; + } + } + + freeaddrinfo( res ); + return addCount; +} + +bool sock_sockaddrToDnbd3(struct sockaddr* sa, dnbd3_host_t *host) +{ + if ( sa->sa_family == AF_INET ) { + // Set host (IPv4) + struct sockaddr_in *addr4 = (struct sockaddr_in*)sa; + host->type = HOST_IP4; + host->port = addr4->sin_port; + memcpy( host->addr, &addr4->sin_addr, 4 ); + return true; + } +#ifdef WITH_IPV6 + if ( sa->sa_family == AF_INET6 ) { + // Set host (IPv6) + struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)sa; + host->type = HOST_IP6; + host->port = addr6->sin6_port; + memcpy( host->addr, &addr6->sin6_addr, 16 ); + return true; + } +#endif + return false; +} + +void sock_setTimeout(const int sockfd, const int milliseconds) +{ + struct timeval tv; + tv.tv_sec = milliseconds / 1000; + tv.tv_usec = (milliseconds * 1000) % 1000000; + setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) ); + setsockopt( sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv) ); +} + +poll_list_t* sock_newPollList() +{ + poll_list_t *list = (poll_list_t*)malloc( sizeof( poll_list_t ) ); + list->count = 0; + return list; +} + +void sock_destroyPollList(poll_list_t *list) +{ + for ( int i = 0; i < list->count; ++i ) { + if ( list->entry[i].fd >= 0 ) close( list->entry[i].fd ); + } + free( list ); +} + +size_t sock_printHost(const dnbd3_host_t * const host, char * const buffer, const size_t len) +{ + // Worst case: Port 5 chars, ':' to separate ip and port 1 char, terminating null 1 char = 7, [] for IPv6 + if ( len < 10 ) return 0; + char *output = buffer; + if ( host->type == HOST_IP6 ) { + *output++ = '['; + inet_ntop( AF_INET6, host->addr, output, (socklen_t)( len - 10 ) ); + output += strlen( output ); + *output++ = ']'; + } else if ( host->type == HOST_IP4 ) { + inet_ntop( AF_INET, host->addr, output, (socklen_t)( len - 8 ) ); + output += strlen( output ); + } else { + int ret = snprintf( output, len, "", (int)host->type ); + if ( ret <= 0 ) return 0; + return MIN( (size_t)ret, len-1 ); + } + *output = '\0'; + if ( host->port != 0 ) { + // There are still at least 7 bytes left in the buffer, port is at most 5 bytes + ':' + '\0' = 7 + int ret = snprintf( output, 7, ":%d", (int)ntohs( host->port ) ); + if ( ret < 0 ) ret = 0; + output += MIN( ret, 6 ); + } + return output - buffer; +} + +size_t sock_printable(const struct sockaddr * const addr, const socklen_t addrLen, char *output, const size_t len) +{ + char host[100], port[10]; + int outlen = 0; + int ret = getnameinfo( addr, addrLen, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV ); + if ( ret == 0 ) { + if ( addr->sa_family == AF_INET ) { + outlen = snprintf( output, len, "%s:%s", host, port ); + } else { + outlen = snprintf( output, len, "[%s]:%s", host, port ); + } + } + if ( outlen <= 0 ) return 0; + return MIN( (size_t)outlen, len-1 ); +} + +bool sock_listen(poll_list_t* list, char* bind_addr, uint16_t port) +{ + if ( list->count >= MAXLISTEN ) return false; + struct addrinfo hints, *res = NULL, *ptr; + char portStr[6]; + const int on = 1; + int openCount = 0; + // Set hints for local addresses. + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + snprintf( portStr, sizeof portStr, "%d", (int)port ); + if ( getaddrinfo( bind_addr, portStr, &hints, &res ) != 0 || res == NULL ) return false; + // Attempt to bind to all of the addresses as long as there's room in the poll list + for( ptr = res; ptr != NULL; ptr = ptr->ai_next ) { + char bla[100]; + if ( !sock_printable( (struct sockaddr*)ptr->ai_addr, ptr->ai_addrlen, bla, 100 ) ) snprintf( bla, 100, "[invalid]" ); + logadd( LOG_DEBUG1, "Binding to %s...", bla ); + int sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); + if ( sock < 0 ) { + logadd( LOG_WARNING, "(Bind to %s): cannot socket(), errno=%d", bla, errno ); + continue; + } + setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); + if ( ptr->ai_family == PF_INET6 ) setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on) ); + if ( bind( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 ) { + logadd( LOG_WARNING, "(Bind to %s): cannot bind(), errno=%d", bla, errno ); + close( sock ); + continue; + } + if ( listen( sock, 20 ) == -1 ) { + logadd( LOG_WARNING, "(Bind to %s): cannot listen(), errno=%d", bla, errno ); + close( sock ); + continue; + } + list->entry[list->count].fd = sock; + list->entry[list->count].events = POLLIN | POLLRDHUP; + list->count++; + openCount++; + if ( list->count >= MAXLISTEN ) break; + } + freeaddrinfo( res ); + return openCount > 0; +} + +bool sock_listenAny(poll_list_t* list, uint16_t port) +{ + return sock_listen( list, NULL, port ); +} + +int sock_multiConnect(poll_list_t* list, const dnbd3_host_t* host, int connect_ms, int rw_ms) +{ + // Nonblocking connect seems to be hard to get right in a portable fashion + // that's why you might see some weird checks here and there. For now there's + // only Linux and FreeBSD, but let's try to not make this code fall on its nose + // should dnbd3 be ported to other platforms. + if ( list->count < MAXLISTEN && host != NULL ) { + int sock = sock_connect( host, -1, -1 ); + if ( sock != -1 ) { + list->entry[list->count].fd = sock; + list->entry[list->count].events = POLLIN | POLLOUT | POLLRDHUP; + list->count++; + } + } + if ( list->count == 0 ) { + return -2; + } + int ret, tries = 5; + do { + ret = poll( list->entry, list->count, connect_ms ); + if ( ret > 0 ) break; + if ( ret == 0 ) return -1; + if ( ret == -1 && ( errno == EINTR || errno == EAGAIN ) ) { + if ( --tries == 0 ) return -1; + if ( connect_ms > 1 ) connect_ms /= 2; // Maybe properly account time one day + continue; + } + return -1; + } while ( true ); + for ( int i = list->count - 1; i >= 0; --i ) { + int fd = -1; + if ( list->entry[i].revents & ( POLLIN | POLLOUT ) ) { + struct sockaddr_storage tmp; + socklen_t len = sizeof(tmp); + fd = list->entry[i].fd; + if ( getpeername( fd, (struct sockaddr*)&tmp, &len ) == -1 ) { // More portable then SO_ERROR ... + close( fd ); + fd = -1; + } + } else if ( list->entry[i].revents != 0 ) { + close( list->entry[i].fd ); + } else { + continue; + } + // Either error or connect success + list->count--; + if ( i != list->count ) list->entry[i] = list->entry[list->count]; + if ( fd != -1 ) { + sock_set_block( fd ); + if ( rw_ms != -1 && rw_ms != connect_ms ) { + sock_setTimeout( fd, rw_ms ); + } + return fd; + } + } + return -1; +} + +int sock_accept(poll_list_t *list, struct sockaddr_storage *addr, socklen_t *length_ptr) +{ + int ret = poll( list->entry, list->count, -1 ); + if ( ret < 0 ) { + return -1; + } + for ( int i = list->count - 1; i >= 0; --i ) { + if ( list->entry[i].revents == 0 ) continue; + if ( list->entry[i].revents == POLLIN ) return accept( list->entry[i].fd, (struct sockaddr *)addr, length_ptr ); + if ( list->entry[i].revents & ( POLLNVAL | POLLHUP | POLLERR | POLLRDHUP ) ) { + logadd( LOG_DEBUG1, "poll fd revents=%d for index=%d and fd=%d", (int)list->entry[i].revents, i, list->entry[i].fd ); + close( list->entry[i].fd ); + list->count--; + if ( i != list->count ) list->entry[i] = list->entry[list->count]; + } + } + return -1; +} + +void sock_set_nonblock(int sock) +{ + int flags = fcntl( sock, F_GETFL, 0 ); + if ( flags == -1 ) flags = 0; + fcntl( sock, F_SETFL, flags | O_NONBLOCK ); +} + +void sock_set_block(int sock) +{ + int flags = fcntl( sock, F_GETFL, 0 ); + if ( flags == -1 ) flags = 0; + fcntl( sock, F_SETFL, flags & ~(int)O_NONBLOCK ); +} + +bool sock_append(poll_list_t *list, const int sock, bool wantRead, bool wantWrite) +{ + if ( sock == -1 || list->count >= MAXLISTEN ) return false; + list->entry[list->count++].fd = sock; + list->entry[list->count++].events = (short)( ( wantRead ? POLLIN : 0 ) | ( wantWrite ? POLLOUT : 0 ) | POLLRDHUP ); + list->count++; + return true; +} + +ssize_t sock_sendAll(const int sock, const void *buffer, const size_t len, int maxtries) +{ + size_t done = 0; + ssize_t ret = 0; + while ( done < len ) { + if ( maxtries >= 0 && --maxtries == -1 ) break; + ret = send( sock, (const uint8_t*)buffer + done, len - done, MSG_NOSIGNAL ); + if ( ret == -1 ) { + if ( errno == EINTR ) continue; + if ( errno == EAGAIN || errno == EWOULDBLOCK ) { + continue; + } + break; + } + if ( ret == 0 ) break; + done += ret; + } + if ( done == 0 ) return ret; + return done; +} + +ssize_t sock_recv(const int sock, void *buffer, const size_t len) +{ + size_t done = 0; + ssize_t ret = 0; + int intrs = 0; + while ( done < len ) { + ret = recv( sock, (char*)buffer + done, len - done, MSG_NOSIGNAL ); + if ( ret == -1 ) { + if ( errno == EINTR && ++intrs < 10 ) continue; + break; + } + if ( ret == 0 ) break; + done += ret; + } + if ( done == 0 ) return ret; + return done; +} + diff --git a/src/shared/sockhelper.h b/src/shared/sockhelper.h new file mode 100644 index 0000000..8d70789 --- /dev/null +++ b/src/shared/sockhelper.h @@ -0,0 +1,120 @@ +#ifndef SOCKHELPER_H_ +#define SOCKHELPER_H_ + +/* + * Helper functions for dealing with sockets. These functions should + * abstract from the IP version by using getaddrinfo() and thelike. + */ + +#include "../types.h" +#include +#include +#include + +typedef struct _poll_list poll_list_t; + +/** + * Connect to given dnbd3_host_t. + * @param addr - address of host to connect to + * @param connect_ms - timeout in milliseconds after which the connection attempt fails + * @param rw_ms - read/write timeout in milliseconds to apply on successful connect + * @return socket file descriptor, or -1 on error + */ +int sock_connect(const dnbd3_host_t * const addr, const int connect_ms, const int rw_ms); + +/** + * Resolve/parse given address and put the result(s) into passed dnbd3_host_t array, + * but only up to count entries. + * @return Number of items added to array + */ +int sock_resolveToDnbd3Host(const char * const address, dnbd3_host_t * const dest, const int count); + +bool sock_sockaddrToDnbd3(struct sockaddr* sa, dnbd3_host_t *host); + +void sock_setTimeout(const int sockfd, const int milliseconds); + +size_t sock_printHost(const dnbd3_host_t * const host, char *output, const size_t len); + +size_t sock_printable(const struct sockaddr * const addr, const socklen_t addrLen, char *output, const size_t len); + +/** + * Create new poll list. + */ +poll_list_t* sock_newPollList(); + +/** + * Delete a poll list, closing all sockets first if necessary. + */ +void sock_destroyPollList(poll_list_t *list); + +/** + * Listen on all interfaces/available IP addresses, using the given protocol. + * IPv4 and IPv6 are supported. + * @param protocol_family PF_INET or PF_INET6 + * @param port port to listen on + * @return true if any listen call was successful + */ +bool sock_listenAny(poll_list_t* list, uint16_t port); + +/** + * Listen on a specific address and port. + * @param bind_addr human readable address to bind to for listening + * @param port to listen on + */ +bool sock_listen(poll_list_t* list, char* bind_addr, uint16_t port); + +/** + * Asynchroneously connect to multiple hosts. + * This can be called multiple times with varying timeouts. Calling it + * the first time on an empty list is identical to sock_connect(). On + * consecutive calls, more nonblocking sockets in connecting state will + * be added to the list, and on each of these calls, all the pending + * sockets will be checked for successful connection (or error), respecting + * the passed timeout. + * host can be NULL to just wait on the sockets already in the list. + * If at least one socket completed the connection + * within the given timeout, it will be removed from the list and + * returned. On error or timeout, -1 is returned. If there are no more sockets + * in the list, -2 is returned. + */ +int sock_multiConnect(poll_list_t* list, const dnbd3_host_t* host, int connect_ms, int rw_ms); + +/** + * This is a multi-socket version of accept. Pass in an array of listening sockets. + * If any of the sockets has an incoming connection, accept it and return the new socket's fd. + * On error, return -1, just like accept(). + * @param sockets array of listening socket fds + * @param socket_count number of sockets in that array + * @return fd of new client socket, -1 on error + */ +int sock_accept(poll_list_t *list, struct sockaddr_storage *addr, socklen_t *length_ptr); + +void sock_set_nonblock(int sock); + +void sock_set_block(int sock); + +/** + * Add given socket to array. Take an existing empty slot ( == -1) if available, + * append to end otherwise. Updates socket count variable passed by reference. + * + * @param poll_list_t list the poll list to add the socket to + * @param sock socket fd to add + * @param wantRead whether to set the EPOLLIN flag + * @param wantWrite whether to set the EPOLLOUT flag + * @return true on success, false iff the array is already full or socket is < 0 + */ +bool sock_append(poll_list_t *list, const int sock, bool wantRead, bool wantWrite); + +/** + * Send the whole buffer, calling write() multiple times if neccessary. + * Give up after calling write() maxtries times. + * Set maxtries < 0 to try infinitely. + */ +ssize_t sock_sendAll(const int sock, const void *buffer, const size_t len, int maxtries); + +/** + * Send given buffer, repeatedly calling recv on partial send or EINTR. + */ +ssize_t sock_recv(const int sock, void *buffer, const size_t len); + +#endif /* SOCKHELPER_H_ */ diff --git a/src/shared/timing.c b/src/shared/timing.c new file mode 100644 index 0000000..4ca1002 --- /dev/null +++ b/src/shared/timing.c @@ -0,0 +1,21 @@ +#include "timing.h" +#include +#include +#include +#include + +struct timespec basetime; + +void timing_abort() +{ + printf( "Cannot get CLOCK_MONOTONIC(_RAW), errno=%d\n", errno ); + exit( 1 ); +} + +void timing_setBase() +{ + if ( clock_gettime( BEST_CLOCK_SOURCE, &basetime ) == -1 ) { + memset( &basetime, 0, sizeof(basetime) ); + } +} + diff --git a/src/shared/timing.h b/src/shared/timing.h new file mode 100644 index 0000000..f3d8802 --- /dev/null +++ b/src/shared/timing.h @@ -0,0 +1,162 @@ +#ifndef _D_TIMING_H +#define _D_TIMING_H + +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif + +#include +#include +#include + +#ifdef CLOCK_MONOTONIC_RAW +#define BEST_CLOCK_SOURCE CLOCK_MONOTONIC_RAW +#else +#define BEST_CLOCK_SOURCE CLOCK_MONOTONIC +#endif + +typedef struct timespec ticks; + +extern struct timespec basetime; + +/** + * Assign src to dst while adding secs seconds. + */ +#define timing_set(dst,src,secs) do { (dst)->tv_sec = (src)->tv_sec + secs; (dst)->tv_nsec = (src)->tv_nsec; } while (0) + +/** + * Define variable now, initialize to timing_get. + */ +#define declare_now ticks now; timing_get( &now ) + +/** + * Call this once to calibrate on startup. + * Although overflows of CLOCK_MONOTONIC(_RAW) should + * by definition never happen, we still have a fixed size + * int that could at some point. By forcing the counter + * to start at 0 on startup the point of overflow + * will be very far in the future (decades for 32bit time_t, + * end of universe for 64bit). + */ +void timing_setBase(); + +/** + * Internal, do not use. Moved to another function + * to prevent inlining of error handling code, which + * should be very unlikely to ever trigger. + */ +_Noreturn void timing_abort(); + +/** + * Get current time. Shortcut for clock_gettime with error check. + */ +static inline void timing_get(ticks* retval) +{ + if ( clock_gettime( BEST_CLOCK_SOURCE, retval ) == -1 ) timing_abort(); + retval->tv_sec -= basetime.tv_sec; +} + +/** + * Get a ticks instance somewhere in the future. + * Useful for timeouts. + */ +static inline void timing_gets(ticks* retval, int32_t addSeconds) +{ + timing_get( retval ); + retval->tv_sec += addSeconds; +} + +static inline void timing_addSeconds(ticks* retval, ticks* base, int32_t addSeconds) +{ + retval->tv_sec = base->tv_sec + addSeconds; + retval->tv_nsec = base->tv_nsec; +} + +/** + * Check whether given timeout is reached. + * Might trigger up to one second early. + */ +static inline bool timing_reached(const ticks* timeout, const ticks* now) +{ + return now->tv_sec >= timeout->tv_sec; +} +#define timing_1le2(one,two) timing_reached(one,two) + +/** + * Precise check whether given timeout has been reached. + */ +static inline bool timing_reachedPrecise(const ticks* timeout, const ticks* now) +{ + return now->tv_sec > timeout->tv_sec + || (now->tv_sec == timeout->tv_sec && now->tv_nsec > timeout->tv_nsec); +} + +/** + * Shortcut for above. Useful if not used in loop. + * Might trigger up to one second early. + */ +static inline bool timing_isReached(const ticks* timeout) +{ + ticks now; + timing_get( &now ); + return timing_reached( timeout, &now ); +} +/** + * Shortcut for above. Useful if not used in loop. + */ +static inline bool timing_isReachedPrecise(const ticks* timeout) +{ + ticks now; + timing_get( &now ); + return timing_reachedPrecise( timeout, &now ); +} + + +/** + * Get difference between two ticks, rounded down to seconds. + * Make sure you pass the arguments in the proper order. If + * end is before start, 0 will always be returned. + */ +static inline uint32_t timing_diff(const ticks *start, const ticks *end) +{ + if ( end->tv_sec <= start->tv_sec ) return 0; + return (uint32_t)( ( end->tv_sec - start->tv_sec ) + + ( start->tv_nsec > end->tv_nsec ? -1 : 0 ) ); +} + +/** + * Get difference between two ticks, rounded down to milliseconds. + * Same as above; passing arguments in reverse will always return 0. + */ +static inline uint64_t timing_diffMs(const ticks *start, const ticks *end) +{ + if ( end->tv_sec < start->tv_sec ) return 0; + uint64_t diff = (uint64_t)( end->tv_sec - start->tv_sec ) * 1000; + if ( start->tv_nsec >= end->tv_nsec ) { + if ( diff == 0 ) return 0; + diff -= (start->tv_nsec - end->tv_nsec) / 1000000; + } else { + diff += (end->tv_nsec - start->tv_nsec) / 1000000; + } + return diff; +} + +/** + * Get difference between two ticks, rounded down to microseconds. + * Same as above; passing arguments in reverse will always return 0. + */ +static inline uint64_t timing_diffUs(const ticks *start, const ticks *end) +{ + if ( end->tv_sec < start->tv_sec ) return 0; + uint64_t diff = (uint64_t)( end->tv_sec - start->tv_sec ) * 1000000; + if ( start->tv_nsec >= end->tv_nsec ) { + if ( diff == 0 ) return 0; + diff -= ( start->tv_nsec - end->tv_nsec ) / 1000; + } else { + diff += ( end->tv_nsec - start->tv_nsec ) / 1000; + } + return diff; +} + + +#endif -- cgit v1.2.3-55-g7522